| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- /**
- * 解析让球方
- */
- const ratioAccept = (ratio) => {
- if (ratio > 0) {
- return 'a';
- }
- return '';
- }
- /**
- * 将比率转换为字符串
- * @param {*} ratio
- * @returns
- */
- const ratioString = (ratio) => {
- ratio = Math.abs(ratio);
- ratio = ratio.toString();
- ratio = ratio.replace(/\./, '');
- return ratio;
- }
- /**
- * 解析胜平负盘口
- * @param {*} moneyline
- * @returns
- */
- const parseMoneyline = (moneyline) => {
- // 胜平负
- if (!moneyline) {
- return null;
- }
- const { home, away, draw } = moneyline;
- return {
- 'ior_mh': { v: home },
- 'ior_mc': { v: away },
- 'ior_mn': { v: draw },
- }
- }
- /**
- * 解析让分盘口
- * @param {*} spreads
- * @param {*} wm
- * @returns
- */
- const parseSpreads = (spreads, wm) => {
- // 让分盘
- if (!spreads?.length) {
- return null;
- }
- const events = {};
- spreads.forEach(spread => {
- const { hdp, home, away } = spread;
- // if (!(hdp % 1) || !!(hdp % 0.5)) {
- // // 整数或不能被0.5整除的让分盘不处理
- // return;
- // }
- const ratio_ro = hdp;
- const ratio_r = ratio_ro - wm;
- events[`ior_r${ratioAccept(ratio_r)}h_${ratioString(ratio_r)}`] = {
- v: home,
- r: wm != 0 ? `ior_r${ratioAccept(ratio_ro)}h_${ratioString(ratio_ro)}` : undefined
- };
- events[`ior_r${ratioAccept(-ratio_r)}c_${ratioString(ratio_r)}`] = {
- v: away,
- r: wm != 0 ? `ior_r${ratioAccept(-ratio_ro)}c_${ratioString(ratio_ro)}` : undefined
- };
- });
- return events;
- }
- /**
- * 解析大小球盘口
- * @param {*} totals
- * @returns
- */
- const parseTotals = (totals) => {
- // 大小球盘
- if (!totals?.length) {
- return null;
- }
- const events = {};
- totals.forEach(total => {
- const { points, over, under } = total;
- events[`ior_ouc_${ratioString(points)}`] = { v: over };
- events[`ior_ouh_${ratioString(points)}`] = { v: under };
- });
- return events;
- }
- /**
- * 解析直赛盘口
- * @param {*} straight
- * @param {*} wm
- * @returns
- */
- const parseStraight = (straight, wm) => {
- if (!straight) {
- return null;
- }
- const { cutoff='', status=0, spreads=[], moneyline={}, totals=[] } = straight;
- const cutoffTime = new Date(cutoff).getTime();
- const nowTime = Date.now();
- if (status != 1 || cutoffTime < nowTime) {
- return null;
- }
- const events = {};
- Object.assign(events, parseSpreads(spreads, wm));
- Object.assign(events, parseMoneyline(moneyline));
- Object.assign(events, parseTotals(totals));
- return events;
- }
- /**
- * 解析净胜球盘口
- * @param {*} winningMargin
- * @param {*} home
- * @param {*} away
- * @returns
- */
- const parseWinningMargin = (winningMargin, home, away) => {
- if (!winningMargin) {
- return null;
- }
- const { cutoff='', status='', contestants=[] } = winningMargin;
- const cutoffTime = new Date(cutoff).getTime();
- const nowTime = Date.now();
- if (status != 'O' || cutoffTime < nowTime || !contestants?.length) {
- return null;
- }
- const events = {};
- contestants.forEach(contestant => {
- const { name, price } = contestant;
- const nr = name.match(/\d+$/)?.[0];
- if (!nr) {
- return;
- }
- let side;
- if (name.startsWith(home)) {
- side = 'h';
- }
- else if (name.startsWith(away)) {
- side = 'c';
- }
- else {
- return;
- }
- events[`ior_wm${side}_${nr}`] = { v: price };
- });
- return events;
- }
- /**
- * 解析进球数盘口
- * @param {*} exactTotalGoals
- * @returns
- */
- const parseExactTotalGoals = (exactTotalGoals) => {
- if (!exactTotalGoals) {
- return null;
- }
- const { cutoff='', status='', contestants=[] } = exactTotalGoals;
- const cutoffTime = new Date(cutoff).getTime();
- const nowTime = Date.now();
- if (status != 'O' || cutoffTime < nowTime || !contestants?.length) {
- return null;
- }
- const events = {};
- contestants.forEach(contestant => {
- const { name, price } = contestant;
- if (+name >= 1 && +name <= 7) {
- events[`ior_ot_${name}`] = { v: price };
- }
- });
- return events;
- }
- /**
- * 解析滚球场次状态
- * @param {*} state
- * @returns
- */
- const parseRbState = (state) => {
- let stage = null;
- if (state == 1) {
- stage = '1H';
- }
- else if (state == 2) {
- stage = 'HT';
- }
- else if (state == 3) {
- stage = '2H';
- }
- else if (state >= 4) {
- stage = 'ET';
- }
- return stage;
- }
- /**
- * 解析比赛数据
- * @param {*} game
- * @returns
- */
- export const parseGame = (game, filtedGames) => {
- const { eventId=0, originId=0, periods={}, specials={}, home, away, marketType, state, elapsed, homeScore=0, awayScore=0 } = game;
- const { straight, straight1st } = periods;
- const { winningMargin={}, exactTotalGoals={}, winningMargin1st={}, exactTotalGoals1st={} } = specials;
- const filtedGamesSet = new Set(filtedGames);
- const wm = homeScore - awayScore;
- const score = `${homeScore}-${awayScore}`;
- const events = parseStraight(straight, wm) ?? {};
- const stage = parseRbState(state);
- const retime = elapsed ? `${elapsed}'` : '';
- const evtime = Date.now();
- Object.assign(events, parseWinningMargin(winningMargin, home, away));
- Object.assign(events, parseExactTotalGoals(exactTotalGoals));
- const gameInfos = [];
- gameInfos.push({ eventId, originId, events, evtime, stage, retime, score, wm, marketType });
- const halfEventId = eventId * -1;
- if (filtedGamesSet.has(halfEventId)) {
- const events = parseStraight(straight1st, wm) ?? {};
- Object.assign(events, parseWinningMargin(winningMargin1st, home, away));
- Object.assign(events, parseExactTotalGoals(exactTotalGoals1st));
- gameInfos.push({ eventId: halfEventId, originId, events, evtime, stage, retime, score, wm, marketType });
- }
- return gameInfos;
- }
- /*
- * 解析比率信息
- */
- const parseRatio = (ratioString) => {
- if (!ratioString) {
- return null;
- }
- return parseFloat(`${ratioString[0]}.${ratioString.slice(1)}`);
- }
- /**
- * 解析盘口信息
- * @param {*} ior
- * @returns
- */
- 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 };
- }
- /**
- * 解析盘口详情
- * @param {*} ior
- * @param {*} id
- * @param {*} gamesMap
- * @returns
- */
- export const parseIorDetail = (ior, id, gamesMap) => {
- const gamesData = gamesMap[id];
- if (!gamesData) {
- return { ior, id, message: 'games data not found', cause: 400 };
- }
- const iorOptions = parseIor(ior);
- if (!iorOptions) {
- return { ior, id, message: 'ior options not found', cause: 400 };
- }
- 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) {
- return { ior, id, message: 'item spread not found', cause: 400 };
- }
- 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) {
- return { ior, id, message: 'item total not found', cause: 400 };
- }
- 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) {
- return { ior, id, message: 'item winning margin not found', cause: 400 };
- }
- 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 { ior, id, message: 'item exact total goals not found', cause: 400 };
- }
- const { id: contestantId, lineId, price } = otItem;
- return { leagueId, eventId, specialId, contestantId, lineId, odds: price };
- }
- else {
- return { ior, id, message: 'ior type not found', cause: 400 };
- }
- }
|