Browse Source

增加双盘口支持

flyzto 4 tháng trước cách đây
mục cha
commit
1f7853146b

+ 4 - 6
server/libs/cache.js

@@ -2,13 +2,11 @@ const fs = require('fs');
 const path = require('path');
 
 function getData(file, isMap) {
-  let data;
-  try {
-    data = fs.readFileSync(file);
-  }
-  catch (e) {
-    data = isMap ? '{}' : '[]';
+  if (!fs.existsSync(file)) {
+    return null;
   }
+  let data;
+  data = fs.readFileSync(file);
   try {
     data = JSON.parse(data.toString());
   }

+ 33 - 17
server/models/GamesPs.js

@@ -8,6 +8,7 @@ const fs = require('fs');
 const path = require('path');
 
 const GamesCacheFile = path.join(__dirname, '../data/games.cache');
+const DevGameTastFile = path.join(__dirname, '../data/gameTast.json');
 
 const childOptions = process.env.NODE_ENV == 'development' ? {
   execArgv: ['--inspect=9228'],
@@ -18,17 +19,18 @@ const events_child = fork('./triangle/eventsMatch.js', [], childOptions);
 
 const PS_IOR_KEYS = [
   ['0', 'ior_mh', 'ior_mn', 'ior_mc'],
-  // ['0', 'ior_rh_05', 'ior_mn', 'ior_rc_05'],
   ['-1', 'ior_rh_15', 'ior_wmh_1', 'ior_rac_05'],
   ['-2', 'ior_rh_25', 'ior_wmh_2', 'ior_rac_15'],
   ['+1', 'ior_rah_05', 'ior_wmc_1', 'ior_rc_15'],
   ['+2', 'ior_rah_15', 'ior_wmc_2', 'ior_rc_25'],
-  // ['0-1', 'ior_ot_0', 'ior_os_0-1', 'ior_ot_1'],
+  ['0-1', 'ior_ot_0', 'ior_os_0-1', 'ior_ot_1'],
   ['2-3', 'ior_ot_2', 'ior_os_2-3', 'ior_ot_3'],
 ];
 
-const BASE_URL = 'https://api.qboss.vip/api/p';
+// 测试环境
+// const BASE_URL = 'https://dev.api.czxd8.com/api/p';
 const IS_DEV = process.env.NODE_ENV == 'development';
+const BASE_URL = 'https://api.qboss.vip/api/p';
 
 const GAMES = {
   Leagues: {},
@@ -378,15 +380,29 @@ const getGamesEvents = ({ platform, relIds = [] } = {}) => {
 /**
  * 获取关联比赛
  */
+const getDevGameTast = () => {
+  return new Promise((resolve) => {
+    const data = Cache.getData(DevGameTastFile, true);
+    resolve({data});
+  });
+}
 const fetchGamesRelation = async (mk='') => {
-  return axios.get(`${BASE_URL}/getGameTast?mk=${mk}`)
-  .then(res => {
-    if (res.data.code == 0) {
-      const now = Date.now();
-      const gamesRelation = res.data.data?.filter(item => {
+  const getGameTast = Promise.all([
+    getDevGameTast(),
+    axios.get(`${BASE_URL}/getGameTast?mk=${mk}`)
+  ]);
+  return getGameTast.then(([res1, res2]) => {
+    const resData = res1.data ?? res2.data;
+    if (resData.code == 0) {
+      const nowTime = Date.now();
+      const gamesRelation = resData.data?.filter(item => {
         const timestamp = new Date(item.timestamp).getTime();
+        if (nowTime > timestamp) {
+          item.mk = 2;
+        }
         item.timestamp = timestamp;
-        return timestamp > now;
+        const expireTime = timestamp + 1000*60*60*2;
+        return expireTime > nowTime;
       }).map(item => {
         const {
           id, mk, league_name,
@@ -428,11 +444,11 @@ const fetchGamesRelation = async (mk='') => {
             timestamp
           } : null
         };
-        return { id: ps_event_id, mk, rel };
+        return { id: ps_event_id, mk, rel, timestamp };
       }) ?? [];
       return gamesRelation;
     }
-    return Promise.reject(new Error(res.data.message));
+    return Promise.reject(new Error(resData.message));
   });
 }
 
@@ -442,7 +458,8 @@ const getGamesRelation = ({ mk, listEvents } = {}) => {
       return true;
     }
     return item.mk == mk;
-  });
+  }).sort((a, b) => a.timestamp - b.timestamp);
+
   if (listEvents) {
     return relations;
   }
@@ -463,8 +480,7 @@ const getGamesRelation = ({ mk, listEvents } = {}) => {
  */
 const updateGamesRelation = () => {
   fetchGamesRelation()
-  .then(res => {
-    const gamesRelation = res.flat();
+  .then(gamesRelation => {
 
     const updateCount = {
       add: 0,
@@ -493,9 +509,9 @@ const updateGamesRelation = () => {
         updateCount.delete ++;
       }
       else {
-        const { rel } = GAMES.Relations[id];
-        const relTime = rel.ps?.timestamp;
-        if (relTime && relTime < Date.now()) {
+        const { timestamp } = GAMES.Relations[id];
+        const expireTime = timestamp ? timestamp + 1000*60*60*2 : 0;
+        if (expireTime && expireTime < Date.now()) {
           delete GAMES.Relations[id];
           updateCount.delete ++;
         }

+ 18 - 3
server/triangle/eventSolutions.js

@@ -80,12 +80,24 @@ const triangleProfitCalc = (betInfo) => {
     case 'la_la_wa': // 全输 全输 全赢
       win_side_c = k5*z - k2*x - k4*y;
       break;
+    case 'la_wa_rv': // 两盘口输赢
+      win_side_c = 0;
+      break;
+    default:
+      win_side_c = 0;
   }
 
   win_side_a = fixFloat(win_side_a + inner_rebate_value);
   win_side_b = fixFloat(win_side_b + inner_rebate_value);
   win_side_c = fixFloat(win_side_c + inner_rebate_value);
-  const win_average = fixFloat((win_side_a + win_side_b + win_side_c) / 3);
+  let win_average = 0;
+  if (cross_type == 'la_wa_rv') {
+    win_side_c = 0;
+    win_average = fixFloat((win_side_a + win_side_b) / 2);
+  }
+  else {
+    win_average = fixFloat((win_side_a + win_side_b + win_side_c) / 3);
+  }
 
   return { win_side_a, win_side_b, win_side_c, win_average }
 }
@@ -100,7 +112,7 @@ const triangleGoldCalc = (betInfo) => {
     rebate_side_b: B = 0,
     rebate_side_c: C = 0,
   } = betInfo;
-  if (!a || !b || !c) {
+  if (typeof a !== 'number' || typeof b !== 'number' || typeof c !== 'number') {
     return;
   }
   const k1 = a * (1 + A);
@@ -131,6 +143,9 @@ const triangleGoldCalc = (betInfo) => {
     case 'la_la_wa': // 全输 全输 全赢
       z = (k3 + k4) * y / (k5 + k6);
       break;
+    case 'la_wa_rv': // 两盘口输赢
+      z = 0;
+      break;
     default:
       z = 0;
   }
@@ -186,7 +201,7 @@ const eventSolutions = (betInfo, showGolds=false) => {
     result = {
       ...result,
       gold_side_a, gold_side_b, gold_side_c,
-      // win_side_a, win_side_b, win_side_c,
+      win_side_a, win_side_b, win_side_c,
     }
   }
   return result;

+ 16 - 16
server/triangle/iorKeys.js

@@ -94,11 +94,11 @@ module.exports = {
 
     ['ior_ouc_25', 'ior_ouh_2', 'ior_ot_2', 'la_dr_wa'],
 
-    // ['ior_os_0-1', 'ior_ouc_225', 'ior_ot_2', 'la_lh_wa'],
+    ['ior_os_0-1', 'ior_ouc_225', 'ior_ot_2', 'la_lh_wa'],
 
-    // ['ior_os_0-1', 'ior_ouc_25', 'ior_ot_2', 'la_la_wa'],
+    ['ior_os_0-1', 'ior_ouc_25', 'ior_ot_2', 'la_la_wa'],
 
-    // ['ior_os_0-1', 'ior_ouc_2', 'ior_ot_2', 'la_dr_wa'],
+    ['ior_os_0-1', 'ior_ouc_2', 'ior_ot_2', 'la_dr_wa'],
 
     ['ior_ouh_25', 'ior_ouc_275', 'ior_ot_3', 'la_wh_wa'],
 
@@ -120,19 +120,19 @@ module.exports = {
 
     ['ior_ouc_35', 'ior_ouh_25', 'ior_ot_3', 'la_la_wa'],
 
-    // ['ior_os_0-1', 'ior_ouc_35', 'ior_os_2-3', 'la_la_wa'],
+    ['ior_os_0-1', 'ior_ouc_35', 'ior_os_2-3', 'la_la_wa'],
 
   ],
-  // E: [
-  //   ['ior_rh_05', 'ior_rac_05', '-', 'la_wa_rv'],
-  //   ['ior_rc_05', 'ior_rah_05', '-', 'la_wa_rv'],
-  //   ['ior_mh', 'ior_rac_05', '-', 'la_wa_rv'],
-  //   ['ior_mc', 'ior_rah_05', '-', 'la_wa_rv'],
-
-  //   ['ior_rh_15', 'ior_rac_15', '-', 'la_wa_rv'],
-  //   ['ior_rc_15', 'ior_rah_15', '-', 'la_wa_rv'],
-
-  //   ['ior_rh_25', 'ior_rac_25', '-', 'la_wa_rv'],
-  //   ['ior_rc_25', 'ior_rah_25', '-', 'la_wa_rv'],
-  // ]
+  E: [
+    ['ior_rh_05', 'ior_rac_05', '-', 'la_wa_rv'],
+    ['ior_rc_05', 'ior_rah_05', '-', 'la_wa_rv'],
+    ['ior_mh', 'ior_rac_05', '-', 'la_wa_rv'],
+    ['ior_mc', 'ior_rah_05', '-', 'la_wa_rv'],
+
+    ['ior_rh_15', 'ior_rac_15', '-', 'la_wa_rv'],
+    ['ior_rc_15', 'ior_rah_15', '-', 'la_wa_rv'],
+
+    ['ior_rh_25', 'ior_rac_25', '-', 'la_wa_rv'],
+    ['ior_rc_25', 'ior_rah_25', '-', 'la_wa_rv'],
+  ]
 }

+ 17 - 1
server/triangle/totalProfitCalc.js

@@ -17,7 +17,7 @@ const fixFloat = (number, x = 2) => {
  * 正数为输
  * 负数为赢
  */
-const CROSS_TYPE_MAP = { w: -1, l: 1, a: 1, h: 0.5, d: 0, r: 0 };
+const CROSS_TYPE_MAP = { w: -1, l: 1, a: 1, h: 0.5, d: 0, r: 0, v: 0 };
 const lossProportion = (sol) => {
   const { cross_type, odds_side_a, odds_side_b, rebate_side_a, rebate_side_b } = sol;
   const typeList = cross_type.split('_').map(part => {
@@ -170,6 +170,22 @@ const HandicapCalc = function (data) {
           return { x, y, z };
         }
       ]);
+    },
+    la_wa_rv() {
+      return calcTemplate([
+        () => {
+          const x = g;
+          const y = (k2 * x + t) / k3;
+          const z = 0;
+          return { x, y, z };
+        },
+        () => {
+          const y = g;
+          const x = (k4 * y + t) / k1;
+          const z = 0;
+          return { x, y, z };
+        }
+      ]);
     }
   }
 }

+ 8 - 4
server/triangle/trangleCalc.js

@@ -24,8 +24,10 @@ function getOptimalSelections(odds, rules) {
       let isValid = true;
       for (let j = 0; j < 3; j++) {
         const key = rule[j];
-        const item = odds[key];
-
+        let item = odds[key];
+        if (key == '-') {
+          item = { no: 1};
+        }
         if (!item) {
           isValid = false;
           break;
@@ -43,7 +45,7 @@ function getOptimalSelections(odds, rules) {
           });
         }
         else {
-          const candidates = ['ob', 'hg'].filter((k) => k in item);
+          const candidates = ['ob', 'hg', 'no'].filter((k) => k in item);
           if (candidates.length === 0) {
             isValid = false;
             break;
@@ -134,7 +136,6 @@ const eventsCombination = (passableEvents) => {
     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;
@@ -159,6 +160,9 @@ const eventsCombination = (passableEvents) => {
           rebate_side_c: parseFloat((oddsSideC.r / 100).toFixed(4)),
         };
         const sol = eventSolutions(betInfo, true);
+        if (cpr[2].k == '-') {
+          cpr.pop();
+        }
         if (sol?.win_average > minProfitAmount) {
           const id = info.id;
           const sortedCpr = sortCpr(cpr);

+ 0 - 1
web/apps/web-antd/src/views/match/solutions/index.vue

@@ -164,7 +164,6 @@ const parseIorKey = (iorKey) => {
 
 const PS_IOR_KEYS = [
   ['0', 'ior_mh', 'ior_mn', 'ior_mc'],
-  // ['0', 'ior_rh_05', 'ior_mn', 'ior_rc_05'],
   ['-1', 'ior_rh_15', 'ior_wmh_1', 'ior_rac_05'],
   ['-2', 'ior_rh_25', 'ior_wmh_2', 'ior_rac_15'],
   ['+1', 'ior_rah_05', 'ior_wmc_1', 'ior_rc_15'],