FA-84546 / Betting odds conversion / Open access
Hedge stake matched on profit instead of total return · case 01
The hedged position still has unequal outcomes.
ROOT CAUSE
The lay stake is back_stake * (back_price - 1) / (lay_price - 1), matching liabilities only.
VERIFIED REPAIR
Use back_stake * back_price / lay_price.
Unsuccessful approach: Inverting the price ratio moves the stake in the wrong direction.
Case contract
Green-up a matched back bet by laying at a later price (both > 1, else "invalid"). The equal-profit lay stake is back_stake * back_price / lay_price rounded half up to a cent. Using that rounded lay stake: liability = lay_stake * (lay_price - 1), profit if the selection wins = back_stake * (back_price - 1) - liability, profit if it loses = lay_stake - back_stake. Money values are exact then rounded half up to cents. Return [lay_stake, liability, profit_win, profit_lose].
Why this case matters
Exchange trading tools compute hedge stakes that equalise profit across outcomes.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(back_stake, back_price, lay_price):
bp = Fraction(back_price)
lp = Fraction(lay_price)
if bp <= 1 or lp <= 1:
return 'invalid'
def cents(x):
return math.floor(x + Fraction(1, 2))
lay = cents(back_stake * (bp - 1) / (lp - 1))
liability = lay * (lp - 1)
win = back_stake * (bp - 1) - liability
lose = lay - back_stake
return [lay, cents(liability), cents(win), cents(lose)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
try:
return solve(*args)
except Exception as exc:
return 'raised ' + type(exc).__name__
cases = [[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '7.81', '7.55'), [2586, 16938, 87, 86]),
('variant scenario 1', (1000, '3.26', '7.05'), [462, 2795, -535, -538]),
('variant scenario 2', (2500, '7.95', '5.04'), [3943, 15930, 1445, 1443])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (777, '1.59', '7.16'), [173, 1066, -607, -604]),
('variant scenario 1', (1000, '6.72', '3.81'), [1764, 4957, 763, 764]),
('variant scenario 2', (333, '1.45', '2.25'), [215, 269, -119, -118])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '3.88', '7.37'), [1316, 8383, -1183, -1184]),
('variant scenario 1', (1000, '7.55', '7.11'), [1062, 6489, 61, 62]),
('variant scenario 2', (777, '2.80', '3.78'), [576, 1601, -203, -201])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (333, '3.90', '7.35'), [177, 1124, -158, -156]),
('variant scenario 1', (777, '6.63', '2.19'), [2352, 2799, 1576, 1575]),
('variant scenario 2', (333, '3.52', '4.20'), [279, 893, -54, -54])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '7.26', '4.46'), [4070, 14082, 1568, 1570]),
('variant scenario 1', (333, '5.42', '2.88'), [627, 1179, 293, 294]),
('variant scenario 2', (1000, '5.50', '7.68'), [716, 4783, -283, -284])]]
for label, args, expected in cases[N - 1]:
check(label, run(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control price shortened | [2000, 2000, 0, 1000] | [1500, 1500, 500, 500] | Failed |
| control price drifted | [333, 999, 1, -667] | [500, 1500, -500, -500] | Failed |
| boundary no movement | [1000, 1500, 0, 0] | [1000, 1500, 0, 0] | Passed |
| boundary invalid price | invalid | invalid | Passed |
| regression: hedge ratio | [2599, 17023, 2, 99] | [2586, 16938, 87, 86] | Failed |
| variant scenario 1 | [374, 2263, -3, -626] | [462, 2795, -535, -538] | Failed |
| variant scenario 2 | [4301, 17376, -1, 1801] | [3943, 15930, 1445, 1443] | Failed |
SHA-256 / 9239fa4b65f2131a24c8bb423fccb5dff3b4917e10c0bbd443149f09e264e843
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(back_stake, back_price, lay_price):
bp = Fraction(back_price)
lp = Fraction(lay_price)
if bp <= 1 or lp <= 1:
return 'invalid'
def cents(x):
return math.floor(x + Fraction(1, 2))
lay = cents(back_stake * lp / bp)
liability = lay * (lp - 1)
win = back_stake * (bp - 1) - liability
lose = lay - back_stake
return [lay, cents(liability), cents(win), cents(lose)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
try:
return solve(*args)
except Exception as exc:
return 'raised ' + type(exc).__name__
cases = [[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '7.81', '7.55'), [2586, 16938, 87, 86]),
('variant scenario 1', (1000, '3.26', '7.05'), [462, 2795, -535, -538]),
('variant scenario 2', (2500, '7.95', '5.04'), [3943, 15930, 1445, 1443])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (777, '1.59', '7.16'), [173, 1066, -607, -604]),
('variant scenario 1', (1000, '6.72', '3.81'), [1764, 4957, 763, 764]),
('variant scenario 2', (333, '1.45', '2.25'), [215, 269, -119, -118])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '3.88', '7.37'), [1316, 8383, -1183, -1184]),
('variant scenario 1', (1000, '7.55', '7.11'), [1062, 6489, 61, 62]),
('variant scenario 2', (777, '2.80', '3.78'), [576, 1601, -203, -201])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (333, '3.90', '7.35'), [177, 1124, -158, -156]),
('variant scenario 1', (777, '6.63', '2.19'), [2352, 2799, 1576, 1575]),
('variant scenario 2', (333, '3.52', '4.20'), [279, 893, -54, -54])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '7.26', '4.46'), [4070, 14082, 1568, 1570]),
('variant scenario 1', (333, '5.42', '2.88'), [627, 1179, 293, 294]),
('variant scenario 2', (1000, '5.50', '7.68'), [716, 4783, -283, -284])]]
for label, args, expected in cases[N - 1]:
check(label, run(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control price shortened | [667, 667, 1333, -333] | [1500, 1500, 500, 500] | Failed |
| control price drifted | [2000, 6000, -5000, 1000] | [500, 1500, -500, -500] | Failed |
| boundary no movement | [1000, 1500, 0, 0] | [1000, 1500, 0, 0] | Passed |
| boundary invalid price | invalid | invalid | Passed |
| regression: hedge ratio | [2417, 15831, 1194, -83] | [2586, 16938, 87, 86] | Failed |
| variant scenario 1 | [2163, 13086, -10826, 1163] | [462, 2795, -535, -538] | Failed |
| variant scenario 2 | [1585, 6403, 10972, -915] | [3943, 15930, 1445, 1443] | Failed |
SHA-256 / 637cd3e6cd5d209ed09c4f572d0d8d85868989a052a1ffd8e937a81b54c86eaa
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(back_stake, back_price, lay_price):
bp = Fraction(back_price)
lp = Fraction(lay_price)
if bp <= 1 or lp <= 1:
return 'invalid'
def cents(x):
return math.floor(x + Fraction(1, 2))
lay = cents(back_stake * bp / lp)
liability = lay * (lp - 1)
win = back_stake * (bp - 1) - liability
lose = lay - back_stake
return [lay, cents(liability), cents(win), cents(lose)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
try:
return solve(*args)
except Exception as exc:
return 'raised ' + type(exc).__name__
cases = [[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '7.81', '7.55'), [2586, 16938, 87, 86]),
('variant scenario 1', (1000, '3.26', '7.05'), [462, 2795, -535, -538]),
('variant scenario 2', (2500, '7.95', '5.04'), [3943, 15930, 1445, 1443])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (777, '1.59', '7.16'), [173, 1066, -607, -604]),
('variant scenario 1', (1000, '6.72', '3.81'), [1764, 4957, 763, 764]),
('variant scenario 2', (333, '1.45', '2.25'), [215, 269, -119, -118])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '3.88', '7.37'), [1316, 8383, -1183, -1184]),
('variant scenario 1', (1000, '7.55', '7.11'), [1062, 6489, 61, 62]),
('variant scenario 2', (777, '2.80', '3.78'), [576, 1601, -203, -201])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (333, '3.90', '7.35'), [177, 1124, -158, -156]),
('variant scenario 1', (777, '6.63', '2.19'), [2352, 2799, 1576, 1575]),
('variant scenario 2', (333, '3.52', '4.20'), [279, 893, -54, -54])],
[('control price shortened', (1000, '3.00', '2.00'), [1500, 1500, 500, 500]),
('control price drifted', (1000, '2.00', '4.00'), [500, 1500, -500, -500]),
('boundary no movement', (1000, '2.50', '2.50'), [1000, 1500, 0, 0]),
('boundary invalid price', (1000, '1.00', '2.00'), 'invalid'),
('regression: hedge ratio', (2500, '7.26', '4.46'), [4070, 14082, 1568, 1570]),
('variant scenario 1', (333, '5.42', '2.88'), [627, 1179, 293, 294]),
('variant scenario 2', (1000, '5.50', '7.68'), [716, 4783, -283, -284])]]
for label, args, expected in cases[N - 1]:
check(label, run(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control price shortened | [1500, 1500, 500, 500] | [1500, 1500, 500, 500] | Passed |
| control price drifted | [500, 1500, -500, -500] | [500, 1500, -500, -500] | Passed |
| boundary no movement | [1000, 1500, 0, 0] | [1000, 1500, 0, 0] | Passed |
| boundary invalid price | invalid | invalid | Passed |
| regression: hedge ratio | [2586, 16938, 87, 86] | [2586, 16938, 87, 86] | Passed |
| variant scenario 1 | [462, 2795, -535, -538] | [462, 2795, -535, -538] | Passed |
| variant scenario 2 | [3943, 15930, 1445, 1443] | [3943, 15930, 1445, 1443] | Passed |
SHA-256 / 60b35688d8d2f12f19779384cb1279aa1ac17753b268914871ca2e460d5123a5
Verification & scope
Stipulated, bounded toy contract stated in the contract field; not a claim of conformance with any operator, exchange or regulator rule set. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:50:31.894983+00:00.
Case digest / 868b2a2a1509e338c28027301a7f072ef5a15541d7c55f3ec5191b3a255f2800