FAILURE MAP
← Case archive

FA-61546 / Options payoff and settlement / Open access

European option value with continuous dividend yield: d2 subtracts sigma*T · case 01

Values are wrong for every maturity other than one year.

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

ROOT CAUSE

d2 subtracts sigma*T instead of sigma*sqrt(T).

VERIFIED REPAIR

Use d2 = d1 - sigma*sqrt(T).

Unsuccessful approach: Subtracting sigma^2*sqrt(T) mixes variance and volatility.

Case contract

Inputs kind, spot S, strike K, rate r, dividend yield q, volatility sigma and calendar days to expiry. T = days/365. At days == 0 return intrinsic value. Otherwise d1 = (ln(S/K) + (r - q + sigma^2/2)T)/(sigma sqrt T), d2 = d1 - sigma sqrt T, call = S e^{-qT} N(d1) - K e^{-rT} N(d2), put = K e^{-rT} N(-d2) - S e^{-qT} N(-d1). 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
import math
N = 1
observations = []
def solve(kind, S, K, r, q, sigma, days):
    def N(x):
        return 0.5 * (1 + math.erf(x / math.sqrt(2)))
    T = days / 365
    if days == 0:
        return round(max(S - K, 0.0) if kind == 'C' else max(K - S, 0.0), 6)
    d1 = (math.log(S / K) + (r - q + 0.5 * sigma ** 2) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma * T
    if kind == 'C':
        v = S * math.exp(-q * T) * N(d1) - K * math.exp(-r * T) * N(d2)
    else:
        v = K * math.exp(-r * T) * N(-d2) - S * math.exp(-q * T) * N(-d1)
    return round(v, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression d2 volatility term 1', ['C', 90.0, 95.0, 0.02, 0.03, 0.35, 30], 1.69956], ['regression d2 volatility term 2', ['C', 90.0, 100.0, 0.02, 0.015, 0.2, 182], 1.805544], ['partial repair probe 1', ['C', 100.0, 100.0, 0.02, 0.03, 0.35, 365], 13.067027], ['partial repair probe 2', ['C', 100.0, 100.0, 0.02, 0.0, 0.1, 365], 5.016981], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 100.0, 95.0, 0.05, 0.0, 0.1, 1], 0.0], ['normal control 2', ['P', 90.0, 100.0, 0.0, 0.0, 0.2, 0], 10.0]], [['regression d2 volatility term 1', ['P', 90.0, 95.0, 0.05, 0.0, 0.35, 91], 8.491395], ['regression d2 volatility term 2', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 30], 0.035336], ['partial repair probe 1', ['C', 100.0, 95.0, 0.05, 0.0, 0.2, 365], 13.346465], ['partial repair probe 2', ['C', 110.0, 95.0, 0.0, 0.015, 0.35, 365], 21.78191], ['boundary control 1', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 90.0, 95.0, 0.02, 0.03, 0.2, 0], 5.0], ['normal control 2', ['P', 90.0, 105.0, 0.0, 0.03, 0.35, 1], 15.007397]], [['regression d2 volatility term 1', ['C', 100.0, 105.0, 0.0, 0.03, 0.35, 7], 0.399252], ['regression d2 volatility term 2', ['P', 110.0, 100.0, 0.02, 0.03, 0.1, 91], 0.063955], ['partial repair probe 1', ['C', 110.0, 100.0, 0.05, 0.015, 0.1, 365], 13.698166], ['partial repair probe 2', ['P', 110.0, 95.0, 0.02, 0.0, 0.1, 365], 0.200779], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['C', 100.0, 100.0, 0.05, 0.015, 0.35, 0], 0.0], ['normal control 2', ['C', 90.0, 105.0, 0.0, 0.0, 0.35, 0], 0.0]], [['regression d2 volatility term 1', ['C', 110.0, 105.0, 0.02, 0.03, 0.2, 91], 7.012004], ['regression d2 volatility term 2', ['P', 90.0, 95.0, 0.05, 0.03, 0.35, 30], 6.596833], ['partial repair probe 1', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 365], 1.30802], ['partial repair probe 2', ['C', 90.0, 100.0, 0.0, 0.03, 0.1, 365], 0.378908], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 0], 0.0], ['normal control 2', ['C', 100.0, 105.0, 0.05, 0.03, 0.35, 0], 0.0]], [['regression d2 volatility term 1', ['P', 110.0, 105.0, 0.02, 0.015, 0.2, 182], 3.745196], ['regression d2 volatility term 2', ['P', 100.0, 95.0, 0.05, 0.03, 0.2, 7], 0.032572], ['partial repair probe 1', ['C', 90.0, 95.0, 0.02, 0.0, 0.2, 365], 5.838977], ['partial repair probe 2', ['P', 110.0, 95.0, 0.02, 0.03, 0.2, 365], 2.923685], ['boundary control 1', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['C', 90.0, 100.0, 0.02, 0.015, 0.35, 1], 0.0], ['normal control 2', ['C', 100.0, 105.0, 0.05, 0.03, 0.1, 1], 0.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 d2 volatility term 1-0.6134461.69956Failed
regression d2 volatility term 20.5946331.805544Failed
partial repair probe 113.06702713.067027Passed
partial repair probe 25.0169815.016981Passed
boundary control 110.010.0Passed
boundary control 210.010.0Passed
normal control 10.00.0Passed
normal control 210.010.0Passed

SHA-256 / ac056318a97d31c94b2b1425c4d8ef2ded928b829e3dfab254cefb970a48de56

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(kind, S, K, r, q, sigma, days):
    def N(x):
        return 0.5 * (1 + math.erf(x / math.sqrt(2)))
    T = days / 365
    if days == 0:
        return round(max(S - K, 0.0) if kind == 'C' else max(K - S, 0.0), 6)
    d1 = (math.log(S / K) + (r - q + 0.5 * sigma ** 2) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma ** 2 * math.sqrt(T)
    if kind == 'C':
        v = S * math.exp(-q * T) * N(d1) - K * math.exp(-r * T) * N(d2)
    else:
        v = K * math.exp(-r * T) * N(-d2) - S * math.exp(-q * T) * N(-d1)
    return round(v, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression d2 volatility term 1', ['C', 90.0, 95.0, 0.02, 0.03, 0.35, 30], 1.69956], ['regression d2 volatility term 2', ['C', 90.0, 100.0, 0.02, 0.015, 0.2, 182], 1.805544], ['partial repair probe 1', ['C', 100.0, 100.0, 0.02, 0.03, 0.35, 365], 13.067027], ['partial repair probe 2', ['C', 100.0, 100.0, 0.02, 0.0, 0.1, 365], 5.016981], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 100.0, 95.0, 0.05, 0.0, 0.1, 1], 0.0], ['normal control 2', ['P', 90.0, 100.0, 0.0, 0.0, 0.2, 0], 10.0]], [['regression d2 volatility term 1', ['P', 90.0, 95.0, 0.05, 0.0, 0.35, 91], 8.491395], ['regression d2 volatility term 2', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 30], 0.035336], ['partial repair probe 1', ['C', 100.0, 95.0, 0.05, 0.0, 0.2, 365], 13.346465], ['partial repair probe 2', ['C', 110.0, 95.0, 0.0, 0.015, 0.35, 365], 21.78191], ['boundary control 1', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 90.0, 95.0, 0.02, 0.03, 0.2, 0], 5.0], ['normal control 2', ['P', 90.0, 105.0, 0.0, 0.03, 0.35, 1], 15.007397]], [['regression d2 volatility term 1', ['C', 100.0, 105.0, 0.0, 0.03, 0.35, 7], 0.399252], ['regression d2 volatility term 2', ['P', 110.0, 100.0, 0.02, 0.03, 0.1, 91], 0.063955], ['partial repair probe 1', ['C', 110.0, 100.0, 0.05, 0.015, 0.1, 365], 13.698166], ['partial repair probe 2', ['P', 110.0, 95.0, 0.02, 0.0, 0.1, 365], 0.200779], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['C', 100.0, 100.0, 0.05, 0.015, 0.35, 0], 0.0], ['normal control 2', ['C', 90.0, 105.0, 0.0, 0.0, 0.35, 0], 0.0]], [['regression d2 volatility term 1', ['C', 110.0, 105.0, 0.02, 0.03, 0.2, 91], 7.012004], ['regression d2 volatility term 2', ['P', 90.0, 95.0, 0.05, 0.03, 0.35, 30], 6.596833], ['partial repair probe 1', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 365], 1.30802], ['partial repair probe 2', ['C', 90.0, 100.0, 0.0, 0.03, 0.1, 365], 0.378908], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 0], 0.0], ['normal control 2', ['C', 100.0, 105.0, 0.05, 0.03, 0.35, 0], 0.0]], [['regression d2 volatility term 1', ['P', 110.0, 105.0, 0.02, 0.015, 0.2, 182], 3.745196], ['regression d2 volatility term 2', ['P', 100.0, 95.0, 0.05, 0.03, 0.2, 7], 0.032572], ['partial repair probe 1', ['C', 90.0, 95.0, 0.02, 0.0, 0.2, 365], 5.838977], ['partial repair probe 2', ['P', 110.0, 95.0, 0.02, 0.03, 0.2, 365], 2.923685], ['boundary control 1', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['C', 90.0, 100.0, 0.02, 0.015, 0.35, 1], 0.0], ['normal control 2', ['C', 100.0, 105.0, 0.05, 0.03, 0.1, 1], 0.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 d2 volatility term 1-0.4044461.69956Failed
regression d2 volatility term 2-1.5810951.805544Failed
partial repair probe 14.22553713.067027Failed
partial repair probe 21.5649975.016981Failed
boundary control 110.010.0Passed
boundary control 210.010.0Passed
normal control 10.00.0Passed
normal control 210.010.0Passed

SHA-256 / 487be230165a12e20e5177df8db31e6565cfb00c03f80ff26087e730e2eb3730

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(kind, S, K, r, q, sigma, days):
    def N(x):
        return 0.5 * (1 + math.erf(x / math.sqrt(2)))
    T = days / 365
    if days == 0:
        return round(max(S - K, 0.0) if kind == 'C' else max(K - S, 0.0), 6)
    d1 = (math.log(S / K) + (r - q + 0.5 * sigma ** 2) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma * math.sqrt(T)
    if kind == 'C':
        v = S * math.exp(-q * T) * N(d1) - K * math.exp(-r * T) * N(d2)
    else:
        v = K * math.exp(-r * T) * N(-d2) - S * math.exp(-q * T) * N(-d1)
    return round(v, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression d2 volatility term 1', ['C', 90.0, 95.0, 0.02, 0.03, 0.35, 30], 1.69956], ['regression d2 volatility term 2', ['C', 90.0, 100.0, 0.02, 0.015, 0.2, 182], 1.805544], ['partial repair probe 1', ['C', 100.0, 100.0, 0.02, 0.03, 0.35, 365], 13.067027], ['partial repair probe 2', ['C', 100.0, 100.0, 0.02, 0.0, 0.1, 365], 5.016981], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 100.0, 95.0, 0.05, 0.0, 0.1, 1], 0.0], ['normal control 2', ['P', 90.0, 100.0, 0.0, 0.0, 0.2, 0], 10.0]], [['regression d2 volatility term 1', ['P', 90.0, 95.0, 0.05, 0.0, 0.35, 91], 8.491395], ['regression d2 volatility term 2', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 30], 0.035336], ['partial repair probe 1', ['C', 100.0, 95.0, 0.05, 0.0, 0.2, 365], 13.346465], ['partial repair probe 2', ['C', 110.0, 95.0, 0.0, 0.015, 0.35, 365], 21.78191], ['boundary control 1', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 90.0, 95.0, 0.02, 0.03, 0.2, 0], 5.0], ['normal control 2', ['P', 90.0, 105.0, 0.0, 0.03, 0.35, 1], 15.007397]], [['regression d2 volatility term 1', ['C', 100.0, 105.0, 0.0, 0.03, 0.35, 7], 0.399252], ['regression d2 volatility term 2', ['P', 110.0, 100.0, 0.02, 0.03, 0.1, 91], 0.063955], ['partial repair probe 1', ['C', 110.0, 100.0, 0.05, 0.015, 0.1, 365], 13.698166], ['partial repair probe 2', ['P', 110.0, 95.0, 0.02, 0.0, 0.1, 365], 0.200779], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['C', 100.0, 100.0, 0.05, 0.015, 0.35, 0], 0.0], ['normal control 2', ['C', 90.0, 105.0, 0.0, 0.0, 0.35, 0], 0.0]], [['regression d2 volatility term 1', ['C', 110.0, 105.0, 0.02, 0.03, 0.2, 91], 7.012004], ['regression d2 volatility term 2', ['P', 90.0, 95.0, 0.05, 0.03, 0.35, 30], 6.596833], ['partial repair probe 1', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 365], 1.30802], ['partial repair probe 2', ['C', 90.0, 100.0, 0.0, 0.03, 0.1, 365], 0.378908], ['boundary control 1', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['P', 100.0, 95.0, 0.05, 0.03, 0.1, 0], 0.0], ['normal control 2', ['C', 100.0, 105.0, 0.05, 0.03, 0.35, 0], 0.0]], [['regression d2 volatility term 1', ['P', 110.0, 105.0, 0.02, 0.015, 0.2, 182], 3.745196], ['regression d2 volatility term 2', ['P', 100.0, 95.0, 0.05, 0.03, 0.2, 7], 0.032572], ['partial repair probe 1', ['C', 90.0, 95.0, 0.02, 0.0, 0.2, 365], 5.838977], ['partial repair probe 2', ['P', 110.0, 95.0, 0.02, 0.03, 0.2, 365], 2.923685], ['boundary control 1', ['P', 90.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['boundary control 2', ['C', 110.0, 100.0, 0.05, 0.0, 0.2, 0], 10.0], ['normal control 1', ['C', 90.0, 100.0, 0.02, 0.015, 0.35, 1], 0.0], ['normal control 2', ['C', 100.0, 105.0, 0.05, 0.03, 0.1, 1], 0.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 d2 volatility term 11.699561.69956Passed
regression d2 volatility term 21.8055441.805544Passed
partial repair probe 113.06702713.067027Passed
partial repair probe 25.0169815.016981Passed
boundary control 110.010.0Passed
boundary control 210.010.0Passed
normal control 10.00.0Passed
normal control 210.010.0Passed

SHA-256 / 114e7c1c57a42438643791e0e6dbd0f5552c22b33bdf5af4561cf2e83502bcc9

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

Case digest / 2aa84aecad2b144bf52e15b9ab31d79c721878ff013aff54c0211d8848bbb570