|
@@ -3,6 +3,7 @@ const Logs = require('../libs/logs');
|
|
|
const Cache = require('../libs/cache');
|
|
const Cache = require('../libs/cache');
|
|
|
const Setting = require('./Setting');
|
|
const Setting = require('./Setting');
|
|
|
const { eventSolutions } = require('../triangle/eventSolutions');
|
|
const { eventSolutions } = require('../triangle/eventSolutions');
|
|
|
|
|
+const { getPassableEvents, eventsCombination } = require('../triangle/trangleCalc');
|
|
|
const { calcTotalProfit, calcTotalProfitWithFixedFirst } = require('../triangle/totalProfitCalc');
|
|
const { calcTotalProfit, calcTotalProfitWithFixedFirst } = require('../triangle/totalProfitCalc');
|
|
|
const { getSetting, updateSetting } = require('../triangle/settings');
|
|
const { getSetting, updateSetting } = require('../triangle/settings');
|
|
|
|
|
|
|
@@ -621,7 +622,7 @@ const getGamesEvents = ({ platform, relIds = [] } = {}) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 获取关联比赛
|
|
|
|
|
|
|
+ * 获取远程关联比赛列表
|
|
|
*/
|
|
*/
|
|
|
const fetchGamesRelation = async (mk='') => {
|
|
const fetchGamesRelation = async (mk='') => {
|
|
|
return axios.get(`${BASE_API_URL}/p/getGameTast?mk=${mk}`, {
|
|
return axios.get(`${BASE_API_URL}/p/getGameTast?mk=${mk}`, {
|
|
@@ -686,31 +687,87 @@ const fetchGamesRelation = async (mk='') => {
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const getGamesRelation = ({ mk=-1, ids, listEvents } = {}) => {
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取PC数据
|
|
|
|
|
+ */
|
|
|
|
|
+const getPCEvents = (events) => {
|
|
|
|
|
+ if (!events) {
|
|
|
|
|
+ return undefined;
|
|
|
|
|
+ }
|
|
|
|
|
+ const pcEvents = {};
|
|
|
|
|
+ Object.keys(events).forEach(ior => {
|
|
|
|
|
+ const { v, s, r } = events[ior];
|
|
|
|
|
+ pcEvents[ior] = {
|
|
|
|
|
+ v: s ?? v,
|
|
|
|
|
+ r: r
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ return pcEvents;
|
|
|
|
|
+}
|
|
|
|
|
+const getPCData = (id) => {
|
|
|
|
|
+ const baseList = Object.values(GAMES.Baselist).flat();
|
|
|
|
|
+ const baseMap = new Map(baseList.map(item => [item.eventId, item]));
|
|
|
|
|
+ const baseGame = baseMap.get(id);
|
|
|
|
|
+ if (!baseGame) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ const { matches, events, special, ...gameInfo } = baseGame;
|
|
|
|
|
+ return {
|
|
|
|
|
+ events: getPCEvents(events),
|
|
|
|
|
+ special: getPCEvents(special),
|
|
|
|
|
+ ...gameInfo
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取关联比赛列表
|
|
|
|
|
+ * @param {object} options
|
|
|
|
|
+ * @property {number} mk
|
|
|
|
|
+ * @property {number[]} ids
|
|
|
|
|
+ * @property {boolean} listEvents
|
|
|
|
|
+ * @property {boolean} listPC
|
|
|
|
|
+ * @returns {object[]}
|
|
|
|
|
+ */
|
|
|
|
|
+const getGamesRelation = ({ mk=-1, ids, listEvents=false, listPC=false } = {}) => {
|
|
|
let idsSet = null;
|
|
let idsSet = null;
|
|
|
if (ids?.length) {
|
|
if (ids?.length) {
|
|
|
idsSet = new Set(ids);
|
|
idsSet = new Set(ids);
|
|
|
}
|
|
}
|
|
|
- const relations = Object.values(GAMES.Relations).filter(item => {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ let relations;
|
|
|
|
|
+ if (ids?.length) {
|
|
|
|
|
+ relations = ids.map(id => GAMES.Relations[id]);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ relations = Object.values(GAMES.Relations);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ relations = relations.filter(item => {
|
|
|
if (idsSet && !idsSet.has(item.id)) {
|
|
if (idsSet && !idsSet.has(item.id)) {
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
return mk == -1 || item.mk == mk;
|
|
return mk == -1 || item.mk == mk;
|
|
|
}).sort((a, b) => a.timestamp - b.timestamp);
|
|
}).sort((a, b) => a.timestamp - b.timestamp);
|
|
|
|
|
|
|
|
- if (listEvents) {
|
|
|
|
|
|
|
+ if (listEvents && !listPC) {
|
|
|
return relations;
|
|
return relations;
|
|
|
}
|
|
}
|
|
|
- const gamesRelation = relations.map(item => {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ return relations.map(item => {
|
|
|
const { rel, ...relationInfo } = item;
|
|
const { rel, ...relationInfo } = item;
|
|
|
const tempRel = { ...rel };
|
|
const tempRel = { ...rel };
|
|
|
- Object.keys(tempRel).forEach(platform => {
|
|
|
|
|
- const { events, evtime, sptime, special, ...gameInfo } = tempRel[platform];
|
|
|
|
|
- tempRel[platform] = gameInfo;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const { id } = relationInfo;
|
|
|
|
|
+ if (listPC) {
|
|
|
|
|
+ tempRel.pc = getPCData(id);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!listEvents) {
|
|
|
|
|
+ Object.keys(tempRel).forEach(platform => {
|
|
|
|
|
+ const { events, evtime, special, sptime, ...gameInfo } = tempRel[platform];
|
|
|
|
|
+ tempRel[platform] = gameInfo;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
return { ...relationInfo, rel: tempRel };
|
|
return { ...relationInfo, rel: tempRel };
|
|
|
});
|
|
});
|
|
|
- return gamesRelation;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1184,8 +1241,8 @@ const getTotalProfitWithBetInfo = async (betInfo1, betInfo2, fixed=false, inner_
|
|
|
return Promise.reject(new Error('第二个下注信息无效'));
|
|
return Promise.reject(new Error('第二个下注信息无效'));
|
|
|
}
|
|
}
|
|
|
const { innerDefaultAmount, innerRebateRatio } = getSetting();
|
|
const { innerDefaultAmount, innerRebateRatio } = getSetting();
|
|
|
- inner_base = inner_base ? +inner_base : innerDefaultAmount;
|
|
|
|
|
- inner_rebate = inner_rebate ? +inner_rebate : fixFloat(innerRebateRatio / 100, 3);
|
|
|
|
|
|
|
+ inner_base = typeof(inner_base) != 'undefined' ? +inner_base : innerDefaultAmount;
|
|
|
|
|
+ inner_rebate = typeof(inner_rebate) != 'undefined' ? +inner_rebate : fixFloat(innerRebateRatio / 100, 3);
|
|
|
|
|
|
|
|
if (fixed) {
|
|
if (fixed) {
|
|
|
return calcTotalProfitWithFixedFirst(betInfo1, betInfo2, inner_base, inner_rebate);
|
|
return calcTotalProfitWithFixedFirst(betInfo1, betInfo2, inner_base, inner_rebate);
|
|
@@ -1195,6 +1252,62 @@ const getTotalProfitWithBetInfo = async (betInfo1, betInfo2, fixed=false, inner_
|
|
|
return getTotalProfit(sol1, sol2, inner_base, inner_rebate);
|
|
return getTotalProfit(sol1, sol2, inner_base, inner_rebate);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 计算补单综合利润
|
|
|
|
|
+ */
|
|
|
|
|
+const getTotalReplacement = async (event_id, inner_base, inner_rebate, inner_ior, inner_odds, outer_golds) => {
|
|
|
|
|
+ // return Promise.resolve();
|
|
|
|
|
+ if (!event_id) {
|
|
|
|
|
+ return Promise.reject(new Error('event_id 无效'));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!inner_ior) {
|
|
|
|
|
+ return Promise.reject(new Error('inner_ior 无效'));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (inner_odds?.length != 2) {
|
|
|
|
|
+ return Promise.reject(new Error('inner_odds 无效'));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!outer_golds?.length) {
|
|
|
|
|
+ return Promise.reject(new Error('outer_golds 无效'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const { innerDefaultAmount, innerRebateRatio } = getSetting();
|
|
|
|
|
+ inner_base = typeof(inner_base) != 'undefined' ? +inner_base : innerDefaultAmount;
|
|
|
|
|
+ inner_rebate = typeof(inner_rebate) != 'undefined' ? +inner_rebate : fixFloat(innerRebateRatio / 100, 3);
|
|
|
|
|
+
|
|
|
|
|
+ const inner_odds_value = fixFloat(inner_odds[0] * inner_odds[1], 3);
|
|
|
|
|
+ const outer_golds_rebate = outer_golds.map(item => item.gold * item.rebate).reduce((sum, rebate) => sum + rebate, 0);
|
|
|
|
|
+ const outer_golds_loss = outer_golds.map(item => item.gold).reduce((sum, gold) => sum + gold, 0) - outer_golds_rebate;
|
|
|
|
|
+
|
|
|
|
|
+ const relation = getGamesRelation({ ids: [event_id], listEvents: true, listPC: true }).map(item => {
|
|
|
|
|
+ const { rel, ...relationInfo } = item;
|
|
|
|
|
+ const tempRel = { ...rel };
|
|
|
|
|
+ const events = {};
|
|
|
|
|
+ events[inner_ior] = { v: inner_odds_value };
|
|
|
|
|
+ tempRel.ps = { ...rel.ps, events }
|
|
|
|
|
+ return { ...relationInfo, rel: tempRel };
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const passableEvents = getPassableEvents(relation, null);
|
|
|
|
|
+ const solutions = eventsCombination(passableEvents, inner_base, inner_rebate);
|
|
|
|
|
+
|
|
|
|
|
+ if (!solutions?.length) {
|
|
|
|
|
+ return Promise.reject(new Error('没有可用的解决方案'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return solutions.filter(solution => !solution.lower).map(solution => {
|
|
|
|
|
+ const { sid, info, sol, ...solutionInfo } = solution;
|
|
|
|
|
+ const { win_profit_rate, win_average_rate, ...solInfo } = sol;
|
|
|
|
|
+ const { cross_type } = solInfo;
|
|
|
|
|
+ solInfo.win_side_a = typeof(solInfo.win_side_a) !== 'number' ? undefined : fixFloat(solInfo.win_side_a - outer_golds_loss);
|
|
|
|
|
+ solInfo.win_side_b = typeof(solInfo.win_side_b) !== 'number' ? undefined : fixFloat(solInfo.win_side_b - outer_golds_loss);
|
|
|
|
|
+ solInfo.win_side_c = cross_type == 'la_wa_rv' ? 0 : (typeof(solInfo.win_side_c) !== 'number' ? undefined : fixFloat(solInfo.win_side_c - outer_golds_loss));
|
|
|
|
|
+ solInfo.win_average = fixFloat(solInfo.win_average - outer_golds_loss);
|
|
|
|
|
+
|
|
|
|
|
+ return { ...solutionInfo, sol: solInfo };
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 同步Qboss平台配置
|
|
* 同步Qboss平台配置
|
|
|
*/
|
|
*/
|
|
@@ -1389,7 +1502,6 @@ module.exports = {
|
|
|
updateGamesResult,
|
|
updateGamesResult,
|
|
|
updateOriginalData, getOriginalData,
|
|
updateOriginalData, getOriginalData,
|
|
|
getSolutions, getGamesSolutions, getSolution, getSolutionsByIds,
|
|
getSolutions, getGamesSolutions, getSolution, getSolutionsByIds,
|
|
|
- getTotalProfitWithSid,
|
|
|
|
|
- getTotalProfitWithBetInfo,
|
|
|
|
|
|
|
+ getTotalProfitWithSid, getTotalProfitWithBetInfo, getTotalReplacement,
|
|
|
notifyException,
|
|
notifyException,
|
|
|
}
|
|
}
|