FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 priceinvalidinvalidPassed
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 fixtureActualExpectedOutcome
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 priceinvalidinvalidPassed
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 fixtureActualExpectedOutcome
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 priceinvalidinvalidPassed
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