flyzto 4 hari lalu
induk
melakukan
17c9bc8eb1

+ 6 - 6
polymarket/libs/parseMarkets.js

@@ -193,8 +193,8 @@ export const parseOddsAsk = (markets) => {
             iorKeyNo = 'ior_moc';
             break;
         }
-        odds[iorKeyYes] = { v: iorYes, b: -feeYes, t: 1, ask: askYes, ask_size: askSizeYes, m: maxYes, /*token: tokenYes, slug */ };
-        odds[iorKeyNo] = { v: iorNo, b: -feeNo, t: 1, ask: askNo, ask_size: askSizeNo, m: maxNo, /*token: tokenNo, slug */ };
+        odds[iorKeyYes] = { v: iorYes, b: -feeYes, t: 1, ask: askYes, ask_size: askSizeYes, max: maxYes, /*token: tokenYes, slug */ };
+        odds[iorKeyNo] = { v: iorNo, b: -feeNo, t: 1, ask: askNo, ask_size: askSizeNo, max: maxNo, /*token: tokenNo, slug */ };
       });
     }
     else if (key === 'spreads') {
@@ -216,8 +216,8 @@ export const parseOddsAsk = (markets) => {
         const iorAway = fixFloat(1 / askAway);
         const feeHome = parseAskFee(askHome);
         const feeAway = parseAskFee(askAway);
-        odds[`ior_r${ratioAccept(ratio)}h_${ratioString(ratio)}`] = { v: iorHome, b: -feeHome, t: 1, ask: askHome, ask_size: askSizeHome, m: maxHome, /*token: tokenHome, slug */ };
-        odds[`ior_r${ratioAccept(-ratio)}c_${ratioString(ratio)}`] = { v: iorAway, b: -feeAway, t: 1, ask: askAway, ask_size: askSizeAway, m: maxAway, /*token: tokenAway, slug */ };
+        odds[`ior_r${ratioAccept(ratio)}h_${ratioString(ratio)}`] = { v: iorHome, b: -feeHome, t: 1, ask: askHome, ask_size: askSizeHome, max: maxHome, /*token: tokenHome, slug */ };
+        odds[`ior_r${ratioAccept(-ratio)}c_${ratioString(ratio)}`] = { v: iorAway, b: -feeAway, t: 1, ask: askAway, ask_size: askSizeAway, max: maxAway, /*token: tokenAway, slug */ };
       });
     }
     else if (key === 'totals') {
@@ -239,8 +239,8 @@ export const parseOddsAsk = (markets) => {
         const iorUnder = fixFloat(1 / askUnder);
         const feeOver = parseAskFee(askOver);
         const feeUnder = parseAskFee(askUnder);
-        odds[`ior_ouc_${ratioString(ratio)}`] = { v: iorOver, b: -feeOver, t: 1, ask: askOver, ask_size: askSizeOver, m: maxOver, /*token: tokenOver, slug */ };
-        odds[`ior_ouh_${ratioString(ratio)}`] = { v: iorUnder, b: -feeUnder, t: 1, ask: askUnder, ask_size: askSizeUnder, m: maxUnder, /*token: tokenUnder, slug */ };
+        odds[`ior_ouc_${ratioString(ratio)}`] = { v: iorOver, b: -feeOver, t: 1, ask: askOver, ask_size: askSizeOver, max: maxOver, /*token: tokenOver, slug */ };
+        odds[`ior_ouh_${ratioString(ratio)}`] = { v: iorUnder, b: -feeUnder, t: 1, ask: askUnder, ask_size: askSizeUnder, max: maxUnder, /*token: tokenUnder, slug */ };
       });
     }
   });

+ 0 - 213
server/models/Games.bak.js

@@ -1,213 +0,0 @@
-import GetTranslation from "../libs/getTranslation.js";
-import { getSolutionsWithRelations, getGamesRelationsMap } from "../libs/getGamesRelations.js";
-import Store from "../state/store.js";
-
-import { getPlatformIorsDetailInfo, getSolutionByLatestIors, getSoulutionBetResult } from "./Markets.js";
-
-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 storeData = Store.get('gamesRelations') ?? {};
-  // console.log('get games relations', storeData);
-  // const storeRelations = Object.values(storeData);
-  // console.log('store relations', storeRelations);
-  // const polymarketNames = [ ...new Set(storeRelations.map(item => {
-  //   const { teamHomeName, teamAwayName, leagueName } = item.platforms.polymarket;
-  //   return [teamHomeName, teamAwayName, leagueName];
-  // }).flat()) ];
-  // const translatedNames = await GetTranslation(polymarketNames);
-  // const newRelations = storeRelations.map(item => {
-  //   const { platforms: { polymarket, pinnacle } } = item;
-  //   const { teamHomeName, teamAwayName, leagueName } = polymarket;
-  //   const localesTeamHomeName = translatedNames[teamHomeName] ?? teamHomeName;
-  //   const localesTeamAwayName = translatedNames[teamAwayName] ?? teamAwayName;
-  //   const localesLeagueName = translatedNames[leagueName] ?? leagueName;
-  //   return { ...item, platforms: { polymarket: { ...polymarket, localesTeamHomeName, localesTeamAwayName, localesLeagueName }, pinnacle } };
-  // }).sort((a, b) => a.timestamp - b.timestamp);
-  // const newRelations = storeRelations.map(item => {
-  //   return { ...item };
-  // }).sort((a, b) => a.timestamp - b.timestamp);
-
-  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);
-}
-
-/**
- * 获取策略对应的盘口信息
- */
-export const getSolutionIorsInfo = async (sid) => {
-  const solution = Store.get('solutions')?.find(item => item.sid == sid);
-  if (!solution) {
-    return Promise.reject(new Error('solution not found', { cause: 400 }));
-  }
-  const { info: { id }, cpr, sol: { cross_type } } = solution;
-  const gamesRelations = Store.get('gamesRelations') ?? {};
-  const gameRelation = gamesRelations[id];
-  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 };
-  // const accountBalance = await getAccountBalance();
-  // const solutionInfo = getSolutionByLatestIors(iorsInfo, cross_type);
-  // return { cpr, iorsInfo, ...solutionInfo };
-}
-
-/**
- * 根据策略下注
- */
-export const betSolution = async (sid, stake=0) => {
-  const solutionIorsInfo = await getSolutionIorsInfo(sid);
-  const { iorsInfo, cross_type } = solutionIorsInfo;
-  const solutionInfo = getSolutionByLatestIors(iorsInfo, cross_type);
-  return solutionInfo;
-  if (solutionInfo?.error) {
-    const error = new Error(solutionInfo.error, { cause: 400 });
-    error.data = solutionInfo.data;
-    return Promise.reject(error);
-  }
-  const betResult = await getSoulutionBetResult({ ...solutionIorsInfo, ...solutionInfo, stake });
-  return { betResult, ...solutionIorsInfo, ...solutionInfo };
-}
-
-/**
- * 清理过期关系
- */
-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,
-};

+ 0 - 459
server/models/Markets.bak.js

@@ -1,459 +0,0 @@
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-import { getData } from "../libs/cache.js";
-import Logs from "../libs/logs.js";
-
-import eventSolutions from '../triangle/eventSolutions.js';
-
-import { getOrderBook, placeOrder as polymarketPlaceOrder } from "../../polymarket/libs/polymarketClient.js";
-import { getLineInfo, placeOrder as pinnaclePlaceOrder } from "../../polymarket/libs/pinnacleClient.js";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-const polymarketMarketsCacheFile = path.join(__dirname, "../../polymarket/cache/polymarketMarketsCache.json");
-const pinnacleGamesCacheFile = path.join(__dirname, "../../pinnacle/cache/pinnacleGamesCache.json");
-
-/**
- * 最小盈利率
- */
-const MIN_PROFIT_RATE = -1;
-
-/**
- * 精确浮点数字
- * @param {number} number
- * @param {number} x
- * @returns {number}
- */
-const fixFloat = (number, x=3) => {
-  return parseFloat(number.toFixed(x));
-}
-
-/**
- * 依次执行任务
- */
-const runSequentially = async (tasks) => {
-  return new Promise(async (resolve, reject) => {
-    const results = [];
-    let isError = false;
-    for (const task of tasks) {
-      // task 必须是一个「返回 Promise 的函数」
-      const res = await task().catch(err => {
-        err.results = results;
-        isError = true;
-        reject(err);
-      });
-      if (isError) {
-        break;
-      }
-      else if (res) {
-        results.push(res);
-      }
-    }
-    if (isError) {
-      return;
-    }
-    resolve(results);
-  })
-}
-
-/**
- * 计算符合比例的最大和最小数组
- */
-const findMaxMinGroup = (ratios, minVals, maxVals) => {
-  const n = ratios.length;
-
-  // 1. 计算比例总和 & 归一化比例
-  const totalRatio = ratios.reduce((a, b) => a + b, 0);
-  const proportions = ratios.map(r => r / totalRatio);
-
-  // 2. 计算每个位置允许的最大/最小倍数
-  let maxPossibleScale = Infinity;
-  let minPossibleScale = 0;   // 如果允许0,通常从0开始
-
-  for (let i = 0; i < n; i++) {
-    // 上限约束
-    if (proportions[i] > 0) {
-      maxPossibleScale = Math.min(maxPossibleScale, maxVals[i] / proportions[i]);
-    }
-    // 下限约束(如果 minVals[i] > 0 才有意义)
-    if (proportions[i] > 0 && minVals[i] > 0) {
-      minPossibleScale = Math.max(minPossibleScale, minVals[i] / proportions[i]);
-    }
-  }
-
-  // 3. 最终取值
-  const maxGroup = proportions.map(p => p * maxPossibleScale);
-  const minGroup = proportions.map(p => p * Math.max(minPossibleScale, 0));
-
-  return {
-    maxGroup: maxGroup.map(v => fixFloat(v)), // 可控制精度
-    minGroup: minGroup.map(v => fixFloat(v)),
-    proportions: proportions.map(v => fixFloat(v)),
-    scaleForMax: fixFloat(maxPossibleScale),
-    scaleForMin: fixFloat(minPossibleScale)
-  };
-}
-
-/**
- * 解析盘口信息
- */
-const parseRatio = (ratioString) => {
-  if (!ratioString) {
-    return null;
-  }
-  return parseFloat(`${ratioString[0]}.${ratioString.slice(1)}`);
-}
-
-const parseIor = (ior) => {
-  const iorMatch = ior.match(/ior_(m|r|ou|wm|ot)([ao])?([hcn])?_?(\d+)?/);
-  if (!iorMatch) {
-    return null;
-  }
-  const [, type, action, side, ratio] = iorMatch;
-  return { type, action, side, ratio };
-}
-
-const getPolymarketIorInfo = async (ior, id) => {
-  const cacheData = await getData(polymarketMarketsCacheFile);
-  const marketsData = cacheData[id]?.marketsData;
-  if (!marketsData) {
-    Logs.outDev('polymarket markets data not found', id);
-    return null;
-  }
-  const iorOptions = parseIor(ior);
-  if (!iorOptions) {
-    Logs.outDev('polymarket ior options not found', ior);
-    return null;
-  }
-  const { type, action, side, ratio } = iorOptions;
-
-  let marketTypeData, outcomesSide;
-
-  if (type === 'm' && !ratio) {
-    const sideKey = side === 'h' ? 'Home' : side === 'c' ? 'Away' : 'Draw';
-    const sideAction = action === 'o' ? 'No' : 'Yes';
-    marketTypeData = marketsData.moneyline[sideKey];
-    outcomesSide = sideAction;
-  }
-
-  else if (type === 'r') {
-    const sideKey = side === 'h' ? 'Home' : side === 'c' ? 'Away' : '';
-    let ratioDirection = 1;
-    if (side === 'c' && action === 'a' || side === 'h' && !action) {
-      ratioDirection = -1;
-    }
-    const ratioValue = parseRatio(ratio) * ratioDirection;
-    const ratioKey = ratioValue > 0 ? `+${ratioValue}` : `${ratioValue}`;
-    marketTypeData = marketsData.spreads?.[ratioKey];
-    outcomesSide = sideKey;
-  }
-
-  else if (type === 'ou') {
-    const sideKey = side === 'c' ? 'Over' : side === 'h' ? 'Under' : '';
-    const ratioKey = parseRatio(ratio);
-    marketTypeData = marketsData.totals[ratioKey];
-    outcomesSide = sideKey;
-  }
-
-  const result = marketTypeData?.outcomes?.[outcomesSide];
-
-  if (!result) {
-    Logs.outDev('polymarket market type data not found', { ior, id, type, action, side, ratio, marketTypeData, outcomesSide });
-    return null;
-  }
-  return result;
-}
-
-const getPinnacleIorInfo = async (ior, id) => {
-  const cacheData = await getData(pinnacleGamesCacheFile);
-  const gamesData = cacheData[id];
-  if (!gamesData) {
-    Logs.outDev('pinnacle games data not found', id);
-    return null;
-  }
-  const iorOptions = parseIor(ior);
-  if (!iorOptions) {
-    Logs.outDev('pinnacle ior options not found', ior);
-    return null;
-  }
-  const { type, action, side, ratio } = iorOptions;
-
-  const { leagueId, id: eventId, home: homeTeamName, away: awayTeamName, periods={}, specials={}} = gamesData;
-
-  const straightData = periods.straight ?? {};
-  const { lineId: straightLineId, moneyline, spreads, totals } = straightData;
-  const { winningMargin, exactTotalGoals } = specials;
-
-  if (type === 'm' && moneyline && !action && !ratio) {
-    const sideKey = side === 'h' ? 'home' : side === 'c' ? 'away' : 'draw';
-    const team = side === 'h' ? 'TEAM1' : side === 'c' ? 'TEAM2' : 'DRAW';
-    const odds = moneyline[sideKey];
-    return { leagueId, eventId, betType: 'MONEYLINE', team, lineId: straightLineId, odds };
-  }
-
-  else if (type === 'r' && spreads) {
-    let ratioDirection = 1;
-    if (side === 'c' && action === 'a' || side === 'h' && !action) {
-      ratioDirection = -1;
-    }
-    const ratioKey = parseRatio(ratio) * ratioDirection;
-    const itemSpread = spreads.find(spread => spread.hdp == ratioKey);
-    if (!itemSpread) {
-      Logs.outDev('pinnacle item spread not found', id, type, action, side, ratio);
-      return null;
-    }
-    const { altLineId=null, home, away } = itemSpread;
-    const odds = side === 'h' ? home : away;
-    const team = side === 'h' ? 'TEAM1' : 'TEAM2';
-    const handicap = ratioKey * (side === 'h' ? 1 : -1);
-    return { leagueId, eventId, handicap, betType: 'SPREAD', team, lineId: straightLineId, altLineId, odds };
-  }
-
-  else if (type === 'ou' && totals) {
-    const ratioKey = parseRatio(ratio);
-    const itemTotal = totals.find(total => total.points == ratioKey);
-    if (!itemTotal) {
-      Logs.outDev('pinnacle item total not found', id, type, action, side, ratio);
-      return null;
-    }
-    const { altLineId=null, over, under } = itemTotal;
-    const odds = side === 'c' ? over : under;
-    const sideKey = side === 'c' ? 'OVER' : 'UNDER';
-    return { leagueId, eventId, handicap: ratioKey, betType: 'TOTAL_POINTS', side: sideKey, lineId: straightLineId, altLineId, odds };
-  }
-
-  else if (type === 'wm' && winningMargin) {
-    const ratioKey = parseRatio(ratio);
-    const { id: specialId } = winningMargin;
-    const wmName = side === 'h' ? `${homeTeamName} By ${ratioKey}` : side === 'c' ? `${awayTeamName} By ${ratioKey}` : '';
-    const wmItem = winningMargin.contestants.find(contestant => contestant.name == wmName);
-    if (!wmItem) {
-      Logs.outDev('pinnacle item winning margin not found', id, type, action, side, ratio);
-      return null;
-    }
-    const { id: contestantId, lineId, price } = wmItem;
-    return { leagueId, eventId, specialId, contestantId, lineId, odds: price };
-  }
-
-  else if (type === 'ot' && exactTotalGoals) {
-    const ratioKey = parseRatio(ratio);
-    const { id: specialId } = exactTotalGoals;
-    const otItem = exactTotalGoals.contestants.find(contestant => contestant.name == ratioKey);
-    if (!otItem) {
-      Logs.outDev('pinnacle item exact total goals not found', id, type, action, side, ratio);
-      return null;
-    }
-    const { id: contestantId, lineId, price } = otItem;
-    return { leagueId, eventId, specialId, contestantId, lineId, odds: price };
-  }
-
-  else {
-    Logs.outDev('pinnacle ior type not found', ior, id);
-    return null;
-  }
-}
-
-/**
- * 获取平台盘口id信息
- */
-export const getPlatformIorInfo = async (ior, platform, id) => {
-  const getInfo = {
-    polymarket() {
-      return getPolymarketIorInfo(ior, id);
-    },
-    pinnacle() {
-      return getPinnacleIorInfo(ior, id);
-    }
-  }
-  Logs.outDev('getPlatformIorInfo', { ior, platform, id });
-  return getInfo[platform]?.();
-}
-
-
-/**
- * 获取polymarket盘口详细信息
- */
-const getPolymarketIorDetailInfo = async (info) => {
-  const { id } = info;
-  return getOrderBook(id);
-}
-
-/**
- * 获取pinnacle盘口详细信息
- */
-const getPinnacleIorDetailInfo = async (info, channel) => {
-  return getLineInfo(info, channel);
-}
-
-/**
- * 获取平台盘口详细信息
- */
-export const getPlatformIorsDetailInfo = async (ior, platform, id, channel) => {
-  const info = await getPlatformIorInfo(ior, platform, id);
-  if (!info) {
-    return Promise.reject(new Error('platform ior info not found', { cause: 400 }));
-  }
-  const getInfo = {
-    polymarket() {
-      return getPolymarketIorDetailInfo(info);
-    },
-    pinnacle() {
-      return getPinnacleIorDetailInfo(info, channel);
-    }
-  }
-  return getInfo[platform]?.();
-}
-
-/**
- * 平台盘口下注
- */
-export const placePlatformOrder = async (ior, platform, id, stake=0, channel) => {
-  const iorInfo = await getPlatformIorsDetailInfo(ior, platform, id, channel);
-  const betInfo = { ...iorInfo, stakeSize: stake };
-  const placeOrder = {
-    polymarket() {
-      return polymarketPlaceOrder(betInfo);
-    },
-    pinnacle() {
-      return pinnaclePlaceOrder(betInfo, channel);
-    }
-  }
-  return placeOrder[platform]?.();
-}
-
-/**
- * 根据最新赔率获取策略
- */
-export const getSolutionByLatestIors = (iorsInfo, cross_type, retry=false) => {
-  const askIndex = +retry;
-  const iorsValues = iorsInfo.map(item => {
-    if (item.asks) {
-      const bestAsk = [...item.asks].sort((a, b) => a.price - b.price)[askIndex];
-      const value = fixFloat(1 / bestAsk.price, 3);
-      const maxStake = fixFloat(bestAsk.size * bestAsk.price);
-      const minStake = fixFloat(item.min_order_size * bestAsk.price);
-      return { value, maxStake, minStake, bestPrice: bestAsk.price };
-    }
-    else if (item.info) {
-      const value = item.info.price;
-      const maxStake = Math.floor(item.info.maxRiskStake);
-      const minStake = Math.ceil(item.info.minRiskStake*10);
-      return { value, maxStake, minStake };
-    }
-  });
-
-  const nullIndex = iorsValues.findIndex(item => item.value == null);
-
-  if (nullIndex >= 0) {
-    return { error: `IORS_NULL_VALUE_AT_INDEX_${nullIndex}_RETRY_${askIndex}`, data: iorsInfo };
-  }
-
-  const baseIndex = iorsValues.reduce((minIdx, cur, idx) => cur.value < iorsValues[minIdx].value ? idx : minIdx, 0);
-
-  if (iorsValues.length === 2) {
-    iorsValues.push({ value: 1, maxStake: 0, minStake: 0 });
-  }
-
-  const betInfo = {
-    cross_type,
-    base_index: baseIndex,
-    base_stake: 10000,
-    odds_side_a: fixFloat(iorsValues[0].value - 1),
-    odds_side_b: fixFloat(iorsValues[1].value - 1),
-    odds_side_c: fixFloat(iorsValues[2].value - 1),
-  };
-
-  const sol = eventSolutions(betInfo, true);
-  const { win_average, win_profit_rate, gold_side_a, gold_side_b, gold_side_c } = sol;
-
-  if (win_profit_rate < MIN_PROFIT_RATE) {
-    Logs.outDev('win_profit_rate is less than profit rate limit', sol, iorsValues, iorsInfo, cross_type);
-    return { error: `WIN_PROFIT_RATE_LESS_THAN_MIN_PROFIT_RATE_RETRY_${askIndex}`, data: { sol, iorsValues, iorsInfo } };
-  }
-
-  const goldRatios = [gold_side_a, gold_side_b];
-  if (gold_side_c) {
-    goldRatios.push(gold_side_c);
-  }
-  const minVals = iorsValues.map(item => item.minStake);
-  const maxVals = iorsValues.map(item => item.maxStake);
-
-  const stakeLimit = findMaxMinGroup(goldRatios, minVals, maxVals);
-  const { scaleForMax, scaleForMin } = stakeLimit;
-
-  if (scaleForMax < scaleForMin) {
-    Logs.outDev('scaleForMax is less than scaleForMin');
-    if (!retry) {
-      return getSolutionByLatestIors(iorsInfo, cross_type, true);
-    }
-    else {
-      return { error: `NO_ENOUGH_STAKE_SIZE_TO_BET_RETRY_${askIndex}`, data: { sol, iorsValues, iorsInfo } };
-    }
-  }
-
-  const winLimit = {
-    max: fixFloat(win_average * scaleForMax / (gold_side_a + gold_side_b + gold_side_c)),
-    min: fixFloat(win_average * scaleForMin / (gold_side_a + gold_side_b + gold_side_c)),
-  }
-
-  return { sol, iors: iorsValues, stakeLimit, winLimit };
-}
-
-export const getSoulutionBetResult = async ({ iors, iorsInfo, stakeLimit, stake=0 }) => {
-  const maxStake = stakeLimit.maxGroup.reduce((acc, curr) => acc + curr, 0);
-  const minStake = stakeLimit.minGroup.reduce((acc, curr) => acc + curr, 0);
-  let betStakeGroup = [];
-  if (stake > maxStake || stake < 0) {
-    stake = maxStake;
-    betStakeGroup = stakeLimit.maxGroup;
-  }
-  else if (stake < minStake) {
-    stake = minStake;
-    betStakeGroup = stakeLimit.minGroup;
-  }
-  else {
-    betStakeGroup = stakeLimit.proportions.map(p => p * stake);
-  }
-
-  const betInfo = iorsInfo.map((item, index) => {
-    if (item.asks) {
-      const bestPrice = +iors[index].bestPrice;
-      const stakeSize = fixFloat(betStakeGroup[index] / bestPrice, 0); // 必须保证买单金额小数不超过2位
-      return { ...item, stakeSize, bestPrice, betIndex: index, platform: 'polymarket' }
-    }
-    else if (item.info) {
-      const stakeSize = fixFloat(betStakeGroup[index], 0);
-      return { ...item, stakeSize, betIndex: index, platform: 'pinnacle' }
-    }
-  }).sort((a, b) => {
-    if (a.platform === 'polymarket' && b.platform === 'pinnacle') {
-      return -1;
-    }
-    else if (a.platform === 'pinnacle' && b.platform === 'polymarket') {
-      return 1;
-    }
-    else {
-      return 0;
-    }
-  });
-
-  // return { betInfo };
-  return runSequentially(betInfo.map(item => async() => {
-    if (item.asks) {
-      const result = await polymarketPlaceOrder(item);
-      return [result, item.betIndex]
-    }
-    else if (item.info) {
-      const result = await pinnaclePlaceOrder(item);
-      return [result, item.betIndex]
-    }
-  })).then(results => {
-    return results.sort((a, b) => a[1] - b[1]).map(item => item[0]);
-  }).catch(error => {
-    Logs.out('get soulution bet result error', error.message);
-    Logs.errDev(error);
-    return Promise.reject(error);
-  });
-}

+ 7 - 4
server/models/Markets.js

@@ -129,7 +129,7 @@ export const getPlatformIorInfo = async (ior, platform, id) => {
     }
   }
   const result = await getInfo[platform]?.();
-  Logs.outDev('getPlatformIorInfo', { ior, platform, id },result);
+  Logs.outDev('getPlatformIorInfo', { ior, platform, id }, result);
   return result;
 }
 
@@ -137,7 +137,7 @@ export const getPlatformIorInfo = async (ior, platform, id) => {
  * 获取polymarket盘口详细信息
  */
 const getPolymarketIorDetailInfo = async (info) => {
-  Logs.outDev('get polymarket ior detail info', info);
+  // Logs.outDev('get polymarket ior detail info', info);
   const { id } = info;
   return polymarketSdk.getOrderBook(id)
   .catch(err => {
@@ -151,7 +151,7 @@ const getPolymarketIorDetailInfo = async (info) => {
  * 获取pinnacle盘口详细信息
  */
 const getPinnacleIorDetailInfo = async (info, channel) => {
-  Logs.outDev('get pinnacle ior detail info', { info, channel });
+  // Logs.outDev('get pinnacle ior detail info', { info, channel });
   return pinnacleSdk.getLineInfo({ info, channel })
   .catch(err => {
     Logs.out('get pinnacle ior detail info error', err.message);
@@ -210,9 +210,12 @@ export const getSolutionByLatestIors = (iorsInfo, cross_type, retry=false) => {
       const rebateType = 1;
       return { value, maxStake, minStake, rebateType };
     }
+    else {
+      return {};
+    }
   });
 
-  const nullIndex = iorsValues.findIndex(item => item.value == null);
+  const nullIndex = iorsValues.findIndex(item => item?.value == null);
 
   if (nullIndex >= 0) {
     return { error: `IORS_NULL_VALUE_AT_INDEX_${nullIndex}_RETRY_${askIndex}`, data: iorsInfo };

+ 4 - 1
web/src/views/home.vue

@@ -151,6 +151,7 @@ const getSolutionStakeRows = (solution) => {
       odds: cpr.v ?? '-',
       rebate: cpr.b ?? 0,
       stake: sol[`gold_side_${key}`],
+      maxStake: cpr.max ?? '-',
       win: sol[`win_side_${key}`],
       active: solution.cpr?.[index] || Number(sol[`gold_side_${key}`] ?? 0) !== 0,
     };
@@ -351,6 +352,7 @@ onUnmounted(() => {
                   <span>赔率</span>
                   <span>返佣</span>
                   <span>投注额</span>
+                  <span>最大投注</span>
                   <span>命中收益</span>
                 </div>
                 <div
@@ -364,6 +366,7 @@ onUnmounted(() => {
                   <span>{{ row.odds }}</span>
                   <span>{{ row.rebate }}%</span>
                   <span>{{ formatStake(row.stake) }}</span>
+                  <span>{{ formatStake(row.maxStake) }}</span>
                   <span>{{ formatStake(row.win) }}</span>
                 </div>
               </div>
@@ -507,7 +510,7 @@ onUnmounted(() => {
 }
 .stake-row {
   display: grid;
-  grid-template-columns: 42px 96px minmax(180px, 1fr) 80px 80px 90px 90px;
+  grid-template-columns: 42px 96px minmax(180px, 1fr) 80px 80px 80px 80px 80px;
   min-width: 760px;
   span {
     padding: 7px 8px;