FAILURE MAP
← Case archive

FA-61481 / Options payoff and settlement / Open access

Binary option settlement with an at-strike rule: option side is parsed from the wrong token · case 01

Every digital is treated as a put.

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

ROOT CAUSE

The call/put side is read from the first hyphen-separated token.

VERIFIED REPAIR

Read the side from the second token of the kind.

Unsuccessful approach: Searching for call only in the first four characters never matches.

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('-')[0] == '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 kind dispatch 1', ['cash-call', 105, 93, 10], 0], ['regression kind dispatch 2', ['asset-call', 105, 104.5, 10], 0.0], ['partial repair probe 1', ['asset-call', 95, 83, 100], 0], ['partial repair probe 2', ['asset-call', 105, 93, 1000], 0], ['boundary control 1', ['asset-put', 100, 90, 10], 90], ['boundary control 2', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100, 10], 50.0], ['normal control 2', ['cash-put', 100, 100, 100], 50.0]], [['regression kind dispatch 1', ['cash-call', 105, 112, 1000], 1000], ['regression kind dispatch 2', ['cash-call', 95, 95.5, 100], 100], ['partial repair probe 1', ['asset-call', 100, 88, 1000], 0], ['partial repair probe 2', ['asset-call', 105, 93, 100], 0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['cash-put', 105, 105, 10], 5.0], ['normal control 2', ['cash-put', 100, 99.5, 1000], 1000]], [['regression kind dispatch 1', ['cash-call', 95, 94.5, 100], 0], ['regression kind dispatch 2', ['asset-call', 95, 95.5, 1000], 95.5], ['partial repair probe 1', ['cash-call', 100, 100.5, 1000], 1000], ['partial repair probe 2', ['asset-call', 95, 102, 100], 102], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['cash-put', 95, 95.5, 100], 0], ['normal control 2', ['asset-call', 100, 100, 1000], 50.0]], [['regression kind dispatch 1', ['cash-call', 95, 95.5, 10], 10], ['regression kind dispatch 2', ['cash-call', 95, 95.5, 1000], 1000], ['partial repair probe 1', ['cash-call', 100, 107, 100], 100], ['partial repair probe 2', ['asset-call', 105, 93, 100], 0], ['boundary control 1', ['asset-put', 100, 90, 10], 90], ['boundary control 2', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-put', 100, 107, 100], 0], ['normal control 2', ['asset-put', 105, 93, 10], 93]], [['regression kind dispatch 1', ['asset-call', 105, 104.5, 100], 0.0], ['regression kind dispatch 2', ['asset-call', 100, 88, 1000], 0], ['partial repair probe 1', ['cash-call', 105, 104.5, 100], 0], ['partial repair probe 2', ['asset-call', 100, 100.5, 100], 100.5], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['asset-put', 100, 100, 100], 50.0], ['normal control 2', ['asset-call', 105, 105, 100], 52.5]]]
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 kind dispatch 1100Failed
regression kind dispatch 2104.50.0Failed
partial repair probe 1830Failed
partial repair probe 2930Failed
boundary control 19090Passed
boundary control 25.05.0Passed
normal control 150.050.0Passed
normal control 250.050.0Passed

SHA-256 / 1efc05fea24feb9155ac8489a4cfbb488e45de2face3b5cdb7c61753a030dbe4

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 'call' in kind[:4]:
        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 kind dispatch 1', ['cash-call', 105, 93, 10], 0], ['regression kind dispatch 2', ['asset-call', 105, 104.5, 10], 0.0], ['partial repair probe 1', ['asset-call', 95, 83, 100], 0], ['partial repair probe 2', ['asset-call', 105, 93, 1000], 0], ['boundary control 1', ['asset-put', 100, 90, 10], 90], ['boundary control 2', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100, 10], 50.0], ['normal control 2', ['cash-put', 100, 100, 100], 50.0]], [['regression kind dispatch 1', ['cash-call', 105, 112, 1000], 1000], ['regression kind dispatch 2', ['cash-call', 95, 95.5, 100], 100], ['partial repair probe 1', ['asset-call', 100, 88, 1000], 0], ['partial repair probe 2', ['asset-call', 105, 93, 100], 0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['cash-put', 105, 105, 10], 5.0], ['normal control 2', ['cash-put', 100, 99.5, 1000], 1000]], [['regression kind dispatch 1', ['cash-call', 95, 94.5, 100], 0], ['regression kind dispatch 2', ['asset-call', 95, 95.5, 1000], 95.5], ['partial repair probe 1', ['cash-call', 100, 100.5, 1000], 1000], ['partial repair probe 2', ['asset-call', 95, 102, 100], 102], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['cash-put', 95, 95.5, 100], 0], ['normal control 2', ['asset-call', 100, 100, 1000], 50.0]], [['regression kind dispatch 1', ['cash-call', 95, 95.5, 10], 10], ['regression kind dispatch 2', ['cash-call', 95, 95.5, 1000], 1000], ['partial repair probe 1', ['cash-call', 100, 107, 100], 100], ['partial repair probe 2', ['asset-call', 105, 93, 100], 0], ['boundary control 1', ['asset-put', 100, 90, 10], 90], ['boundary control 2', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-put', 100, 107, 100], 0], ['normal control 2', ['asset-put', 105, 93, 10], 93]], [['regression kind dispatch 1', ['asset-call', 105, 104.5, 100], 0.0], ['regression kind dispatch 2', ['asset-call', 100, 88, 1000], 0], ['partial repair probe 1', ['cash-call', 105, 104.5, 100], 0], ['partial repair probe 2', ['asset-call', 100, 100.5, 100], 100.5], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['asset-put', 100, 100, 100], 50.0], ['normal control 2', ['asset-call', 105, 105, 100], 52.5]]]
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 kind dispatch 1100Failed
regression kind dispatch 2104.50.0Failed
partial repair probe 1830Failed
partial repair probe 2930Failed
boundary control 19090Passed
boundary control 25.05.0Passed
normal control 150.050.0Passed
normal control 250.050.0Passed

SHA-256 / 1a8171707a7285df15fd648bb84b84348e1fbf6cebdc66d1000195ab25571b47

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 kind dispatch 1', ['cash-call', 105, 93, 10], 0], ['regression kind dispatch 2', ['asset-call', 105, 104.5, 10], 0.0], ['partial repair probe 1', ['asset-call', 95, 83, 100], 0], ['partial repair probe 2', ['asset-call', 105, 93, 1000], 0], ['boundary control 1', ['asset-put', 100, 90, 10], 90], ['boundary control 2', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['asset-call', 100, 100, 10], 50.0], ['normal control 2', ['cash-put', 100, 100, 100], 50.0]], [['regression kind dispatch 1', ['cash-call', 105, 112, 1000], 1000], ['regression kind dispatch 2', ['cash-call', 95, 95.5, 100], 100], ['partial repair probe 1', ['asset-call', 100, 88, 1000], 0], ['partial repair probe 2', ['asset-call', 105, 93, 100], 0], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['cash-put', 105, 105, 10], 5.0], ['normal control 2', ['cash-put', 100, 99.5, 1000], 1000]], [['regression kind dispatch 1', ['cash-call', 95, 94.5, 100], 0], ['regression kind dispatch 2', ['asset-call', 95, 95.5, 1000], 95.5], ['partial repair probe 1', ['cash-call', 100, 100.5, 1000], 1000], ['partial repair probe 2', ['asset-call', 95, 102, 100], 102], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['cash-put', 95, 95.5, 100], 0], ['normal control 2', ['asset-call', 100, 100, 1000], 50.0]], [['regression kind dispatch 1', ['cash-call', 95, 95.5, 10], 10], ['regression kind dispatch 2', ['cash-call', 95, 95.5, 1000], 1000], ['partial repair probe 1', ['cash-call', 100, 107, 100], 100], ['partial repair probe 2', ['asset-call', 105, 93, 100], 0], ['boundary control 1', ['asset-put', 100, 90, 10], 90], ['boundary control 2', ['cash-call', 100, 100, 10], 5.0], ['normal control 1', ['cash-put', 100, 107, 100], 0], ['normal control 2', ['asset-put', 105, 93, 10], 93]], [['regression kind dispatch 1', ['asset-call', 105, 104.5, 100], 0.0], ['regression kind dispatch 2', ['asset-call', 100, 88, 1000], 0], ['partial repair probe 1', ['cash-call', 105, 104.5, 100], 0], ['partial repair probe 2', ['asset-call', 100, 100.5, 100], 100.5], ['boundary control 1', ['cash-call', 100, 100, 10], 5.0], ['boundary control 2', ['asset-put', 100, 90, 10], 90], ['normal control 1', ['asset-put', 100, 100, 100], 50.0], ['normal control 2', ['asset-call', 105, 105, 100], 52.5]]]
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 kind dispatch 100Passed
regression kind dispatch 20.00.0Passed
partial repair probe 100Passed
partial repair probe 200Passed
boundary control 19090Passed
boundary control 25.05.0Passed
normal control 150.050.0Passed
normal control 250.050.0Passed

SHA-256 / 7f1a5c4425eab2172a3379310825312adc91ff97c514114c6e682881a35925a3

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

Case digest / 3251e4aaa453f09753e9e9268a681626a21276ecacf5b3c59fb341582dd2c886