| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- const crypto = require('crypto');
- const Logs = require('../libs/logs');
- const IOR_KEYS_MAP = require('./iorKeys');
- const { getSetting } = require('./settings');
- const { eventSolutions } = require('./eventSolutions');
- /**
- * 筛选最优赔率
- */
- const oddRebateValue = (odds, platform) => {
- const setting = getSetting();
- const rebateRatio = setting[`${platform}RebateRatio`] ?? 0;
- const rebateType = setting[`${platform}RebateType`] ?? 0;
- if (rebateType == 0) {
- return odds * (1 + rebateRatio / 100);
- }
- return odds + rebateRatio / 100;
- }
- const getOptimalSelections = (odds, rules) => {
- const results = [];
- rules.forEach((rule, ruleIndex) => {
- let validOptions = [];
- for (let i = 0; i < 3; i++) {
- const innerIndex = i;
- const selection = [];
- let isValid = true;
- for (let j = 0; j < 3; j++) {
- const key = rule[j];
- let item = odds[key];
- if (key == '-') {
- item = { no: { v: 1 } };
- }
- if (!item) {
- isValid = false;
- break;
- }
- if (j === innerIndex) {
- if (!('ps' in item)) {
- isValid = false;
- break;
- }
- selection.push({
- k: key,
- p: 'ps',
- v: item.ps.v,
- r: item.ps.r,
- s: item.ps.s,
- o: item
- });
- }
- else {
- const candidates = ['ob', 'hg', 'no'].filter((k) => k in item);
- if (candidates.length === 0) {
- isValid = false;
- break;
- }
- // Logs.out('candidates', candidates)
- const best = candidates.reduce((a, b) => {
- const aValue = oddRebateValue(item[a].v-1, a);
- const bValue = oddRebateValue(item[b].v-1, b);
- const seletcted = aValue > bValue ? a : b;
- return seletcted;
- });
- // Logs.out('best', item, best)
- selection.push({
- k: key,
- p: best,
- v: item[best].v,
- r: item[best].r,
- s: item[best].s,
- o: item
- });
- }
- }
- if (isValid) {
- validOptions.push(selection);
- }
- }
- validOptions.forEach(iors => {
- results.push({ rule, iors, ruleIndex });
- });
- // if (validOptions.length > 0) {
- // const iors = validOptions.reduce((a, b) => {
- // const sumA = a.reduce((sum, x) => sum + x.v, 0);
- // const sumB = b.reduce((sum, x) => sum + x.v, 0);
- // return sumA > sumB ? a : b;
- // });
- // results.push({ rule, iors, ruleIndex });
- // }
- });
- return results;
- }
- /**
- * 精确浮点数字
- * @param {number} number
- * @param {number} x
- * @returns {number}
- */
- const fixFloat = (number, x=2) => {
- return parseFloat(number.toFixed(x));
- }
- /**
- * 盘口排序
- */
- const priority = { ps: 1, ob: 2, hg: 3 };
- const sortCpr = (cpr) => {
- const temp = [...cpr];
- temp.sort((a, b) => priority[a.p] - priority[b.p]);
- return temp;
- }
- /**
- * 添加返佣
- */
- const attachRebate = (ior) => {
- const { obRebateRatio, obRebateType, hgRebateRatio, hgRebateType } = getSetting();
- const { p } = ior;
- let rebate = 0, rebateType = 0;
- if (p == 'ps') {
- rebate = 0;
- rebateType = -1;
- }
- else if (p == 'ob') {
- rebate = obRebateRatio;
- rebateType = obRebateType;
- }
- else if (p == 'hg') {
- rebate = hgRebateRatio;
- rebateType = hgRebateType;
- }
- return { ...ior, b: rebate, t: rebateType };
- }
- const eventsCombination = (passableEvents) => {
- const { innerDefaultAmount, innerRebateRatio } = getSetting();
- const solutions = [];
- passableEvents.forEach(events => {
- const { odds, info } = events;
- Object.keys(IOR_KEYS_MAP).forEach(iorGroup => {
- const rules = IOR_KEYS_MAP[iorGroup];
- const optimalSelections = getOptimalSelections(odds, rules);
- optimalSelections.forEach(selection => {
- const { rule, iors, ruleIndex } = selection;
- const [, , , crossType] = rule;
- const oddsSideA = attachRebate(iors[0]);
- const oddsSideB = attachRebate(iors[1]);
- const oddsSideC = attachRebate(iors[2]);
- const innerIndex = iors.findIndex(item => item.p == 'ps');
- if (!oddsSideA || !oddsSideB || !oddsSideC) {
- return;
- }
- const cpr = [ oddsSideA, oddsSideB, oddsSideC ];
- const betInfo = {
- cross_type: crossType,
- inner_index: innerIndex,
- inner_base: innerDefaultAmount,
- inner_rebate: fixFloat(innerRebateRatio / 100, 3),
- odds_side_a: fixFloat(oddsSideA.v - 1),
- odds_side_b: fixFloat(oddsSideB.v - 1),
- odds_side_c: fixFloat(oddsSideC.v - 1),
- rebate_side_a: parseFloat((oddsSideA.b / 100).toFixed(4)),
- rebate_type_side_a: oddsSideA.t,
- rebate_side_b: parseFloat((oddsSideB.b / 100).toFixed(4)),
- rebate_type_side_b: oddsSideB.t,
- rebate_side_c: parseFloat((oddsSideC.b / 100).toFixed(4)),
- rebate_type_side_c: oddsSideC.t,
- };
- const sol = eventSolutions(betInfo, true);
- if (cpr[2].k == '-') {
- cpr.pop();
- }
- if (!isNaN(sol?.win_average)) {
- const id = info.id;
- const sortedCpr = sortCpr(cpr);
- const keys = sortedCpr.map(item => `${item.k}`).join('_');
- const sid = crypto.createHash('sha1').update(`${id}_${keys}`).digest('hex');
- const crpGroup = `${id}_${sortedCpr[0].k}`;
- const timestamp = Date.now();
- solutions.push({sid, sol, cpr, info, group: crpGroup, rule: `${iorGroup}:${ruleIndex}`, timestamp});
- }
- });
- });
- });
- return solutions.sort((a, b) => {
- return b.sol.win_average - a.sol.win_average;
- });
- }
- module.exports = { eventsCombination };
|