polymarketClient.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import axios from "axios";
  2. import { HttpsProxyAgent } from "https-proxy-agent";
  3. import getDateInTimezone from "./getDateInTimezone.js";
  4. /**
  5. * 清理对象中的undefined值
  6. * @param {*} obj
  7. * @returns {Object}
  8. */
  9. const cleanUndefined = (obj) => {
  10. return Object.fromEntries(
  11. Object.entries(obj).filter(([, v]) => v !== undefined)
  12. );
  13. }
  14. const axiosDefaultOptions = {
  15. baseURL: "https://gamma-api.polymarket.com",
  16. url: "",
  17. method: "GET",
  18. headers: {},
  19. params: {},
  20. data: {},
  21. timeout: 10000,
  22. };
  23. const fetchMarketData = async (options) => {
  24. const { url } = options;
  25. if (!url) {
  26. throw new Error("url is required");
  27. }
  28. const mergedOptions = { ...axiosDefaultOptions, ...options };
  29. const proxy = process.env.NODE_HTTP_PROXY;
  30. if (proxy) {
  31. mergedOptions.proxy = false;
  32. mergedOptions.httpsAgent = new HttpsProxyAgent(proxy);
  33. }
  34. return axios(mergedOptions).then(res => res.data);
  35. };
  36. /**
  37. * 获取有效联赛
  38. * @param {*} marketsData
  39. * @param {*} soccerSports
  40. * @returns {Array}
  41. */
  42. const getLeagues = (marketsData, soccerSports) => {
  43. const soccerSportsMap = new Map(soccerSports.map(item => [+item.series, item]));
  44. const leaguesList = marketsData.map(item => {
  45. const { leagueId: id, leagueName: name } = item;
  46. const sport = soccerSportsMap.get(+id)?.sport;
  47. return { id, name, sport };
  48. });
  49. const leaguesMap = new Map(leaguesList.map(item => [item.id, item]));
  50. return Array.from(leaguesMap.values()).sort((a, b) => a.id - b.id);
  51. }
  52. /**
  53. * 获取足球联赛
  54. * @returns {Promise}
  55. */
  56. const getSoccerSports = async () => {
  57. return fetchMarketData({ url: "/sports" })
  58. .then(sportsData => {
  59. return sportsData.filter(item => {
  60. const { tags } = item;
  61. const tagIds = tags.split(",").map(item => +item);
  62. return tagIds.includes(100350);
  63. });
  64. });
  65. }
  66. /**
  67. * 解析赛事标题
  68. * @param {*} eventTitle
  69. * @returns {Object}
  70. */
  71. const parseTeamData = (eventTitle) => {
  72. const teamData = eventTitle.replace(' - More Markets', '').split(" vs. ");
  73. return {
  74. teamHomeName: teamData[0],
  75. teamAwayName: teamData[1],
  76. };
  77. }
  78. /**
  79. * 解析赛事数据
  80. * @param {*} event
  81. * @returns {Object}
  82. */
  83. const parseEvent = (event) => {
  84. const { id, title, series, gameId, parentEventId, startTime } = event;
  85. const { teamHomeName, teamAwayName } = parseTeamData(title);
  86. const leagueId = series[0].id;
  87. const leagueName = series[0].title;
  88. const timestamp = new Date(startTime).getTime();
  89. return {
  90. id: +id,
  91. gameId: gameId ? +gameId : undefined,
  92. parentEventId: parentEventId ? +parentEventId : undefined,
  93. leagueId: +leagueId,
  94. teamHomeName, teamAwayName, leagueName,
  95. timestamp,
  96. startTime: getDateInTimezone('+8', timestamp, true),
  97. };
  98. }
  99. /**
  100. * 解析市场列表数据
  101. * @param {*} events
  102. * @returns {Object}
  103. */
  104. const parseMarkets = (events) => {
  105. return events.map(parseEvent)
  106. .filter(item => !item.parentEventId)
  107. .map(cleanUndefined)
  108. .sort((a, b) => a.timestamp - b.timestamp);
  109. }
  110. /**
  111. * 获取赛事数据
  112. * @param {*} seriesIds
  113. * @returns {Promise}
  114. */
  115. const getMarketsData = async () => {
  116. const endDateMin = new Date().toISOString();
  117. const tomorrowDateMinus4 = getDateInTimezone(-4, Date.now()+24*60*60*1000);
  118. const tomorrowGmtMinus4EndTime = new Date(`${tomorrowDateMinus4} 23:59:59 GMT-4`).getTime();
  119. const endDateMax = new Date(tomorrowGmtMinus4EndTime).toISOString();
  120. return fetchMarketData({
  121. url: "/events",
  122. params: {
  123. limit: 500,
  124. tag_id: 100350,
  125. active: true,
  126. closed: false,
  127. end_date_min: endDateMin,
  128. end_date_max: endDateMax,
  129. }
  130. })
  131. .then(eventsData => {
  132. return parseMarkets(eventsData);
  133. })
  134. }
  135. /**
  136. * 获取联赛和比赛列表
  137. * @returns {Promise}
  138. */
  139. export const polymarketLeaguesAndGames = async () => {
  140. return getSoccerSports()
  141. .then(sports => {
  142. return Promise.all([
  143. getMarketsData(),
  144. Promise.resolve(sports)
  145. ])
  146. })
  147. .then(([games, sports]) => {
  148. const leagues = getLeagues(games, sports);
  149. return { leagues, games };
  150. });
  151. }