FAILURE MAP
← Case archive

FA-61471 / Options payoff and settlement / Open access

Binary option settlement with an at-strike rule: puts are in the money above the strike · case 01

Digital puts pay when the underlying rises.

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

ROOT CAUSE

The put branch reuses the call comparison.

VERIFIED REPAIR

Puts are in the money when final < strike.

Unsuccessful approach: Flipping the comparison but dropping the half-payment case still fails at the strike.

Case contract

Inputs kind (cash-call, cash-put, asset-call, asset-put), strike, final price and cash amount. Calls are in the money when final > strike, puts when final < strike; at final == strike both pay half. Cash-or-nothing pays the cash amount, asset-or-nothing pays the final price, times the state (1, 0.5 or 0). Round to 6.

Why this case matters

Option expiry, exercise and settlement engines move cash and shares; a wrong branch misstates obligations.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(kind, strike, final, cash_amount):
    if kind.split('-')[1] == 'call':
        state = 1 if final > strike else (0.5 if final == strike else 0)
    else:
        state = 1 if final > strike else (0.5 if final == strike else 0)
    unit = cash_amount if kind.startswith('cash') else final
    return round(unit * state, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression put moneyness 1', ['cash-put', 105, 104.5, 10], 10], ['regression put moneyness 2', ['cash-put', 100, 100.5, 100], 0], ['partial repair probe 1', ['cash-put', 95, 95, 1000], 500.0], ['partial repair probe 2', ['cash-put', 95, 95, 10], 5.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100.5, 10], 100.5], ['normal control 2', ['asset-call', 100, 99.5, 1000], 0.0], ['normal control 3', ['cash-call', 105, 105, 1000], 500.0]], [['regression put moneyness 1', ['asset-put', 95, 95.5, 10], 0.0], ['regression put moneyness 2', ['asset-put', 105, 104.5, 10], 104.5], ['partial repair probe 1', ['asset-put', 100, 100, 1000], 50.0], ['partial repair probe 2', ['asset-put', 100, 100, 100], 50.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 95, 95.5, 1000], 1000], ['normal control 2', ['cash-call', 100, 88, 1000], 0], ['normal control 3', ['asset-call', 105, 105.5, 10], 105.5]], [['regression put moneyness 1', ['asset-put', 100, 100.5, 1000], 0.0], ['regression put moneyness 2', ['asset-put', 95, 94.5, 100], 94.5], ['partial repair probe 1', ['cash-put', 100, 100, 1000], 500.0], ['partial repair probe 2', ['cash-put', 95, 95, 100], 50.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100.5, 1000], 100.5], ['normal control 2', ['asset-call', 105, 104.5, 100], 0.0], ['normal control 3', ['asset-call', 100, 100, 10], 50.0]], [['regression put moneyness 1', ['asset-put', 100, 107, 1000], 0], ['regression put moneyness 2', ['asset-put', 95, 102, 10], 0], ['partial repair probe 1', ['cash-put', 105, 105, 1000], 500.0], ['partial repair probe 2', ['asset-put', 95, 95, 100], 47.5], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 105, 93, 100], 0], ['normal control 2', ['cash-call', 100, 88, 10], 0], ['normal control 3', ['cash-call', 100, 107, 1000], 1000]], [['regression put moneyness 1', ['asset-put', 100, 100.5, 100], 0.0], ['regression put moneyness 2', ['cash-put', 105, 112, 100], 0], ['partial repair probe 1', ['asset-put', 100, 100, 10], 50.0], ['partial repair probe 2', ['cash-put', 105, 105, 10], 5.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 105, 105, 1000], 500.0], ['normal control 2', ['cash-call', 100, 99.5, 10], 0], ['normal control 3', ['asset-call', 105, 93, 1000], 0]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*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
regression put moneyness 1010Failed
regression put moneyness 21000Failed
partial repair probe 1500.0500.0Passed
partial repair probe 25.05.0Passed
boundary control 15.05.0Passed
normal control 1100.5100.5Passed
normal control 20.00.0Passed
normal control 3500.0500.0Passed

SHA-256 / 8068db6c351668f33d9a9d07a50a3ffb035f0a2b6ad668e8e912f23a1b4412ea

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(kind, strike, final, cash_amount):
    if kind.split('-')[1] == 'call':
        state = 1 if final > strike else (0.5 if final == strike else 0)
    else:
        state = 1 if final < strike else 0
    unit = cash_amount if kind.startswith('cash') else final
    return round(unit * state, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression put moneyness 1', ['cash-put', 105, 104.5, 10], 10], ['regression put moneyness 2', ['cash-put', 100, 100.5, 100], 0], ['partial repair probe 1', ['cash-put', 95, 95, 1000], 500.0], ['partial repair probe 2', ['cash-put', 95, 95, 10], 5.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100.5, 10], 100.5], ['normal control 2', ['asset-call', 100, 99.5, 1000], 0.0], ['normal control 3', ['cash-call', 105, 105, 1000], 500.0]], [['regression put moneyness 1', ['asset-put', 95, 95.5, 10], 0.0], ['regression put moneyness 2', ['asset-put', 105, 104.5, 10], 104.5], ['partial repair probe 1', ['asset-put', 100, 100, 1000], 50.0], ['partial repair probe 2', ['asset-put', 100, 100, 100], 50.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 95, 95.5, 1000], 1000], ['normal control 2', ['cash-call', 100, 88, 1000], 0], ['normal control 3', ['asset-call', 105, 105.5, 10], 105.5]], [['regression put moneyness 1', ['asset-put', 100, 100.5, 1000], 0.0], ['regression put moneyness 2', ['asset-put', 95, 94.5, 100], 94.5], ['partial repair probe 1', ['cash-put', 100, 100, 1000], 500.0], ['partial repair probe 2', ['cash-put', 95, 95, 100], 50.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100.5, 1000], 100.5], ['normal control 2', ['asset-call', 105, 104.5, 100], 0.0], ['normal control 3', ['asset-call', 100, 100, 10], 50.0]], [['regression put moneyness 1', ['asset-put', 100, 107, 1000], 0], ['regression put moneyness 2', ['asset-put', 95, 102, 10], 0], ['partial repair probe 1', ['cash-put', 105, 105, 1000], 500.0], ['partial repair probe 2', ['asset-put', 95, 95, 100], 47.5], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 105, 93, 100], 0], ['normal control 2', ['cash-call', 100, 88, 10], 0], ['normal control 3', ['cash-call', 100, 107, 1000], 1000]], [['regression put moneyness 1', ['asset-put', 100, 100.5, 100], 0.0], ['regression put moneyness 2', ['cash-put', 105, 112, 100], 0], ['partial repair probe 1', ['asset-put', 100, 100, 10], 50.0], ['partial repair probe 2', ['cash-put', 105, 105, 10], 5.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 105, 105, 1000], 500.0], ['normal control 2', ['cash-call', 100, 99.5, 10], 0], ['normal control 3', ['asset-call', 105, 93, 1000], 0]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*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
regression put moneyness 11010Passed
regression put moneyness 200Passed
partial repair probe 10500.0Failed
partial repair probe 205.0Failed
boundary control 15.05.0Passed
normal control 1100.5100.5Passed
normal control 20.00.0Passed
normal control 3500.0500.0Passed

SHA-256 / 0c87146c9ef2540d0f685447b7024045bb96ce0f7a7969b5a7df23b5830d6042

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(kind, strike, final, cash_amount):
    if kind.split('-')[1] == 'call':
        state = 1 if final > strike else (0.5 if final == strike else 0)
    else:
        state = 1 if final < strike else (0.5 if final == strike else 0)
    unit = cash_amount if kind.startswith('cash') else final
    return round(unit * state, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression put moneyness 1', ['cash-put', 105, 104.5, 10], 10], ['regression put moneyness 2', ['cash-put', 100, 100.5, 100], 0], ['partial repair probe 1', ['cash-put', 95, 95, 1000], 500.0], ['partial repair probe 2', ['cash-put', 95, 95, 10], 5.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100.5, 10], 100.5], ['normal control 2', ['asset-call', 100, 99.5, 1000], 0.0], ['normal control 3', ['cash-call', 105, 105, 1000], 500.0]], [['regression put moneyness 1', ['asset-put', 95, 95.5, 10], 0.0], ['regression put moneyness 2', ['asset-put', 105, 104.5, 10], 104.5], ['partial repair probe 1', ['asset-put', 100, 100, 1000], 50.0], ['partial repair probe 2', ['asset-put', 100, 100, 100], 50.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 95, 95.5, 1000], 1000], ['normal control 2', ['cash-call', 100, 88, 1000], 0], ['normal control 3', ['asset-call', 105, 105.5, 10], 105.5]], [['regression put moneyness 1', ['asset-put', 100, 100.5, 1000], 0.0], ['regression put moneyness 2', ['asset-put', 95, 94.5, 100], 94.5], ['partial repair probe 1', ['cash-put', 100, 100, 1000], 500.0], ['partial repair probe 2', ['cash-put', 95, 95, 100], 50.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100.5, 1000], 100.5], ['normal control 2', ['asset-call', 105, 104.5, 100], 0.0], ['normal control 3', ['asset-call', 100, 100, 10], 50.0]], [['regression put moneyness 1', ['asset-put', 100, 107, 1000], 0], ['regression put moneyness 2', ['asset-put', 95, 102, 10], 0], ['partial repair probe 1', ['cash-put', 105, 105, 1000], 500.0], ['partial repair probe 2', ['asset-put', 95, 95, 100], 47.5], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 105, 93, 100], 0], ['normal control 2', ['cash-call', 100, 88, 10], 0], ['normal control 3', ['cash-call', 100, 107, 1000], 1000]], [['regression put moneyness 1', ['asset-put', 100, 100.5, 100], 0.0], ['regression put moneyness 2', ['cash-put', 105, 112, 100], 0], ['partial repair probe 1', ['asset-put', 100, 100, 10], 50.0], ['partial repair probe 2', ['cash-put', 105, 105, 10], 5.0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-call', 105, 105, 1000], 500.0], ['normal control 2', ['cash-call', 100, 99.5, 10], 0], ['normal control 3', ['asset-call', 105, 93, 1000], 0]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*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
regression put moneyness 11010Passed
regression put moneyness 200Passed
partial repair probe 1500.0500.0Passed
partial repair probe 25.05.0Passed
boundary control 15.05.0Passed
normal control 1100.5100.5Passed
normal control 20.00.0Passed
normal control 3500.0500.0Passed

SHA-256 / dbcc59b69990c007ac41162bbe7bc693d2edc1d5ddabc9bedd2d3dc48fcd2de2

Verification & scope

A deterministic toy contract stated explicitly in the contract field; no claim of conformance to any exchange or clearing rulebook. 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:46:55.493581+00:00.

Case digest / b4bc40ea1745571d4a7a230ef07c955a0ca077e6f7efcc09044a6f6d1e50e510