import GetTranslation from "../libs/getTranslation.js"; import { getSolutionsWithRelations, getGamesRelationsMap } from "../libs/getGamesRelations.js"; import Store from "../state/store.js"; import { createBetOrder, getBetOrders, removeBetOrder } from "./BetOrder.js"; import { getPlatformIorsDetailInfo, getSolutionByLatestIors, createPolymarketLimitBuyOrder, getPolymarketBalanceAllowance, getPolymarketOpenOrders, getPolymarketOrder, getPinnacleBalance, transferPolymarketWallet, } from "./Markets.js"; /** * 精确浮点数字 * @param {number} number * @param {number} x * @returns {number} */ const fixFloat = (number, x=3) => { return parseFloat(number.toFixed(x)); } export const getLeagues = async () => { const { polymarket, pinnacle } = Store.get('leagues') ?? { polymarket: [], pinnacle: [] }; const polymarketNames = polymarket.map(item => item.name); const translatedNames = await GetTranslation(polymarketNames); const newPolymarket = polymarket.map(item => { const { name } = item; const localesName = translatedNames[name] ?? name; return { ...item, localesName }; }); return { polymarket: newPolymarket, pinnacle }; } export const setLeaguesRelation = async (relation) => { const { id, platforms } = relation; if (!id || !platforms) { return Promise.reject(new Error('invalid request', { cause: 400 })); } const storeRelations = Store.get('leaguesRelations') ?? {}; if (storeRelations[id]) { return Promise.reject(new Error('relation already exists', { cause: 400 })); } storeRelations[id] = relation; Store.set('leaguesRelations', storeRelations); return Promise.resolve(); }; export const removeLeaguesRelation = async (id) => { if (!id) { return Promise.reject(new Error('invalid request', { cause: 400 })); } const storeRelations = Store.get('leaguesRelations') ?? {}; if (!storeRelations[id]) { return Promise.reject(new Error('relation not found', { cause: 400 })); } delete storeRelations[id]; Store.set('leaguesRelations', storeRelations); return Promise.resolve(); }; export const getLeaguesRelations = async () => { const storeRelations = Object.values(Store.get('leaguesRelations') ?? {}); const polymarketNames = storeRelations.map(item => item.platforms.polymarket.name); const translatedNames = await GetTranslation(polymarketNames); const newRelations = storeRelations.map(item => { const { platforms: { polymarket, pinnacle } } = item; const { name } = polymarket; const localesName = translatedNames[name] ?? name; return { ...item, platforms: { polymarket: { ...polymarket, localesName }, pinnacle } }; }); return Promise.resolve(newRelations); }; export const getGames = async () => { const { polymarket, pinnacle } = Store.get('games') ?? { polymarket: [], pinnacle: [] }; const polymarketNames = [ ...new Set(polymarket.map(item => [item.teamHomeName, item.teamAwayName, item.leagueName]).flat()) ]; const translatedNames = await GetTranslation(polymarketNames); const newPolymarket = polymarket.map(item => { const { leagueName, teamHomeName, teamAwayName } = item; const localesTeamHomeName = translatedNames[teamHomeName] ?? teamHomeName; const localesTeamAwayName = translatedNames[teamAwayName] ?? teamAwayName; const localesLeagueName = translatedNames[leagueName] ?? leagueName; return { ...item, localesTeamHomeName, localesTeamAwayName, localesLeagueName }; }).filter(item => { const { timestamp } = item; const now = Date.now(); return (timestamp + 1000 * 60 * 60 * 2) > now; }).sort((a, b) => a.timestamp - b.timestamp); return { polymarket: newPolymarket, pinnacle }; } export const setGamesRelation = async (relation) => { const { id, platforms, timestamp } = relation; if (!id || !platforms || !timestamp) { return Promise.reject(new Error('invalid request', { cause: 400 })); } const storeRelations = Store.get('gamesRelations') ?? {}; if (storeRelations[id]) { return Promise.reject(new Error('relation already exists', { cause: 400 })); } storeRelations[id] = relation; Store.set('gamesRelations', storeRelations); return Promise.resolve(); } export const removeGamesRelation = async (id) => { if (!id) { return Promise.reject(new Error('invalid request', { cause: 400 })); } const storeRelations = Store.get('gamesRelations') ?? {}; if (!storeRelations[id]) { return Promise.reject(new Error('relation not found', { cause: 400 })); } delete storeRelations[id]; Store.set('gamesRelations', storeRelations); return Promise.resolve(); } export const getGamesRelations = async () => { const gamesRelations = Object.values(getGamesRelationsMap()).sort((a, b) => a.timestamp - b.timestamp); return Promise.resolve(gamesRelations); } /** * 获取解决方案 * @param {*} param0 * @returns */ export const getSolutions = async ({ min_profit_rate = 0 } = {}) => { const solutions = Store.get('solutions') ?? []; const solutionsList = solutions.filter(solution => { const { sol: { win_profit_rate } } = solution; return win_profit_rate >= min_profit_rate; }).sort((a, b) => { return b.sol.win_profit_rate - a.sol.win_profit_rate; }); return getSolutionsWithRelations(solutionsList, 5); } /** * 计算Polymarket下注数量精度 */ const calculatePolymarketStakeCount = ({ stake, tick_size, bid_ex, min_order_size } = {}) => { const decimalPlaces = tick_size.toString().split('.')[1]?.length ?? 0; const stakeCount = fixFloat(stake / bid_ex, decimalPlaces); if (stakeCount < min_order_size) { return null; } return stakeCount; } /** * 获取策略对应的盘口信息 */ export const getSolutionIorsInfo = async (sid) => { const gamesRelations = getGamesRelationsMap(); const solution = Store.get('solutions')?.find(item => item.sid == sid); if (!solution) { return Promise.reject(new Error('solution not found', { cause: 400 })); } const { rid, cpr, sol: { cross_type } } = solution; const gameRelation = gamesRelations[rid]; if (!gameRelation) { return Promise.reject(new Error('game relation not found', { cause: 400 })); } const { platforms: { polymarket, pinnacle } } = gameRelation; const idMap = { polymarket: polymarket.id, pinnacle: pinnacle.id }; const iorsInfo = await Promise.all(cpr.map(item => { const { k, p } = item; return getPlatformIorsDetailInfo(k, p, idMap[p]); })); return { cpr, iorsInfo, cross_type, gameRelation }; } /** * 根据策略下注 */ export const betSolution = async (sid, stake=0) => { const { cpr, iorsInfo, cross_type, gameRelation } = await getSolutionIorsInfo(sid); const { iorsValues, stakeLimit, winLimit, sol } = getSolutionByLatestIors(iorsInfo, cross_type); const { minGroup } = stakeLimit ?? {}; if (!minGroup?.length) { return Promise.reject(new Error('no stake limit', { cause: 400 })); } const polymarketIndex = cpr.findIndex(item => item.p === 'polymarket'); const polymarketInfo = iorsInfo[polymarketIndex]; if (!polymarketInfo) { return Promise.reject(new Error('polymarket info not found', { cause: 400 })); } const pinnacleInfos = [...iorsInfo]; pinnacleInfos.splice(polymarketIndex, 1); const polymarketStake = minGroup[polymarketIndex]; const polymarketPrice = cpr[polymarketIndex].bid_ex; const polymarketStakeCount = calculatePolymarketStakeCount({ stake: polymarketStake, tick_size: polymarketInfo.tick_size, bid_ex: polymarketPrice, min_order_size: polymarketInfo.min_order_size }); if (!polymarketStakeCount) { return Promise.reject(new Error('polymarket stake count not found', { cause: 400 })); } // return { cpr, solutionInfo, polymarketInfo, pinnacleInfos, polymarketStakeCount}; const polymarketOrder = await createPolymarketLimitBuyOrder({ tokenID: polymarketInfo.asset_id, price: polymarketPrice, size: polymarketStakeCount, tickSize: polymarketInfo.tick_size, negRisk: polymarketInfo.neg_risk, }); const result = { polymarketOrder, iorsValues, sol, stakeLimit, winLimit, iorsInfo, cpr, gameRelation, }; return createBetOrder({ sid, stake: polymarketStake, side: 'BUY', size: polymarketStakeCount, ...result, }); } /** * 获取下注订单记录 */ export const getOrders = async ({ limit = 100 } = {}) => { return getBetOrders({ limit }); } /** * 删除下注订单记录 */ export const removeOrder = async (id) => { return removeBetOrder(id); } /** * 查询Polymarket单个订单 */ export const getOrder = async ({ orderID } = {}) => { return getPolymarketOrder({ orderID }); } /** * 查询Polymarket开放订单 */ export const getOpenOrders = async ({ id, market, asset_id, only_first_page = false, next_cursor, } = {}) => { return getPolymarketOpenOrders({ id, market, asset_id, only_first_page, next_cursor, }); } /** * 获取Pinnacle账户余额信息 */ export const getPinnacleAccountBalance = async ({ channel } = {}) => { return getPinnacleBalance({ channel }); } /** * 清理过期关系 */ const cleanGamesRelations = () => { const now = Date.now(); const storeRelations = Store.get('gamesRelations') ?? []; Object.keys(storeRelations).forEach(key => { const relation = storeRelations[key]; const { timestamp } = relation; if ((timestamp + 1000 * 60 * 60 * 2) < now) { delete storeRelations[key]; } }); Store.set('gamesRelations', storeRelations); } setInterval(cleanGamesRelations, 1000 * 60); export default { getLeagues, setLeaguesRelation, removeLeaguesRelation, getLeaguesRelations, getGames, setGamesRelation, removeGamesRelation, getGamesRelations, getSolutions, getSolutionIorsInfo, betSolution, getOrders, removeOrder, getOrder, getOpenOrders, getPolymarketBalanceAllowance, getPinnacleAccountBalance, transferPolymarketWallet, };