FA-84556 / Betting odds conversion / Open access
Kelly computed with decimal odds instead of net odds · case 01
Stakes are sized far too large on every price.
ROOT CAUSE
b is taken as the decimal price rather than price - 1.
VERIFIED REPAIR
Use the net odds b = price - 1.
Unsuccessful approach: Using net odds in the numerator but the decimal price in the denominator still misstates the fraction.
Case contract
Kelly staking. With b = price - 1, p = prob and q = 1 - p, the full Kelly fraction is (b * p - q) / b, floored at 0 when the edge is not positive. The stake is bankroll * min(full Kelly * fraction, max_pct / 100), rounded down to a cent. Return [full Kelly fraction rounded half up to four decimals as a string, stake cents].
Why this case matters
Bankroll tools size stakes with fractional Kelly and a hard cap.
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(prob, price, fraction, bankroll_cents, max_pct):
p = Fraction(prob)
b = Fraction(price)
q = 1 - p
k = (b * p - q) / b
if k < 0:
k = Fraction(0)
use = min(k * Fraction(fraction), Fraction(max_pct) / 100)
stake = math.floor(bankroll_cents * use)
r = math.floor(k * 10000 + Fraction(1, 2))
return ['%d.%04d' % (r // 10000, r % 10000), stake]
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 even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.60', '3.27', '0.5', 50000, '10'), ['0.4238', 5000]),
('variant scenario 1', ('0.50', '1.73', '0.5', 100000, '5'), ['0.0000', 0]),
('variant scenario 2', ('0.60', '5.99', '1', 12345, '10'), ['0.5198', 1234])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.80', '4.16', '0.25', 50000, '2'), ['0.7367', 1000]),
('variant scenario 1', ('0.60', '3.64', '0.5', 12345, '5'), ['0.4485', 617]),
('variant scenario 2', ('0.60', '2.09', '1', 12345, '2'), ['0.2330', 246])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.60', '2.62', '0.25', 50000, '5'), ['0.3531', 2500]),
('variant scenario 1', ('0.60', '5.17', '0.25', 50000, '5'), ['0.5041', 2500]),
('variant scenario 2', ('0.57', '3.82', '0.5', 50000, '100'), ['0.4175', 10437])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.55', '1.34', '1', 100000, '10'), ['0.0000', 0]),
('regression: net odds', ('0.57', '2.09', '0.5', 100000, '10'), ['0.1755', 8775]),
('variant scenario 1', ('0.60', '2.15', '1', 12345, '100'), ['0.2522', 3113]),
('variant scenario 2', ('0.48', '3.64', '0.5', 50000, '2'), ['0.2830', 1000])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.55', '3.59', '0.25', 12345, '100'), ['0.3763', 1161]),
('variant scenario 1', ('0.60', '2.93', '0.25', 12345, '10'), ['0.3927', 1212]),
('variant scenario 2', ('0.78', '1.41', '0.25', 100000, '100'), ['0.2434', 6085])]]
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 even-money edge | ['0.3250', 32500] | ['0.1000', 10000] | Failed |
| control half kelly | ['0.3250', 16250] | ['0.1000', 5000] | Failed |
| boundary capped stake | ['0.4000', 5000] | ['0.2000', 5000] | Failed |
| boundary no edge | ['0.1000', 5000] | ['0.0000', 0] | Failed |
| control underdog edge | ['0.1250', 12500] | ['0.0667', 6666] | Failed |
| regression: net odds | ['0.4777', 5000] | ['0.4238', 5000] | Failed |
| variant scenario 1 | ['0.2110', 5000] | ['0.0000', 0] | Failed |
| variant scenario 2 | ['0.5332', 1234] | ['0.5198', 1234] | Failed |
SHA-256 / 149e954f772927e42934efcc85c1f85e6989903261d84d7b385e985616b983d8
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(prob, price, fraction, bankroll_cents, max_pct):
p = Fraction(prob)
b = Fraction(price) - 1
q = 1 - p
k = (b * p - q) / (b + 1)
if k < 0:
k = Fraction(0)
use = min(k * Fraction(fraction), Fraction(max_pct) / 100)
stake = math.floor(bankroll_cents * use)
r = math.floor(k * 10000 + Fraction(1, 2))
return ['%d.%04d' % (r // 10000, r % 10000), stake]
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 even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.60', '3.27', '0.5', 50000, '10'), ['0.4238', 5000]),
('variant scenario 1', ('0.50', '1.73', '0.5', 100000, '5'), ['0.0000', 0]),
('variant scenario 2', ('0.60', '5.99', '1', 12345, '10'), ['0.5198', 1234])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.80', '4.16', '0.25', 50000, '2'), ['0.7367', 1000]),
('variant scenario 1', ('0.60', '3.64', '0.5', 12345, '5'), ['0.4485', 617]),
('variant scenario 2', ('0.60', '2.09', '1', 12345, '2'), ['0.2330', 246])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.60', '2.62', '0.25', 50000, '5'), ['0.3531', 2500]),
('variant scenario 1', ('0.60', '5.17', '0.25', 50000, '5'), ['0.5041', 2500]),
('variant scenario 2', ('0.57', '3.82', '0.5', 50000, '100'), ['0.4175', 10437])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.55', '1.34', '1', 100000, '10'), ['0.0000', 0]),
('regression: net odds', ('0.57', '2.09', '0.5', 100000, '10'), ['0.1755', 8775]),
('variant scenario 1', ('0.60', '2.15', '1', 12345, '100'), ['0.2522', 3113]),
('variant scenario 2', ('0.48', '3.64', '0.5', 50000, '2'), ['0.2830', 1000])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.55', '3.59', '0.25', 12345, '100'), ['0.3763', 1161]),
('variant scenario 1', ('0.60', '2.93', '0.25', 12345, '10'), ['0.3927', 1212]),
('variant scenario 2', ('0.78', '1.41', '0.25', 100000, '100'), ['0.2434', 6085])]]
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 even-money edge | ['0.0500', 5000] | ['0.1000', 10000] | Failed |
| control half kelly | ['0.0500', 2500] | ['0.1000', 5000] | Failed |
| boundary capped stake | ['0.1000', 5000] | ['0.2000', 5000] | Failed |
| boundary no edge | ['0.0000', 0] | ['0.0000', 0] | Passed |
| control underdog edge | ['0.0500', 5000] | ['0.0667', 6666] | Failed |
| regression: net odds | ['0.2942', 5000] | ['0.4238', 5000] | Failed |
| variant scenario 1 | ['0.0000', 0] | ['0.0000', 0] | Passed |
| variant scenario 2 | ['0.4331', 1234] | ['0.5198', 1234] | Failed |
SHA-256 / f04de6a2d7fe538620b2987cbd4f6e52a3e7537923811dbe09ed0ea671bcc0b4
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(prob, price, fraction, bankroll_cents, max_pct):
p = Fraction(prob)
b = Fraction(price) - 1
q = 1 - p
k = (b * p - q) / b
if k < 0:
k = Fraction(0)
use = min(k * Fraction(fraction), Fraction(max_pct) / 100)
stake = math.floor(bankroll_cents * use)
r = math.floor(k * 10000 + Fraction(1, 2))
return ['%d.%04d' % (r // 10000, r % 10000), stake]
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 even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.60', '3.27', '0.5', 50000, '10'), ['0.4238', 5000]),
('variant scenario 1', ('0.50', '1.73', '0.5', 100000, '5'), ['0.0000', 0]),
('variant scenario 2', ('0.60', '5.99', '1', 12345, '10'), ['0.5198', 1234])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.80', '4.16', '0.25', 50000, '2'), ['0.7367', 1000]),
('variant scenario 1', ('0.60', '3.64', '0.5', 12345, '5'), ['0.4485', 617]),
('variant scenario 2', ('0.60', '2.09', '1', 12345, '2'), ['0.2330', 246])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.60', '2.62', '0.25', 50000, '5'), ['0.3531', 2500]),
('variant scenario 1', ('0.60', '5.17', '0.25', 50000, '5'), ['0.5041', 2500]),
('variant scenario 2', ('0.57', '3.82', '0.5', 50000, '100'), ['0.4175', 10437])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.55', '1.34', '1', 100000, '10'), ['0.0000', 0]),
('regression: net odds', ('0.57', '2.09', '0.5', 100000, '10'), ['0.1755', 8775]),
('variant scenario 1', ('0.60', '2.15', '1', 12345, '100'), ['0.2522', 3113]),
('variant scenario 2', ('0.48', '3.64', '0.5', 50000, '2'), ['0.2830', 1000])],
[('control even-money edge', ('0.55', '2.00', '1', 100000, '100'), ['0.1000', 10000]),
('control half kelly', ('0.55', '2.00', '0.5', 100000, '100'), ['0.1000', 5000]),
('boundary capped stake', ('0.60', '2.00', '1', 100000, '5'), ['0.2000', 5000]),
('boundary no edge', ('0.40', '2.00', '1', 100000, '5'), ['0.0000', 0]),
('control underdog edge', ('0.30', '4.00', '1', 100000, '100'), ['0.0667', 6666]),
('regression: net odds', ('0.55', '3.59', '0.25', 12345, '100'), ['0.3763', 1161]),
('variant scenario 1', ('0.60', '2.93', '0.25', 12345, '10'), ['0.3927', 1212]),
('variant scenario 2', ('0.78', '1.41', '0.25', 100000, '100'), ['0.2434', 6085])]]
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 even-money edge | ['0.1000', 10000] | ['0.1000', 10000] | Passed |
| control half kelly | ['0.1000', 5000] | ['0.1000', 5000] | Passed |
| boundary capped stake | ['0.2000', 5000] | ['0.2000', 5000] | Passed |
| boundary no edge | ['0.0000', 0] | ['0.0000', 0] | Passed |
| control underdog edge | ['0.0667', 6666] | ['0.0667', 6666] | Passed |
| regression: net odds | ['0.4238', 5000] | ['0.4238', 5000] | Passed |
| variant scenario 1 | ['0.0000', 0] | ['0.0000', 0] | Passed |
| variant scenario 2 | ['0.5198', 1234] | ['0.5198', 1234] | Passed |
SHA-256 / 4c27a2ab0929bf143234d6d88ca6e0a8f1037292da2b66d767c27b720c353a01
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.900680+00:00.
Case digest / e0e77f7abccd3e92f7afb723c7aec140b978fbd4bb9ae674d1f3d800378d4649