Games.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import GetTranslation from "../libs/getTranslation.js";
  2. import { getSolutionsWithRelations, getGamesRelationsMap } from "../libs/getGamesRelations.js";
  3. import Store from "../state/store.js";
  4. import {
  5. getPlatformIorsDetailInfo,
  6. getSolutionByLatestIors,
  7. createPolymarketLimitBuyOrder,
  8. getPolymarketBalanceAllowance,
  9. transferPolymarketWallet,
  10. } from "./Markets.js";
  11. /**
  12. * 精确浮点数字
  13. * @param {number} number
  14. * @param {number} x
  15. * @returns {number}
  16. */
  17. const fixFloat = (number, x=3) => {
  18. return parseFloat(number.toFixed(x));
  19. }
  20. export const getLeagues = async () => {
  21. const { polymarket, pinnacle } = Store.get('leagues') ?? { polymarket: [], pinnacle: [] };
  22. const polymarketNames = polymarket.map(item => item.name);
  23. const translatedNames = await GetTranslation(polymarketNames);
  24. const newPolymarket = polymarket.map(item => {
  25. const { name } = item;
  26. const localesName = translatedNames[name] ?? name;
  27. return { ...item, localesName };
  28. });
  29. return { polymarket: newPolymarket, pinnacle };
  30. }
  31. export const setLeaguesRelation = async (relation) => {
  32. const { id, platforms } = relation;
  33. if (!id || !platforms) {
  34. return Promise.reject(new Error('invalid request', { cause: 400 }));
  35. }
  36. const storeRelations = Store.get('leaguesRelations') ?? {};
  37. if (storeRelations[id]) {
  38. return Promise.reject(new Error('relation already exists', { cause: 400 }));
  39. }
  40. storeRelations[id] = relation;
  41. Store.set('leaguesRelations', storeRelations);
  42. return Promise.resolve();
  43. };
  44. export const removeLeaguesRelation = async (id) => {
  45. if (!id) {
  46. return Promise.reject(new Error('invalid request', { cause: 400 }));
  47. }
  48. const storeRelations = Store.get('leaguesRelations') ?? {};
  49. if (!storeRelations[id]) {
  50. return Promise.reject(new Error('relation not found', { cause: 400 }));
  51. }
  52. delete storeRelations[id];
  53. Store.set('leaguesRelations', storeRelations);
  54. return Promise.resolve();
  55. };
  56. export const getLeaguesRelations = async () => {
  57. const storeRelations = Object.values(Store.get('leaguesRelations') ?? {});
  58. const polymarketNames = storeRelations.map(item => item.platforms.polymarket.name);
  59. const translatedNames = await GetTranslation(polymarketNames);
  60. const newRelations = storeRelations.map(item => {
  61. const { platforms: { polymarket, pinnacle } } = item;
  62. const { name } = polymarket;
  63. const localesName = translatedNames[name] ?? name;
  64. return { ...item, platforms: { polymarket: { ...polymarket, localesName }, pinnacle } };
  65. });
  66. return Promise.resolve(newRelations);
  67. };
  68. export const getGames = async () => {
  69. const { polymarket, pinnacle } = Store.get('games') ?? { polymarket: [], pinnacle: [] };
  70. const polymarketNames = [ ...new Set(polymarket.map(item => [item.teamHomeName, item.teamAwayName, item.leagueName]).flat()) ];
  71. const translatedNames = await GetTranslation(polymarketNames);
  72. const newPolymarket = polymarket.map(item => {
  73. const { leagueName, teamHomeName, teamAwayName } = item;
  74. const localesTeamHomeName = translatedNames[teamHomeName] ?? teamHomeName;
  75. const localesTeamAwayName = translatedNames[teamAwayName] ?? teamAwayName;
  76. const localesLeagueName = translatedNames[leagueName] ?? leagueName;
  77. return { ...item, localesTeamHomeName, localesTeamAwayName, localesLeagueName };
  78. }).filter(item => {
  79. const { timestamp } = item;
  80. const now = Date.now();
  81. return (timestamp + 1000 * 60 * 60 * 2) > now;
  82. }).sort((a, b) => a.timestamp - b.timestamp);
  83. return { polymarket: newPolymarket, pinnacle };
  84. }
  85. export const setGamesRelation = async (relation) => {
  86. const { id, platforms, timestamp } = relation;
  87. if (!id || !platforms || !timestamp) {
  88. return Promise.reject(new Error('invalid request', { cause: 400 }));
  89. }
  90. const storeRelations = Store.get('gamesRelations') ?? {};
  91. if (storeRelations[id]) {
  92. return Promise.reject(new Error('relation already exists', { cause: 400 }));
  93. }
  94. storeRelations[id] = relation;
  95. Store.set('gamesRelations', storeRelations);
  96. return Promise.resolve();
  97. }
  98. export const removeGamesRelation = async (id) => {
  99. if (!id) {
  100. return Promise.reject(new Error('invalid request', { cause: 400 }));
  101. }
  102. const storeRelations = Store.get('gamesRelations') ?? {};
  103. if (!storeRelations[id]) {
  104. return Promise.reject(new Error('relation not found', { cause: 400 }));
  105. }
  106. delete storeRelations[id];
  107. Store.set('gamesRelations', storeRelations);
  108. return Promise.resolve();
  109. }
  110. export const getGamesRelations = async () => {
  111. const gamesRelations = Object.values(getGamesRelationsMap()).sort((a, b) => a.timestamp - b.timestamp);
  112. return Promise.resolve(gamesRelations);
  113. }
  114. /**
  115. * 获取解决方案
  116. * @param {*} param0
  117. * @returns
  118. */
  119. export const getSolutions = async ({ min_profit_rate = 0 } = {}) => {
  120. const solutions = Store.get('solutions') ?? [];
  121. const solutionsList = solutions.filter(solution => {
  122. const { sol: { win_profit_rate } } = solution;
  123. return win_profit_rate >= min_profit_rate;
  124. }).sort((a, b) => {
  125. return b.sol.win_profit_rate - a.sol.win_profit_rate;
  126. });
  127. return getSolutionsWithRelations(solutionsList, 5);
  128. }
  129. /**
  130. * 计算Polymarket下注数量精度
  131. */
  132. const calculatePolymarketStakeCount = ({ stake, tick_size, bid_ex, min_order_size } = {}) => {
  133. const decimalPlaces = tick_size.toString().split('.')[1]?.length ?? 0;
  134. const stakeCount = fixFloat(stake / bid_ex, decimalPlaces);
  135. if (stakeCount < min_order_size) {
  136. return null;
  137. }
  138. return stakeCount;
  139. }
  140. /**
  141. * 获取策略对应的盘口信息
  142. */
  143. export const getSolutionIorsInfo = async (sid) => {
  144. const gamesRelations = getGamesRelationsMap();
  145. const solution = Store.get('solutions')?.find(item => item.sid == sid);
  146. if (!solution) {
  147. return Promise.reject(new Error('solution not found', { cause: 400 }));
  148. }
  149. const { rid, cpr, sol: { cross_type } } = solution;
  150. const gameRelation = gamesRelations[rid];
  151. if (!gameRelation) {
  152. return Promise.reject(new Error('game relation not found', { cause: 400 }));
  153. }
  154. const { platforms: { polymarket, pinnacle } } = gameRelation;
  155. const idMap = { polymarket: polymarket.id, pinnacle: pinnacle.id };
  156. const iorsInfo = await Promise.all(cpr.map(item => {
  157. const { k, p } = item;
  158. return getPlatformIorsDetailInfo(k, p, idMap[p]);
  159. }));
  160. return { cpr, iorsInfo, cross_type, gameRelation };
  161. }
  162. /**
  163. * 根据策略下注
  164. */
  165. export const betSolution = async (sid, stake=0) => {
  166. const { cpr, iorsInfo, cross_type } = await getSolutionIorsInfo(sid);
  167. const solutionInfo = getSolutionByLatestIors(iorsInfo, cross_type);
  168. const { stakeLimit: { minGroup } } = solutionInfo ?? { stakeLimit: {} };
  169. if (!minGroup?.length) {
  170. return Promise.reject(new Error('no stake limit', { cause: 400 }));
  171. }
  172. const polymarketIndex = cpr.findIndex(item => item.p === 'polymarket');
  173. const polymarketInfo = iorsInfo[polymarketIndex];
  174. if (!polymarketInfo) {
  175. return Promise.reject(new Error('polymarket info not found', { cause: 400 }));
  176. }
  177. const pinnacleInfos = [...iorsInfo];
  178. pinnacleInfos.splice(polymarketIndex, 1);
  179. const polymarketStake = minGroup[polymarketIndex];
  180. const polymarketPrice = cpr[polymarketIndex].bid_ex;
  181. const polymarketStakeCount = calculatePolymarketStakeCount({ stake: polymarketStake, tick_size: polymarketInfo.tick_size, bid_ex: polymarketPrice, min_order_size: polymarketInfo.min_order_size });
  182. if (!polymarketStakeCount) {
  183. return Promise.reject(new Error('polymarket stake count not found', { cause: 400 }));
  184. }
  185. // return { cpr, solutionInfo, polymarketInfo, pinnacleInfos, polymarketStakeCount};
  186. const polymarketOrder = await createPolymarketLimitBuyOrder({
  187. tokenID: polymarketInfo.asset_id,
  188. price: polymarketPrice,
  189. size: polymarketStakeCount,
  190. tickSize: polymarketInfo.tick_size,
  191. negRisk: polymarketInfo.neg_risk,
  192. });
  193. return { polymarketOrder, ...solutionInfo, iorsInfo, cpr };
  194. }
  195. /**
  196. * 清理过期关系
  197. */
  198. const cleanGamesRelations = () => {
  199. const now = Date.now();
  200. const storeRelations = Store.get('gamesRelations') ?? [];
  201. Object.keys(storeRelations).forEach(key => {
  202. const relation = storeRelations[key];
  203. const { timestamp } = relation;
  204. if ((timestamp + 1000 * 60 * 60 * 2) < now) {
  205. delete storeRelations[key];
  206. }
  207. });
  208. Store.set('gamesRelations', storeRelations);
  209. }
  210. setInterval(cleanGamesRelations, 1000 * 60);
  211. export default {
  212. getLeagues, setLeaguesRelation, removeLeaguesRelation, getLeaguesRelations,
  213. getGames, setGamesRelation, removeGamesRelation, getGamesRelations,
  214. getSolutions, getSolutionIorsInfo, betSolution, getPolymarketBalanceAllowance, transferPolymarketWallet,
  215. };