FAILURE MAP
← Case archive

FA-84421 / Betting odds conversion / Open access

Implied probabilities taken from display-rounded prices · case 01

Book totals drift because prices are rounded to one decimal before inverting.

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

ROOT CAUSE

Each price is rounded to one decimal place before computing implied probabilities.

VERIFIED REPAIR

Use the exact quoted prices.

Unsuccessful approach: Rounding to two decimals after parsing still perturbs three-decimal quotes.

Case contract

Market book analysis for decimal prices (strings, each > 1, else "invalid"). Implied probability is 1/d; book = sum of implied probabilities. Return [overround percent (book - 1) * 100, bookmaker margin percent (1 - 1/book) * 100, fair prices d * book for proportional margin removal], every number rounded half up to two decimals (negative values are rounded toward +infinity at the half) and formatted with two decimals.

Why this case matters

Trading tools report overround and margin separately and derive no-vig fair prices.

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(prices):
    def fmt(x):
        c = math.floor(x * 100 + Fraction(1, 2))
        sign = '-' if c < 0 else ''
        c = abs(c)
        return sign + '%d.%02d' % (c // 100, c % 100)
    ds = [round(Fraction(p), 1) for p in prices]
    if any(d <= 1 for d in ds):
        return 'invalid'
    book = sum(1 / d for d in ds)
    over = (book - 1) * 100
    margin = (1 - 1 / book) * 100
    fair = [fmt(d * book) for d in ds]
    return [fmt(over), fmt(margin), fair]
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 fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs',
   (['4.87', '6.63', '2.10', '4.53'],),
   ['5.31', '5.04', ['5.13', '6.98', '2.21', '4.77']]),
  ('variant scenario 1', (['1.63', '2.52'],), ['1.03', '1.02', ['1.65', '2.55']]),
  ('variant scenario 2', (['2.13', '2.50', '6.73'],), ['1.81', '1.78', ['2.17', '2.55', '6.85']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['2.66', '1.37'],), ['10.59', '9.57', ['2.94', '1.52']]),
  ('variant scenario 1',
   (['1.93', '3.15', '12.63', '7.24'],),
   ['5.29', '5.02', ['2.03', '3.32', '13.30', '7.62']]),
  ('variant scenario 2', (['2.67', '1.43'],), ['7.38', '6.88', ['2.87', '1.54']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['4.03', '1.36'],), ['-1.66', '-1.68', ['3.96', '1.34']]),
  ('variant scenario 1', (['0.90', '5.64', '2.67'],), 'invalid'),
  ('variant scenario 2',
   (['5.61', '2.31', '1.94'],),
   ['12.66', '11.24', ['6.32', '2.60', '2.19']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs',
   (['2.44', '3.46', '13.35', '2.95'],),
   ['11.27', '10.13', ['2.72', '3.85', '14.86', '3.28']]),
  ('variant scenario 1',
   (['13.41', '1.64', '2.16'],),
   ['14.73', '12.84', ['15.39', '1.88', '2.48']]),
  ('variant scenario 2',
   (['2.60', '4.98', '1.85'],),
   ['12.60', '11.19', ['2.93', '5.61', '2.08']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['1.58', '2.04'],), ['12.31', '10.96', ['1.77', '2.29']]),
  ('variant scenario 1', (['1.68', '3.49', '6.42'],), ['3.75', '3.62', ['1.74', '3.62', '6.66']]),
  ('variant scenario 2', (['2.08', '3.41', '4.19'],), ['1.27', '1.25', ['2.11', '3.45', '4.24']])]]
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 fair coin['0.00', '0.00', ['2.00', '2.00']]['0.00', '0.00', ['2.00', '2.00']]Passed
control standard juice['5.26', '5.00', ['2.00', '2.00']]['4.71', '4.50', ['2.00', '2.00']]Failed
boundary three-way['5.73', '5.42', ['2.64', '3.38', '3.07']]['5.73', '5.42', ['2.64', '3.38', '3.07']]Passed
boundary no-profit priceinvalidinvalidPassed
regression: display rounded inputs['5.40', '5.12', ['5.16', '6.96', '2.21', '4.74']]['5.31', '5.04', ['5.13', '6.98', '2.21', '4.77']]Failed
variant scenario 1['2.50', '2.44', ['1.64', '2.56']]['1.03', '1.02', ['1.65', '2.55']]Failed
variant scenario 2['2.54', '2.48', ['2.15', '2.56', '6.87']]['1.81', '1.78', ['2.17', '2.55', '6.85']]Failed

SHA-256 / e2f3c867ae936da7329034a7fc12077aff09a8734d15b1eab79d696480553722

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(prices):
    def fmt(x):
        c = math.floor(x * 100 + Fraction(1, 2))
        sign = '-' if c < 0 else ''
        c = abs(c)
        return sign + '%d.%02d' % (c // 100, c % 100)
    ds = [Fraction(p).limit_denominator(20) for p in prices]
    if any(d <= 1 for d in ds):
        return 'invalid'
    book = sum(1 / d for d in ds)
    over = (book - 1) * 100
    margin = (1 - 1 / book) * 100
    fair = [fmt(d * book) for d in ds]
    return [fmt(over), fmt(margin), fair]
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 fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs',
   (['4.87', '6.63', '2.10', '4.53'],),
   ['5.31', '5.04', ['5.13', '6.98', '2.21', '4.77']]),
  ('variant scenario 1', (['1.63', '2.52'],), ['1.03', '1.02', ['1.65', '2.55']]),
  ('variant scenario 2', (['2.13', '2.50', '6.73'],), ['1.81', '1.78', ['2.17', '2.55', '6.85']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['2.66', '1.37'],), ['10.59', '9.57', ['2.94', '1.52']]),
  ('variant scenario 1',
   (['1.93', '3.15', '12.63', '7.24'],),
   ['5.29', '5.02', ['2.03', '3.32', '13.30', '7.62']]),
  ('variant scenario 2', (['2.67', '1.43'],), ['7.38', '6.88', ['2.87', '1.54']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['4.03', '1.36'],), ['-1.66', '-1.68', ['3.96', '1.34']]),
  ('variant scenario 1', (['0.90', '5.64', '2.67'],), 'invalid'),
  ('variant scenario 2',
   (['5.61', '2.31', '1.94'],),
   ['12.66', '11.24', ['6.32', '2.60', '2.19']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs',
   (['2.44', '3.46', '13.35', '2.95'],),
   ['11.27', '10.13', ['2.72', '3.85', '14.86', '3.28']]),
  ('variant scenario 1',
   (['13.41', '1.64', '2.16'],),
   ['14.73', '12.84', ['15.39', '1.88', '2.48']]),
  ('variant scenario 2',
   (['2.60', '4.98', '1.85'],),
   ['12.60', '11.19', ['2.93', '5.61', '2.08']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['1.58', '2.04'],), ['12.31', '10.96', ['1.77', '2.29']]),
  ('variant scenario 1', (['1.68', '3.49', '6.42'],), ['3.75', '3.62', ['1.74', '3.62', '6.66']]),
  ('variant scenario 2', (['2.08', '3.41', '4.19'],), ['1.27', '1.25', ['2.11', '3.45', '4.24']])]]
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 fair coin['0.00', '0.00', ['2.00', '2.00']]['0.00', '0.00', ['2.00', '2.00']]Passed
control standard juice['4.76', '4.55', ['2.00', '2.00']]['4.71', '4.50', ['2.00', '2.00']]Failed
boundary three-way['5.73', '5.42', ['2.64', '3.38', '3.07']]['5.73', '5.42', ['2.64', '3.38', '3.07']]Passed
boundary no-profit priceinvalidinvalidPassed
regression: display rounded inputs['5.32', '5.06', ['5.13', '6.98', '2.21', '4.77']]['5.31', '5.04', ['5.13', '6.98', '2.21', '4.77']]Failed
variant scenario 1['0.87', '0.87', ['1.65', '2.55']]['1.03', '1.02', ['1.65', '2.55']]Failed
variant scenario 2['1.74', '1.71', ['2.17', '2.54', '6.84']]['1.81', '1.78', ['2.17', '2.55', '6.85']]Failed

SHA-256 / bdf8667eb1db795ed7811a7752d2ab1147bc59135973fce757f83efd20aab49d

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(prices):
    def fmt(x):
        c = math.floor(x * 100 + Fraction(1, 2))
        sign = '-' if c < 0 else ''
        c = abs(c)
        return sign + '%d.%02d' % (c // 100, c % 100)
    ds = [Fraction(p) for p in prices]
    if any(d <= 1 for d in ds):
        return 'invalid'
    book = sum(1 / d for d in ds)
    over = (book - 1) * 100
    margin = (1 - 1 / book) * 100
    fair = [fmt(d * book) for d in ds]
    return [fmt(over), fmt(margin), fair]
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 fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs',
   (['4.87', '6.63', '2.10', '4.53'],),
   ['5.31', '5.04', ['5.13', '6.98', '2.21', '4.77']]),
  ('variant scenario 1', (['1.63', '2.52'],), ['1.03', '1.02', ['1.65', '2.55']]),
  ('variant scenario 2', (['2.13', '2.50', '6.73'],), ['1.81', '1.78', ['2.17', '2.55', '6.85']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['2.66', '1.37'],), ['10.59', '9.57', ['2.94', '1.52']]),
  ('variant scenario 1',
   (['1.93', '3.15', '12.63', '7.24'],),
   ['5.29', '5.02', ['2.03', '3.32', '13.30', '7.62']]),
  ('variant scenario 2', (['2.67', '1.43'],), ['7.38', '6.88', ['2.87', '1.54']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['4.03', '1.36'],), ['-1.66', '-1.68', ['3.96', '1.34']]),
  ('variant scenario 1', (['0.90', '5.64', '2.67'],), 'invalid'),
  ('variant scenario 2',
   (['5.61', '2.31', '1.94'],),
   ['12.66', '11.24', ['6.32', '2.60', '2.19']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs',
   (['2.44', '3.46', '13.35', '2.95'],),
   ['11.27', '10.13', ['2.72', '3.85', '14.86', '3.28']]),
  ('variant scenario 1',
   (['13.41', '1.64', '2.16'],),
   ['14.73', '12.84', ['15.39', '1.88', '2.48']]),
  ('variant scenario 2',
   (['2.60', '4.98', '1.85'],),
   ['12.60', '11.19', ['2.93', '5.61', '2.08']])],
 [('control fair coin', (['2.00', '2.00'],), ['0.00', '0.00', ['2.00', '2.00']]),
  ('control standard juice', (['1.91', '1.91'],), ['4.71', '4.50', ['2.00', '2.00']]),
  ('boundary three-way', (['2.50', '3.20', '2.90'],), ['5.73', '5.42', ['2.64', '3.38', '3.07']]),
  ('boundary no-profit price', (['1.00', '5.00'],), 'invalid'),
  ('regression: display rounded inputs', (['1.58', '2.04'],), ['12.31', '10.96', ['1.77', '2.29']]),
  ('variant scenario 1', (['1.68', '3.49', '6.42'],), ['3.75', '3.62', ['1.74', '3.62', '6.66']]),
  ('variant scenario 2', (['2.08', '3.41', '4.19'],), ['1.27', '1.25', ['2.11', '3.45', '4.24']])]]
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 fair coin['0.00', '0.00', ['2.00', '2.00']]['0.00', '0.00', ['2.00', '2.00']]Passed
control standard juice['4.71', '4.50', ['2.00', '2.00']]['4.71', '4.50', ['2.00', '2.00']]Passed
boundary three-way['5.73', '5.42', ['2.64', '3.38', '3.07']]['5.73', '5.42', ['2.64', '3.38', '3.07']]Passed
boundary no-profit priceinvalidinvalidPassed
regression: display rounded inputs['5.31', '5.04', ['5.13', '6.98', '2.21', '4.77']]['5.31', '5.04', ['5.13', '6.98', '2.21', '4.77']]Passed
variant scenario 1['1.03', '1.02', ['1.65', '2.55']]['1.03', '1.02', ['1.65', '2.55']]Passed
variant scenario 2['1.81', '1.78', ['2.17', '2.55', '6.85']]['1.81', '1.78', ['2.17', '2.55', '6.85']]Passed

SHA-256 / 1f2cd808afc2929882b80853d36490227510494fe6600b7b31a6f0dd7af1929c

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:30.632637+00:00.

Case digest / 98533feb0548c6c91e1fe814f75a503bad1994e9fea4de5ad86337d401a8df22