Games.js 9.5 KB

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