FAILURE MAP
← Case archive

FA-61751 / Options payoff and settlement / Open access

Delta hedge order sized in lots: put deltas are treated as positive · case 01

Put positions are hedged in the wrong direction.

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

ROOT CAUSE

The sign for puts is not applied to the absolute delta.

VERIFIED REPAIR

Negate delta for puts.

Unsuccessful approach: Negating only long puts leaves short puts wrong.

Case contract

Inputs positions [kind, signed contracts, absolute delta], multiplier, lot size and existing shares. Put delta is negative. Exposure = sum(sign*delta*contracts*multiplier); target shares = -exposure; the order is target - existing, rounded to whole lots with halves away from zero. Return the signed share quantity.

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
import math
from fractions import Fraction
N = 1
observations = []
def solve(positions, multiplier, lot, existing):
    exposure = Fraction(0)
    for kind, c, d in positions:
        sgn = 1
        exposure += sgn * Fraction(str(d)) * c * multiplier
    target = -exposure
    trade = target - existing
    lots = trade / lot
    n = math.floor(abs(lots) + Fraction(1, 2))
    return int((n if lots >= 0 else -n) * lot)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression put delta sign 1', [[['P', -1, 0.25], ['P', 5, 0.75], ['C', 1, 0.05]], 100, 100, 0], 300], ['regression put delta sign 2', [[['P', -1, 0.6], ['C', 5, 0.6], ['C', -3, 0.75]], 100, 25, 50], -175], ['partial repair probe 1', [[['P', 2, 0.75], ['C', -1, 0.05], ['P', -3, 0.5], ['P', 2, 0.75]], 10, 50, 0], 0], ['partial repair probe 2', [[['C', 5, 0.5], ['P', 2, 0.5], ['P', -3, 0.6]], 10, 100, 50], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 5, 0.05], ['P', 5, 0.35], ['P', 1, 0.5], ['C', 1, 0.05]], 10, 100, 0], 0], ['normal control 2', [[['C', 2, 0.6], ['C', 1, 0.05]], 10, 25, -250], 250], ['normal control 3', [[['P', -1, 0.75], ['C', -3, 0.25]], 10, 50, 100], -100]], [['regression put delta sign 1', [[['P', 2, 0.25], ['C', -3, 0.6]], 100, 50, 50], 200], ['regression put delta sign 2', [[['C', 1, 0.35], ['P', -3, 0.6]], 100, 25, 75], -300], ['partial repair probe 1', [[['P', 2, 0.5], ['P', -1, 0.35]], 10, 25, 0], 0], ['partial repair probe 2', [[['P', 2, 0.25], ['P', -1, 0.5], ['C', 5, 0.25], ['C', 5, 0.35]], 10, 50, -250], 200], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', -3, 0.6], ['C', -3, 0.6]], 10, 100, 100], -100], ['normal control 2', [[['P', -3, 0.05], ['P', 1, 0.25], ['C', 10, 0.6]], 100, 100, 100], -700], ['normal control 3', [[['C', -3, 0.35]], 100, 50, 50], 50]], [['regression put delta sign 1', [[['P', -1, 0.35], ['C', 2, 0.25]], 100, 25, 100], -175], ['regression put delta sign 2', [[['P', 10, 0.35]], 100, 50, 100], 250], ['partial repair probe 1', [[['P', 10, 0.25], ['C', 10, 0.75], ['C', 5, 0.5], ['P', -3, 0.75]], 10, 50, 50], -150], ['partial repair probe 2', [[['P', -1, 0.5], ['P', 2, 0.6]], 10, 25, 0], 0], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 1, 0.35]], 10, 100, 0], 0], ['normal control 2', [[['C', 2, 0.5]], 10, 25, -250], 250], ['normal control 3', [[['C', 5, 0.35], ['C', 1, 0.75]], 10, 50, -250], 250]], [['regression put delta sign 1', [[['P', 5, 0.35], ['P', 10, 0.35]], 10, 50, 0], 50], ['regression put delta sign 2', [[['C', -1, 0.6], ['P', 5, 0.05]], 100, 100, 0], 100], ['partial repair probe 1', [[['P', -1, 0.05], ['P', -1, 0.6], ['P', 10, 0.05]], 100, 50, 0], 0], ['partial repair probe 2', [[['P', -3, 0.25], ['P', 2, 0.5], ['C', 5, 0.35]], 10, 25, 75], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['P', 1, 0.6], ['P', -1, 0.5], ['C', 2, 0.35], ['C', 5, 0.25]], 10, 100, 50], -100], ['normal control 2', [[['P', 5, 0.35], ['C', -1, 0.05]], 10, 100, 100], -100], ['normal control 3', [[['P', -1, 0.75], ['C', 5, 0.6], ['C', 10, 0.35], ['P', -3, 0.05]], 10, 50, 0], -50]], [['regression put delta sign 1', [[['P', 10, 0.75], ['P', -1, 0.35], ['P', 5, 0.75], ['P', 5, 0.6]], 100, 25, 0], 1400], ['regression put delta sign 2', [[['C', -1, 0.5], ['P', -1, 0.35], ['C', 1, 0.25], ['P', 10, 0.5]], 100, 50, 0], 500], ['partial repair probe 1', [[['P', -3, 0.05], ['P', 10, 0.05]], 100, 100, 0], 0], ['partial repair probe 2', [[['P', 1, 0.05], ['C', 1, 0.5], ['P', -3, 0.6], ['P', 5, 0.25]], 10, 50, 75], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 1, 0.25]], 10, 50, 50], -50], ['normal control 2', [[['C', -1, 0.75]], 100, 25, 75], 0], ['normal control 3', [[['P', 2, 0.35], ['P', -1, 0.05]], 10, 100, 100], -100]]]
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 delta sign 1-400300Failed
regression put delta sign 2-75-175Failed
partial repair probe 100Passed
partial repair probe 2-100-100Passed
boundary control 1-100-100Passed
normal control 100Passed
normal control 2250250Passed
normal control 3-100-100Passed

SHA-256 / 9e737992701212433b49336c8bb9056ba93de85d27645e27a050801aee8f2345

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(positions, multiplier, lot, existing):
    exposure = Fraction(0)
    for kind, c, d in positions:
        sgn = -1 if kind == 'P' and c > 0 else 1
        exposure += sgn * Fraction(str(d)) * c * multiplier
    target = -exposure
    trade = target - existing
    lots = trade / lot
    n = math.floor(abs(lots) + Fraction(1, 2))
    return int((n if lots >= 0 else -n) * lot)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression put delta sign 1', [[['P', -1, 0.25], ['P', 5, 0.75], ['C', 1, 0.05]], 100, 100, 0], 300], ['regression put delta sign 2', [[['P', -1, 0.6], ['C', 5, 0.6], ['C', -3, 0.75]], 100, 25, 50], -175], ['partial repair probe 1', [[['P', 2, 0.75], ['C', -1, 0.05], ['P', -3, 0.5], ['P', 2, 0.75]], 10, 50, 0], 0], ['partial repair probe 2', [[['C', 5, 0.5], ['P', 2, 0.5], ['P', -3, 0.6]], 10, 100, 50], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 5, 0.05], ['P', 5, 0.35], ['P', 1, 0.5], ['C', 1, 0.05]], 10, 100, 0], 0], ['normal control 2', [[['C', 2, 0.6], ['C', 1, 0.05]], 10, 25, -250], 250], ['normal control 3', [[['P', -1, 0.75], ['C', -3, 0.25]], 10, 50, 100], -100]], [['regression put delta sign 1', [[['P', 2, 0.25], ['C', -3, 0.6]], 100, 50, 50], 200], ['regression put delta sign 2', [[['C', 1, 0.35], ['P', -3, 0.6]], 100, 25, 75], -300], ['partial repair probe 1', [[['P', 2, 0.5], ['P', -1, 0.35]], 10, 25, 0], 0], ['partial repair probe 2', [[['P', 2, 0.25], ['P', -1, 0.5], ['C', 5, 0.25], ['C', 5, 0.35]], 10, 50, -250], 200], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', -3, 0.6], ['C', -3, 0.6]], 10, 100, 100], -100], ['normal control 2', [[['P', -3, 0.05], ['P', 1, 0.25], ['C', 10, 0.6]], 100, 100, 100], -700], ['normal control 3', [[['C', -3, 0.35]], 100, 50, 50], 50]], [['regression put delta sign 1', [[['P', -1, 0.35], ['C', 2, 0.25]], 100, 25, 100], -175], ['regression put delta sign 2', [[['P', 10, 0.35]], 100, 50, 100], 250], ['partial repair probe 1', [[['P', 10, 0.25], ['C', 10, 0.75], ['C', 5, 0.5], ['P', -3, 0.75]], 10, 50, 50], -150], ['partial repair probe 2', [[['P', -1, 0.5], ['P', 2, 0.6]], 10, 25, 0], 0], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 1, 0.35]], 10, 100, 0], 0], ['normal control 2', [[['C', 2, 0.5]], 10, 25, -250], 250], ['normal control 3', [[['C', 5, 0.35], ['C', 1, 0.75]], 10, 50, -250], 250]], [['regression put delta sign 1', [[['P', 5, 0.35], ['P', 10, 0.35]], 10, 50, 0], 50], ['regression put delta sign 2', [[['C', -1, 0.6], ['P', 5, 0.05]], 100, 100, 0], 100], ['partial repair probe 1', [[['P', -1, 0.05], ['P', -1, 0.6], ['P', 10, 0.05]], 100, 50, 0], 0], ['partial repair probe 2', [[['P', -3, 0.25], ['P', 2, 0.5], ['C', 5, 0.35]], 10, 25, 75], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['P', 1, 0.6], ['P', -1, 0.5], ['C', 2, 0.35], ['C', 5, 0.25]], 10, 100, 50], -100], ['normal control 2', [[['P', 5, 0.35], ['C', -1, 0.05]], 10, 100, 100], -100], ['normal control 3', [[['P', -1, 0.75], ['C', 5, 0.6], ['C', 10, 0.35], ['P', -3, 0.05]], 10, 50, 0], -50]], [['regression put delta sign 1', [[['P', 10, 0.75], ['P', -1, 0.35], ['P', 5, 0.75], ['P', 5, 0.6]], 100, 25, 0], 1400], ['regression put delta sign 2', [[['C', -1, 0.5], ['P', -1, 0.35], ['C', 1, 0.25], ['P', 10, 0.5]], 100, 50, 0], 500], ['partial repair probe 1', [[['P', -3, 0.05], ['P', 10, 0.05]], 100, 100, 0], 0], ['partial repair probe 2', [[['P', 1, 0.05], ['C', 1, 0.5], ['P', -3, 0.6], ['P', 5, 0.25]], 10, 50, 75], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 1, 0.25]], 10, 50, 50], -50], ['normal control 2', [[['C', -1, 0.75]], 100, 25, 75], 0], ['normal control 3', [[['P', 2, 0.35], ['P', -1, 0.05]], 10, 100, 100], -100]]]
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 delta sign 1400300Failed
regression put delta sign 2-75-175Failed
partial repair probe 1500Failed
partial repair probe 20-100Failed
boundary control 1-100-100Passed
normal control 100Passed
normal control 2250250Passed
normal control 3-100-100Passed

SHA-256 / 1e154b7cb46d31818dae4b35ad2b07d0a50c7c8c79b39e94cb0c95af80fed0aa

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(positions, multiplier, lot, existing):
    exposure = Fraction(0)
    for kind, c, d in positions:
        sgn = -1 if kind == 'P' else 1
        exposure += sgn * Fraction(str(d)) * c * multiplier
    target = -exposure
    trade = target - existing
    lots = trade / lot
    n = math.floor(abs(lots) + Fraction(1, 2))
    return int((n if lots >= 0 else -n) * lot)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression put delta sign 1', [[['P', -1, 0.25], ['P', 5, 0.75], ['C', 1, 0.05]], 100, 100, 0], 300], ['regression put delta sign 2', [[['P', -1, 0.6], ['C', 5, 0.6], ['C', -3, 0.75]], 100, 25, 50], -175], ['partial repair probe 1', [[['P', 2, 0.75], ['C', -1, 0.05], ['P', -3, 0.5], ['P', 2, 0.75]], 10, 50, 0], 0], ['partial repair probe 2', [[['C', 5, 0.5], ['P', 2, 0.5], ['P', -3, 0.6]], 10, 100, 50], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 5, 0.05], ['P', 5, 0.35], ['P', 1, 0.5], ['C', 1, 0.05]], 10, 100, 0], 0], ['normal control 2', [[['C', 2, 0.6], ['C', 1, 0.05]], 10, 25, -250], 250], ['normal control 3', [[['P', -1, 0.75], ['C', -3, 0.25]], 10, 50, 100], -100]], [['regression put delta sign 1', [[['P', 2, 0.25], ['C', -3, 0.6]], 100, 50, 50], 200], ['regression put delta sign 2', [[['C', 1, 0.35], ['P', -3, 0.6]], 100, 25, 75], -300], ['partial repair probe 1', [[['P', 2, 0.5], ['P', -1, 0.35]], 10, 25, 0], 0], ['partial repair probe 2', [[['P', 2, 0.25], ['P', -1, 0.5], ['C', 5, 0.25], ['C', 5, 0.35]], 10, 50, -250], 200], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', -3, 0.6], ['C', -3, 0.6]], 10, 100, 100], -100], ['normal control 2', [[['P', -3, 0.05], ['P', 1, 0.25], ['C', 10, 0.6]], 100, 100, 100], -700], ['normal control 3', [[['C', -3, 0.35]], 100, 50, 50], 50]], [['regression put delta sign 1', [[['P', -1, 0.35], ['C', 2, 0.25]], 100, 25, 100], -175], ['regression put delta sign 2', [[['P', 10, 0.35]], 100, 50, 100], 250], ['partial repair probe 1', [[['P', 10, 0.25], ['C', 10, 0.75], ['C', 5, 0.5], ['P', -3, 0.75]], 10, 50, 50], -150], ['partial repair probe 2', [[['P', -1, 0.5], ['P', 2, 0.6]], 10, 25, 0], 0], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 1, 0.35]], 10, 100, 0], 0], ['normal control 2', [[['C', 2, 0.5]], 10, 25, -250], 250], ['normal control 3', [[['C', 5, 0.35], ['C', 1, 0.75]], 10, 50, -250], 250]], [['regression put delta sign 1', [[['P', 5, 0.35], ['P', 10, 0.35]], 10, 50, 0], 50], ['regression put delta sign 2', [[['C', -1, 0.6], ['P', 5, 0.05]], 100, 100, 0], 100], ['partial repair probe 1', [[['P', -1, 0.05], ['P', -1, 0.6], ['P', 10, 0.05]], 100, 50, 0], 0], ['partial repair probe 2', [[['P', -3, 0.25], ['P', 2, 0.5], ['C', 5, 0.35]], 10, 25, 75], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['P', 1, 0.6], ['P', -1, 0.5], ['C', 2, 0.35], ['C', 5, 0.25]], 10, 100, 50], -100], ['normal control 2', [[['P', 5, 0.35], ['C', -1, 0.05]], 10, 100, 100], -100], ['normal control 3', [[['P', -1, 0.75], ['C', 5, 0.6], ['C', 10, 0.35], ['P', -3, 0.05]], 10, 50, 0], -50]], [['regression put delta sign 1', [[['P', 10, 0.75], ['P', -1, 0.35], ['P', 5, 0.75], ['P', 5, 0.6]], 100, 25, 0], 1400], ['regression put delta sign 2', [[['C', -1, 0.5], ['P', -1, 0.35], ['C', 1, 0.25], ['P', 10, 0.5]], 100, 50, 0], 500], ['partial repair probe 1', [[['P', -3, 0.05], ['P', 10, 0.05]], 100, 100, 0], 0], ['partial repair probe 2', [[['P', 1, 0.05], ['C', 1, 0.5], ['P', -3, 0.6], ['P', 5, 0.25]], 10, 50, 75], -100], ['boundary control 1', [[['C', 1, 0.5]], 100, 100, 0], -100], ['normal control 1', [[['C', 1, 0.25]], 10, 50, 50], -50], ['normal control 2', [[['C', -1, 0.75]], 100, 25, 75], 0], ['normal control 3', [[['P', 2, 0.35], ['P', -1, 0.05]], 10, 100, 100], -100]]]
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 delta sign 1300300Passed
regression put delta sign 2-175-175Passed
partial repair probe 100Passed
partial repair probe 2-100-100Passed
boundary control 1-100-100Passed
normal control 100Passed
normal control 2250250Passed
normal control 3-100-100Passed

SHA-256 / 585bac3e196c65f20e1b0a50cc39035f09c8ef4cdf6a373e07282b4911e37f3a

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

Case digest / 8a1e5e9c92546acdd287565604fde16ad1d9a79953d590eac2803aae4c5400cf