|
|
@@ -284,6 +284,129 @@ const updateGamesList = (({ platform, mk, games } = {}) => {
|
|
|
// });
|
|
|
// }
|
|
|
|
|
|
+/**
|
|
|
+ * 解析盘口关键词
|
|
|
+ */
|
|
|
+const parseRatio = (ratioString) => {
|
|
|
+ return parseFloat(`${ratioString[0]}.${ratioString.slice(1)}`);
|
|
|
+}
|
|
|
+const parseIorKey = (iorKey) => {
|
|
|
+ const iorKeyMatch = iorKey.match(/^ior_(r|ou|m|wm|ot|os)(a?)(h|c|n)?(_([\d-]+))?$/);
|
|
|
+ if (!iorKeyMatch) {
|
|
|
+ console.log('no iorKeyMatch', iorKey);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const [, type, accept, side, , ratioString] = iorKeyMatch;
|
|
|
+ let ratio = 0;
|
|
|
+ if (type === 'ot' || type === 'os') {
|
|
|
+ ratio = ratioString;
|
|
|
+ }
|
|
|
+ else if (ratioString) {
|
|
|
+ ratio = parseRatio(ratioString) * (accept ? 1 : -1);
|
|
|
+ }
|
|
|
+ return { type, side, ratio };
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 格式化盘口数据
|
|
|
+ */
|
|
|
+const getRouEvents = (events) => {
|
|
|
+ const eventsMap = {};
|
|
|
+ Object.keys(events).forEach(key => {
|
|
|
+ const { type, side, ratio } = parseIorKey(key) ?? {};
|
|
|
+ if (!type) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let ratioKey, index;
|
|
|
+ if (type === 'r') {
|
|
|
+ if (side === 'h') {
|
|
|
+ ratioKey = ratio;
|
|
|
+ index = 0;
|
|
|
+ }
|
|
|
+ else if (side === 'c') {
|
|
|
+ ratioKey = -ratio;
|
|
|
+ index = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (type === 'ou') {
|
|
|
+ ratioKey = `ou_${Math.abs(ratio)}`;
|
|
|
+ if (side === 'c') {
|
|
|
+ index = 0;
|
|
|
+ }
|
|
|
+ else if (side === 'h') {
|
|
|
+ index = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof (ratioKey) == 'number') {
|
|
|
+ if (ratioKey > 0) {
|
|
|
+ ratioKey = `+${ratioKey}`;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ratioKey = `${ratioKey}`;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ratioKey || index === undefined) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!eventsMap[ratioKey]) {
|
|
|
+ eventsMap[ratioKey] = new Array(2).fill(undefined);
|
|
|
+ }
|
|
|
+
|
|
|
+ const v = events[key]?.v ?? 0;
|
|
|
+ const r = events[key]?.r;
|
|
|
+ const q = events[key]?.q ?? 1;
|
|
|
+ eventsMap[ratioKey][index] = { key, v, r, q };
|
|
|
+ });
|
|
|
+
|
|
|
+ return eventsMap;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 限制让胜负/大小球返还率
|
|
|
+ */
|
|
|
+const rouMaxAdjust = (events) => {
|
|
|
+ const { innerRouMaxAdjust } = getSetting();
|
|
|
+ const rouEvents = getRouEvents(events);
|
|
|
+ // Logs.outDev('rouEvents', rouEvents);
|
|
|
+
|
|
|
+ const adjustedEvents = {};
|
|
|
+ Object.values(rouEvents).forEach(item => {
|
|
|
+ const [a, b] = item;
|
|
|
+ const returnRate = (a.v*b.v)/(a.v+b.v)*100;
|
|
|
+ if (returnRate > innerRouMaxAdjust) {
|
|
|
+ const proportion = returnRate / innerRouMaxAdjust;
|
|
|
+ item.forEach(ior => {
|
|
|
+ const { key, v, r, q } = ior;
|
|
|
+ adjustedEvents[key] = {
|
|
|
+ v: fixFloat(v/proportion, 3),
|
|
|
+ r: r,
|
|
|
+ s: v,
|
|
|
+ q: q,
|
|
|
+ rt: fixFloat(returnRate, 3),
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (events['ior_mh']?.v > adjustedEvents['ior_rh_05']?.v) {
|
|
|
+ events['ior_mh'].s = events['ior_mh'].v;
|
|
|
+ events['ior_mh'].v = adjustedEvents['ior_rh_05'].v;
|
|
|
+ events['ior_mh'].rt = adjustedEvents['ior_rh_05'].rt;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (events['ior_mc']?.v > adjustedEvents['ior_rc_05']?.v) {
|
|
|
+ events['ior_mc'].s = events['ior_mc'].v;
|
|
|
+ events['ior_mc'].v = adjustedEvents['ior_rc_05'].v;
|
|
|
+ events['ior_mc'].rt = adjustedEvents['ior_rc_05'].rt;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Object.assign(events, adjustedEvents);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* 同步基准盘口
|
|
|
*/
|
|
|
@@ -308,33 +431,34 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
|
|
|
const { eventId, originId, stage, retime, score, wm, evtime, events } = game;
|
|
|
const baseGame = baseMap.get(eventId);
|
|
|
if (baseGame) {
|
|
|
- Object.keys(events).forEach(ior => {
|
|
|
- const regRm = /^ior_(r|mh|mc)/;
|
|
|
+ const adjustedEvents = rouMaxAdjust(events);
|
|
|
+ Object.keys(adjustedEvents).forEach(ior => {
|
|
|
+ // const regRm = /^ior_(r|mh|mc)/;
|
|
|
const regWm = /^ior_(wm|mn)/;
|
|
|
const regOu = /^ior_ou/;
|
|
|
const regOt = /^ior_ot/;
|
|
|
// 胜负/让胜负/大小球调水(数值)
|
|
|
- if ((regRm.test(ior) || regOu.test(ior)) && innerRouSubsidyValue) {
|
|
|
- const sourceOdds = events[ior].v;
|
|
|
- events[ior].v = fixFloat(sourceOdds + innerRouSubsidyValue, 3);
|
|
|
- events[ior].s = sourceOdds;
|
|
|
- }
|
|
|
+ // if ((regRm.test(ior) || regOu.test(ior)) && innerRouSubsidyValue) {
|
|
|
+ // const sourceOdds = adjustedEvents[ior].v;
|
|
|
+ // adjustedEvents[ior].v = fixFloat(sourceOdds + innerRouSubsidyValue, 3);
|
|
|
+ // adjustedEvents[ior].s = sourceOdds;
|
|
|
+ // }
|
|
|
// 平局/让平调水(%)
|
|
|
- else if (regWm.test(ior) && innerWmSubsidyRatio) {
|
|
|
- const sourceOdds = events[ior].v;
|
|
|
- events[ior].v = fixFloat(sourceOdds * (1 + innerWmSubsidyRatio / 100), 3);
|
|
|
- events[ior].s = sourceOdds;
|
|
|
+ if (regWm.test(ior) && innerWmSubsidyRatio) {
|
|
|
+ const sourceOdds = adjustedEvents[ior].v;
|
|
|
+ adjustedEvents[ior].v = fixFloat(sourceOdds * (1 + innerWmSubsidyRatio / 100), 3);
|
|
|
+ adjustedEvents[ior].s = sourceOdds;
|
|
|
}
|
|
|
// 进球数调水(%)
|
|
|
else if (regOt.test(ior) && innerOtSubsidyRatio) {
|
|
|
- const sourceOdds = events[ior].v;
|
|
|
- events[ior].v = fixFloat(sourceOdds * (1 + innerOtSubsidyRatio / 100), 3);
|
|
|
- events[ior].s = sourceOdds;
|
|
|
+ const sourceOdds = adjustedEvents[ior].v;
|
|
|
+ adjustedEvents[ior].v = fixFloat(sourceOdds * (1 + innerOtSubsidyRatio / 100), 3);
|
|
|
+ adjustedEvents[ior].s = sourceOdds;
|
|
|
}
|
|
|
// 大小球最低赔率
|
|
|
if (regOu.test(ior) && innerOuMinValue) {
|
|
|
- const sourceOdds = events[ior].s ?? events[ior].v ?? 1;
|
|
|
- events[ior].q = sourceOdds < innerOuMinValue ? 0 : 1;
|
|
|
+ const sourceOdds = adjustedEvents[ior].s ?? adjustedEvents[ior].v ?? 1;
|
|
|
+ adjustedEvents[ior].q = sourceOdds < innerOuMinValue ? 0 : 1;
|
|
|
}
|
|
|
});
|
|
|
baseGame.originId = originId;
|
|
|
@@ -343,51 +467,10 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
|
|
|
baseGame.score = score;
|
|
|
baseGame.wm = wm;
|
|
|
baseGame.evtime = evtime;
|
|
|
- baseGame.events = events;
|
|
|
+ baseGame.events = adjustedEvents;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- // 浏览器采集特殊盘口用的
|
|
|
- // outrights?.forEach(outright => {
|
|
|
- // const { parentId, sptime, special } = outright;
|
|
|
- // const baseGame = baseMap.get(parentId);
|
|
|
- // if (baseGame) { // 赛前特殊盘口
|
|
|
- // const { timestamp } = baseGame;
|
|
|
- // const isSubsidy = timestamp > nowTime && timestamp < nowTime + 1000*60*60*subsidyTime;
|
|
|
- // if (isSubsidy) {
|
|
|
- // Object.keys(special).forEach(ior => {
|
|
|
- // if (ior.startsWith('ior_ot') && subsidyAmount) {
|
|
|
- // const sourceOdds = special[ior].v;
|
|
|
- // special[ior].v = fixFloat(sourceOdds * (1 + subsidyAmount), 3);
|
|
|
- // special[ior].s = sourceOdds
|
|
|
- // }
|
|
|
- // });
|
|
|
- // }
|
|
|
- // baseGame.sptime = sptime;
|
|
|
- // baseGame.special = special;
|
|
|
- // }
|
|
|
- // else {
|
|
|
- // const originBaseMap = new Map(baseList[marketType].map(item => [item.originId, item]));
|
|
|
- // const originBaseGame = originBaseMap.get(parentId);
|
|
|
- // if (originBaseGame) { // 滚球特殊盘口
|
|
|
- // Object.keys(special).forEach(ior => {
|
|
|
- // if (ior.startsWith('ior_wm') && subsidyRbWmAmount) {
|
|
|
- // const sourceOdds = special[ior].v;
|
|
|
- // special[ior].v = fixFloat(sourceOdds * (1 + subsidyRbWmAmount), 3);
|
|
|
- // special[ior].s = sourceOdds
|
|
|
- // }
|
|
|
- // else if (ior.startsWith('ior_ot') && subsidyRbOtAmount) {
|
|
|
- // const sourceOdds = special[ior].v;
|
|
|
- // special[ior].v = fixFloat(sourceOdds * (1 + subsidyRbOtAmount), 3);
|
|
|
- // special[ior].s = sourceOdds
|
|
|
- // }
|
|
|
- // });
|
|
|
- // originBaseGame.sptime = sptime;
|
|
|
- // originBaseGame.special = special;
|
|
|
- // }
|
|
|
- // }
|
|
|
- // });
|
|
|
-
|
|
|
if (games?.length) {
|
|
|
const gamesList = baseList[marketType]?.map(game => {
|
|
|
const { evtime, events, sptime, special, ...gameInfo } = game;
|
|
|
@@ -402,12 +485,13 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
|
|
|
}
|
|
|
const matches = PS_IOR_KEYS.map(([label, ...keys]) => {
|
|
|
let match = keys.map(key => {
|
|
|
- let value = odds[key]?.v ?? 0;
|
|
|
return {
|
|
|
- key, value,
|
|
|
+ key,
|
|
|
+ value: odds[key]?.v ?? 0,
|
|
|
origin: odds[key]?.r,
|
|
|
source: odds[key]?.s,
|
|
|
qualified: odds[key]?.q ?? 1,
|
|
|
+ returnRate: odds[key]?.rt,
|
|
|
};
|
|
|
});
|
|
|
if (label == 'jqs' || label == 'ou') {
|
|
|
@@ -458,12 +542,13 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
|
|
|
if (relatedGame) {
|
|
|
const events = {};
|
|
|
matches.forEach(({ label, match }) => {
|
|
|
- match.forEach(({ key, value, origin, source, qualified }) => {
|
|
|
+ match.forEach(({ key, value, origin, source, qualified, returnRate }) => {
|
|
|
events[key] = {
|
|
|
v: value,
|
|
|
r: origin,
|
|
|
s: source,
|
|
|
q: qualified,
|
|
|
+ rt: returnRate,
|
|
|
};
|
|
|
});
|
|
|
});
|
|
|
@@ -1431,9 +1516,9 @@ const syncQbossConfig = () => {
|
|
|
axios.get(`${BASE_API_URL}/p/QbossSystemConfig`, { proxy: false })
|
|
|
.then(res => {
|
|
|
const { data } = res;
|
|
|
- Logs.outDev('syncQbossConfig', data);
|
|
|
+ Logs.outDev('QbossSystemConfig', data);
|
|
|
if (!data?.data) {
|
|
|
- throw new Error('syncQbossConfig data is empty');
|
|
|
+ throw new Error('QbossSystemConfig data is empty');
|
|
|
}
|
|
|
const {
|
|
|
qboss_return_ratio,
|
|
|
@@ -1441,34 +1526,35 @@ const syncQbossConfig = () => {
|
|
|
im_return_ratio, im_return_type, im_odds_more_than,
|
|
|
hg_return_ratio, hg_return_type, hg_odds_more_than,
|
|
|
pc_return_ratio, pc_return_type,
|
|
|
- qboss_jq_add_odds, qboss_jq_add_hours,
|
|
|
- qboss_gq_add_dy_odds, qboss_gq_add_jq_odds,
|
|
|
- bc_before_hours,
|
|
|
+ // qboss_jq_add_odds, qboss_jq_add_hours,
|
|
|
+ // qboss_gq_add_dy_odds, qboss_gq_add_jq_odds,
|
|
|
+ bc_before_hours, qboss_ts_rqdx_max_return_rate_adjust,
|
|
|
qboss_ts_sfdx_odds_add, qboss_ts_pjrq_odds_add, qboss_ts_jqs_odds_add,
|
|
|
} = data.data;
|
|
|
const qbossSetting = {
|
|
|
- innerRebateRatio: qboss_return_ratio ? +qboss_return_ratio : 0,
|
|
|
- obRebateRatio: ob_return_ratio ? +ob_return_ratio : 0,
|
|
|
- obRebateType: ob_return_type ? +ob_return_type : 0,
|
|
|
- obMaxDiff: ob_odds_more_than ? +ob_odds_more_than : 0,
|
|
|
- imRebateRatio: im_return_ratio ? +im_return_ratio : 0,
|
|
|
- imRebateType: im_return_type ? +im_return_type : 0,
|
|
|
- imMaxDiff: im_odds_more_than ? +im_odds_more_than : 0,
|
|
|
- hgRebateRatio: hg_return_ratio ? +hg_return_ratio : 0,
|
|
|
- hgRebateType: hg_return_type ? +hg_return_type : 0,
|
|
|
- hgMaxDiff: hg_odds_more_than ? +hg_odds_more_than : 0,
|
|
|
- pcRebateRatio: pc_return_ratio ? +pc_return_ratio : 0,
|
|
|
- pcRebateType: pc_return_type ? +pc_return_type : 0,
|
|
|
- subsidyTime: qboss_jq_add_hours ? +qboss_jq_add_hours : 0,
|
|
|
- subsidyAmount: qboss_jq_add_odds ? +qboss_jq_add_odds : 0,
|
|
|
- subsidyRbWmAmount: qboss_gq_add_dy_odds ? +qboss_gq_add_dy_odds : 0,
|
|
|
- subsidyRbOtAmount: qboss_gq_add_jq_odds ? +qboss_gq_add_jq_odds : 0,
|
|
|
- innerRouSubsidyValue: qboss_ts_sfdx_odds_add ? +qboss_ts_sfdx_odds_add : 0,
|
|
|
- innerWmSubsidyRatio: qboss_ts_pjrq_odds_add ? +qboss_ts_pjrq_odds_add : 0,
|
|
|
- innerOtSubsidyRatio: qboss_ts_jqs_odds_add ? +qboss_ts_jqs_odds_add : 0,
|
|
|
- halfTimeActiveTime: bc_before_hours ? +bc_before_hours : 0,
|
|
|
+ innerRebateRatio: +(qboss_return_ratio ?? '0'),
|
|
|
+ obRebateRatio: +(ob_return_ratio ?? '0'),
|
|
|
+ obRebateType: +(ob_return_type ?? '0'),
|
|
|
+ obMaxDiff: +(ob_odds_more_than ?? '0'),
|
|
|
+ imRebateRatio: +(im_return_ratio ?? '0'),
|
|
|
+ imRebateType: +(im_return_type ?? '0'),
|
|
|
+ imMaxDiff: +(im_odds_more_than ?? '0'),
|
|
|
+ hgRebateRatio: +(hg_return_ratio ?? '0'),
|
|
|
+ hgRebateType: +(hg_return_type ?? '0'),
|
|
|
+ hgMaxDiff: +(hg_odds_more_than ?? '0'),
|
|
|
+ pcRebateRatio: +(pc_return_ratio ?? '0'),
|
|
|
+ pcRebateType: +(pc_return_type ?? '0'),
|
|
|
+ // subsidyTime: +(qboss_jq_add_hours ?? '0'),
|
|
|
+ // subsidyAmount: +(qboss_jq_add_odds ?? '0'),
|
|
|
+ // subsidyRbWmAmount: +(qboss_gq_add_dy_odds ?? '0'),
|
|
|
+ // subsidyRbOtAmount: +(qboss_gq_add_jq_odds ?? '0'),
|
|
|
+ innerRouSubsidyValue: +(qboss_ts_sfdx_odds_add ?? '0'),
|
|
|
+ innerRouMaxAdjust: +(qboss_ts_rqdx_max_return_rate_adjust ?? '100'),
|
|
|
+ innerWmSubsidyRatio: +(qboss_ts_pjrq_odds_add ?? '0'),
|
|
|
+ innerOtSubsidyRatio: +(qboss_ts_jqs_odds_add ?? '0'),
|
|
|
+ halfTimeActiveTime: +(bc_before_hours ?? '0'),
|
|
|
};
|
|
|
- Logs.outDev('syncQbossConfig', qbossSetting);
|
|
|
+ Logs.outDev('Sync QbossSystemConfig', qbossSetting);
|
|
|
const settingFields = {};
|
|
|
let needUpdate = false;
|
|
|
Object.keys(qbossSetting).forEach(key => {
|
|
|
@@ -1486,7 +1572,7 @@ const syncQbossConfig = () => {
|
|
|
// }
|
|
|
})
|
|
|
.catch(err => {
|
|
|
- Logs.out('syncQbossConfig error', err.message);
|
|
|
+ Logs.out('Sync QbossSystemConfig error', err.message);
|
|
|
})
|
|
|
.finally(() => {
|
|
|
setTimeout(syncQbossConfig, 1000*15);
|