|
@@ -3,8 +3,14 @@ const fixFloat = (number, x = 2) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const HandicapCalc = function (data) {
|
|
const HandicapCalc = function (data) {
|
|
|
- const { i, g, a, b, c, w, l } = data;
|
|
|
|
|
|
|
+ const { i, g, a, b, c, A, B, C, w, l } = data;
|
|
|
const t = w + l;
|
|
const t = w + l;
|
|
|
|
|
+ const k1 = a * (1 + A);
|
|
|
|
|
+ const k2 = 1 - A;
|
|
|
|
|
+ const k3 = b * (1 + B);
|
|
|
|
|
+ const k4 = 1 - B;
|
|
|
|
|
+ const k5 = c * (1 + C);
|
|
|
|
|
+ const k6 = 1 - C;
|
|
|
|
|
|
|
|
const calcTemplate = (handlers) => {
|
|
const calcTemplate = (handlers) => {
|
|
|
if (i > 2 || i < 0) {
|
|
if (i > 2 || i < 0) {
|
|
@@ -12,8 +18,9 @@ const HandicapCalc = function (data) {
|
|
|
}
|
|
}
|
|
|
if (i === 2) {
|
|
if (i === 2) {
|
|
|
const z = g;
|
|
const z = g;
|
|
|
- const x = (b + 1) * (t + z) / (a * b - 1);
|
|
|
|
|
- const y = (a + 1) * (t + z) / (a * b - 1);
|
|
|
|
|
|
|
+ const m = t + k6 * z;
|
|
|
|
|
+ const x = (k3 + k4) * m / (k1 * k3 - k2 * k4);
|
|
|
|
|
+ const y = (k1 + k2) * m / (k1 * k3 - k2 * k4);
|
|
|
return { x, y, z };
|
|
return { x, y, z };
|
|
|
};
|
|
};
|
|
|
return handlers[i]?.() ?? {};
|
|
return handlers[i]?.() ?? {};
|
|
@@ -24,14 +31,15 @@ const HandicapCalc = function (data) {
|
|
|
return calcTemplate([
|
|
return calcTemplate([
|
|
|
() => {
|
|
() => {
|
|
|
const x = g;
|
|
const x = g;
|
|
|
- const z = (t + x) / (2 * c + 1);
|
|
|
|
|
- const y = (c + 1) * (t + x) / (c + 0.5) / b;
|
|
|
|
|
|
|
+ const m = t + x - A * x;
|
|
|
|
|
+ const z = m / k5 * 2 + k6;
|
|
|
|
|
+ const y = (k5 + k6) * m / (k3 * k5 + k3 * k6 / 2);
|
|
|
return { x, y, z };
|
|
return { x, y, z };
|
|
|
},
|
|
},
|
|
|
() => {
|
|
() => {
|
|
|
const y = g;
|
|
const y = g;
|
|
|
- const z = ((a + 1) * t + (1 - a * b / 2) * y) / (a * c - 1);
|
|
|
|
|
- const x = ((c + 1) * t + (c - b / 2) * y) / (a * c - 1);
|
|
|
|
|
|
|
+ const z = ((k1 + k2) * t + (k2 * k4 - k1 * k3 / 2) * y) / (k1 * k5 - k2 * k6);
|
|
|
|
|
+ const x = ((k5 + k6) * t + (k4 * k5 - k3 * k6 / 2) * y) / (k1 * k5 - k2 * k6);
|
|
|
return { x, y, z };
|
|
return { x, y, z };
|
|
|
}
|
|
}
|
|
|
]);
|
|
]);
|
|
@@ -118,10 +126,53 @@ const HandicapCalc = function (data) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 计算输赢比例
|
|
|
|
|
+ * 与其他方法中的输赢逻辑相反
|
|
|
|
|
+ * 正数为输
|
|
|
|
|
+ * 负数为赢
|
|
|
|
|
+ */
|
|
|
|
|
+const CROSS_TYPE_MAP = { w: -1, l: 1, a: 1, h: 0.5, d: 0, r: 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 => {
|
|
|
|
|
+ return part.split('').map(key => CROSS_TYPE_MAP[key]);
|
|
|
|
|
+ }).map(([a, b])=> a * b);
|
|
|
|
|
+
|
|
|
|
|
+ let loss_proportion_a = 0, loss_proportion_b = 0;
|
|
|
|
|
+ if (typeList[0] >= 0) {
|
|
|
|
|
+ loss_proportion_a = typeList[0] * (1 - rebate_side_a);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ loss_proportion_a = typeList[0] * odds_side_a * (1 + rebate_side_a);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (typeList[1] >= 0) {
|
|
|
|
|
+ loss_proportion_b = typeList[1] * (1 - rebate_side_b);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ loss_proportion_b = typeList[1] * odds_side_b * (1 + rebate_side_b);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return { loss_proportion_a, loss_proportion_b };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const calcExternalHandicap = (data) => {
|
|
const calcExternalHandicap = (data) => {
|
|
|
- const { gold_side_inner: g, odds_side_a: a, odds_side_b: b, odds_side_c: c, inner_index: i, cross_type: t, win_target: w, loss_out_1 } = data;
|
|
|
|
|
|
|
+ const {
|
|
|
|
|
+ gold_side_inner: g,
|
|
|
|
|
+ odds_side_a: a,
|
|
|
|
|
+ odds_side_b: b,
|
|
|
|
|
+ odds_side_c: c,
|
|
|
|
|
+ rebate_side_a: A,
|
|
|
|
|
+ rebate_side_b: B,
|
|
|
|
|
+ rebate_side_c: C,
|
|
|
|
|
+ inner_index: i,
|
|
|
|
|
+ cross_type: t,
|
|
|
|
|
+ win_target: w,
|
|
|
|
|
+ loss_out_1,
|
|
|
|
|
+ } = data;
|
|
|
const l = loss_out_1 ?? 0;
|
|
const l = loss_out_1 ?? 0;
|
|
|
- const calc = new HandicapCalc({ i, g, a, b, c, w, l });
|
|
|
|
|
|
|
+ const calc = new HandicapCalc({ i, g, a, b, c, A, B, C, w, l });
|
|
|
const { x, y, z } = calc?.[t]() ?? {};
|
|
const { x, y, z } = calc?.[t]() ?? {};
|
|
|
return {
|
|
return {
|
|
|
gold_side_a: fixFloat(x),
|
|
gold_side_a: fixFloat(x),
|
|
@@ -129,7 +180,6 @@ const calcExternalHandicap = (data) => {
|
|
|
gold_side_c: fixFloat(z),
|
|
gold_side_c: fixFloat(z),
|
|
|
inner_index: i,
|
|
inner_index: i,
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const calcGoldsWithWinTarget = (data) => {
|
|
const calcGoldsWithWinTarget = (data) => {
|
|
@@ -138,22 +188,29 @@ const calcGoldsWithWinTarget = (data) => {
|
|
|
gold_side_a: goldA1,
|
|
gold_side_a: goldA1,
|
|
|
gold_side_b: goldB1,
|
|
gold_side_b: goldB1,
|
|
|
gold_side_c: goldC1,
|
|
gold_side_c: goldC1,
|
|
|
- inner_index: inner_index_1
|
|
|
|
|
|
|
+ odds_side_a: oddsA1,
|
|
|
|
|
+ odds_side_b: oddsB1,
|
|
|
|
|
+ odds_side_c: oddsC1,
|
|
|
|
|
+ rebate_side_a: rebateA1,
|
|
|
|
|
+ rebate_side_b: rebateB1,
|
|
|
|
|
+ rebate_side_c: rebateC1,
|
|
|
|
|
+ inner_index: inner_index_1,
|
|
|
} = calcExternalHandicap({ ...sol1, gold_side_inner, win_target });
|
|
} = calcExternalHandicap({ ...sol1, gold_side_inner, win_target });
|
|
|
|
|
|
|
|
let loss_out_1 = 0, win_inner_1 = 0;
|
|
let loss_out_1 = 0, win_inner_1 = 0;
|
|
|
switch (inner_index_1) {
|
|
switch (inner_index_1) {
|
|
|
case 0:
|
|
case 0:
|
|
|
loss_out_1 = goldB1 + goldC1;
|
|
loss_out_1 = goldB1 + goldC1;
|
|
|
- win_inner_1 = gold_side_inner * (sol1.odds_side_a + 1);
|
|
|
|
|
|
|
+ win_inner_1 = gold_side_inner * (oddsA1 + 1);
|
|
|
break;
|
|
break;
|
|
|
case 1:
|
|
case 1:
|
|
|
loss_out_1 = goldA1 + goldC1;
|
|
loss_out_1 = goldA1 + goldC1;
|
|
|
- win_inner_1 = gold_side_inner * (sol1.odds_side_b + 1);
|
|
|
|
|
|
|
+ win_inner_1 = gold_side_inner * (oddsB1 + 1);
|
|
|
break;
|
|
break;
|
|
|
case 2:
|
|
case 2:
|
|
|
- loss_out_1 = goldA1 + goldB1;
|
|
|
|
|
- win_inner_1 = gold_side_inner * (sol1.odds_side_c + 1)
|
|
|
|
|
|
|
+ const { loss_proportion_a: lpA1, loss_proportion_b: lpB1 } = lossProportion(sol1);
|
|
|
|
|
+ loss_out_1 = goldA1 * lpA1 + goldB1 * lpB1 ;
|
|
|
|
|
+ win_inner_1 = gold_side_inner * (oddsC1 + 1)
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -161,7 +218,13 @@ const calcGoldsWithWinTarget = (data) => {
|
|
|
gold_side_a: goldA2,
|
|
gold_side_a: goldA2,
|
|
|
gold_side_b: goldB2,
|
|
gold_side_b: goldB2,
|
|
|
gold_side_c: goldC2,
|
|
gold_side_c: goldC2,
|
|
|
- inner_index: inner_index_2
|
|
|
|
|
|
|
+ odds_side_a: oddsA2,
|
|
|
|
|
+ odds_side_b: oddsB2,
|
|
|
|
|
+ odds_side_c: oddsC2,
|
|
|
|
|
+ rebate_side_a: rebateA2,
|
|
|
|
|
+ rebate_side_b: rebateB2,
|
|
|
|
|
+ rebate_side_c: rebateC2,
|
|
|
|
|
+ inner_index: inner_index_2,
|
|
|
} = calcExternalHandicap({ ...sol2, gold_side_inner, win_target, loss_out_1 });
|
|
} = calcExternalHandicap({ ...sol2, gold_side_inner, win_target, loss_out_1 });
|
|
|
|
|
|
|
|
let loss_out_2 = 0, win_inner_2 = 0, inner_base_key;
|
|
let loss_out_2 = 0, win_inner_2 = 0, inner_base_key;
|
|
@@ -169,17 +232,18 @@ const calcGoldsWithWinTarget = (data) => {
|
|
|
case 0:
|
|
case 0:
|
|
|
inner_base_key = 'goldA2';
|
|
inner_base_key = 'goldA2';
|
|
|
loss_out_2 = gold_side_inner +goldB2 + goldC2 + loss_out_1;
|
|
loss_out_2 = gold_side_inner +goldB2 + goldC2 + loss_out_1;
|
|
|
- win_inner_2 = win_inner_1 * (sol2.odds_side_a + 1);
|
|
|
|
|
|
|
+ win_inner_2 = win_inner_1 * (oddsA2 + 1);
|
|
|
break;
|
|
break;
|
|
|
case 1:
|
|
case 1:
|
|
|
inner_base_key = 'goldB2';
|
|
inner_base_key = 'goldB2';
|
|
|
loss_out_2 = gold_side_inner + goldA2 + goldC2 + loss_out_1;
|
|
loss_out_2 = gold_side_inner + goldA2 + goldC2 + loss_out_1;
|
|
|
- win_inner_2 = win_inner_1 * (sol2.odds_side_b + 1);
|
|
|
|
|
|
|
+ win_inner_2 = win_inner_1 * (oddsB2 + 1);
|
|
|
break;
|
|
break;
|
|
|
case 2:
|
|
case 2:
|
|
|
|
|
+ const { loss_proportion_a: lpA2, loss_proportion_b: lpB2 } = lossProportion(sol2);
|
|
|
inner_base_key = 'goldC2';
|
|
inner_base_key = 'goldC2';
|
|
|
- loss_out_2 = gold_side_inner + goldA2 + goldB2 + loss_out_1;
|
|
|
|
|
- win_inner_2 = win_inner_1 * (sol2.odds_side_c + 1);
|
|
|
|
|
|
|
+ loss_out_2 = gold_side_inner + goldA2 * lpA2 + goldB2 * lpB2 + loss_out_1;
|
|
|
|
|
+ win_inner_2 = win_inner_1 * (oddsC2 + 1);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|