FAILURE MAP
← Case archive

FA-61541 / Options payoff and settlement / Open access

European option value with continuous dividend yield: the dividend yield is added to the drift · case 01

Options on dividend payers are priced as if dividends increased the forward.

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

ROOT CAUSE

d1 uses r + q instead of r - q.

VERIFIED REPAIR

Use r - q in the drift term of d1.

Unsuccessful approach: Dropping q from d1 while keeping the e^{-qT} factor is internally inconsistent.

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 * 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 dividend drift 1', ['P', 110.0, 105.0, 0.0, 0.03, 0.35, 30], 2.338617], ['regression dividend drift 2', ['C', 110.0, 105.0, 0.0, 0.015, 0.35, 91], 9.987818], ['partial repair probe 1', ['C', 100.0, 105.0, 0.05, 0.015, 0.35, 30], 2.164477], ['partial repair probe 2', ['P', 90.0, 105.0, 0.02, 0.03, 0.1, 730], 16.810523], ['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, 105.0, 0.05, 0.015, 0.2, 1], 0.0], ['normal control 2', ['P', 100.0, 105.0, 0.05, 0.0, 0.35, 0], 5.0]], [['regression dividend drift 1', ['C', 100.0, 100.0, 0.02, 0.015, 0.1, 182], 2.917342], ['regression dividend drift 2', ['P', 90.0, 100.0, 0.0, 0.015, 0.35, 730], 25.3049], ['partial repair probe 1', ['P', 100.0, 95.0, 0.02, 0.015, 0.2, 30], 0.558539], ['partial repair probe 2', ['P', 100.0, 105.0, 0.05, 0.03, 0.1, 730], 5.758366], ['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, 105.0, 0.02, 0.0, 0.2, 30], 5.505807], ['normal control 2', ['C', 110.0, 100.0, 0.0, 0.0, 0.2, 730], 17.46773]], [['regression dividend drift 1', ['C', 110.0, 100.0, 0.0, 0.015, 0.35, 365], 19.029274], ['regression dividend drift 2', ['P', 100.0, 95.0, 0.0, 0.03, 0.35, 7], 0.359876], ['partial repair probe 1', ['P', 90.0, 105.0, 0.05, 0.015, 0.1, 182], 13.153147], ['partial repair probe 2', ['P', 100.0, 105.0, 0.0, 0.015, 0.35, 91], 10.129304], ['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', 110.0, 100.0, 0.02, 0.0, 0.2, 730], 5.917793], ['normal control 2', ['C', 100.0, 105.0, 0.0, 0.0, 0.2, 365], 5.905593]], [['regression dividend drift 1', ['P', 100.0, 100.0, 0.02, 0.03, 0.1, 182], 3.034769], ['regression dividend drift 2', ['C', 110.0, 95.0, 0.0, 0.015, 0.35, 91], 16.662902], ['partial repair probe 1', ['P', 110.0, 105.0, 0.05, 0.03, 0.35, 91], 4.98959], ['partial repair probe 2', ['C', 110.0, 100.0, 0.02, 0.03, 0.35, 30], 10.869205], ['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', 100.0, 95.0, 0.05, 0.03, 0.35, 0], 5.0], ['normal control 2', ['C', 110.0, 95.0, 0.02, 0.0, 0.1, 30], 15.156036]], [['regression dividend drift 1', ['C', 90.0, 100.0, 0.05, 0.015, 0.1, 365], 1.303213], ['regression dividend drift 2', ['C', 110.0, 100.0, 0.05, 0.03, 0.1, 365], 12.247458], ['partial repair probe 1', ['C', 100.0, 105.0, 0.02, 0.03, 0.1, 91], 0.402157], ['partial repair probe 2', ['P', 90.0, 105.0, 0.02, 0.03, 0.35, 7], 15.012424], ['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', 90.0, 95.0, 0.0, 0.0, 0.35, 7], 5.298184], ['normal control 2', ['P', 100.0, 105.0, 0.05, 0.0, 0.35, 365], 13.823265]]]
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 dividend drift 12.3339812.338617Failed
regression dividend drift 29.9812459.987818Failed
partial repair probe 12.1633582.164477Failed
partial repair probe 215.32372516.810523Failed
boundary control 110.010.0Passed
boundary control 210.010.0Passed
normal control 10.00.0Passed
normal control 25.05.0Passed

SHA-256 / e9cf4fcc2b17aa052aa35dfd603f29419444aa0b4facd3b287208af77d6f6a05

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 + 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 dividend drift 1', ['P', 110.0, 105.0, 0.0, 0.03, 0.35, 30], 2.338617], ['regression dividend drift 2', ['C', 110.0, 105.0, 0.0, 0.015, 0.35, 91], 9.987818], ['partial repair probe 1', ['C', 100.0, 105.0, 0.05, 0.015, 0.35, 30], 2.164477], ['partial repair probe 2', ['P', 90.0, 105.0, 0.02, 0.03, 0.1, 730], 16.810523], ['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, 105.0, 0.05, 0.015, 0.2, 1], 0.0], ['normal control 2', ['P', 100.0, 105.0, 0.05, 0.0, 0.35, 0], 5.0]], [['regression dividend drift 1', ['C', 100.0, 100.0, 0.02, 0.015, 0.1, 182], 2.917342], ['regression dividend drift 2', ['P', 90.0, 100.0, 0.0, 0.015, 0.35, 730], 25.3049], ['partial repair probe 1', ['P', 100.0, 95.0, 0.02, 0.015, 0.2, 30], 0.558539], ['partial repair probe 2', ['P', 100.0, 105.0, 0.05, 0.03, 0.1, 730], 5.758366], ['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, 105.0, 0.02, 0.0, 0.2, 30], 5.505807], ['normal control 2', ['C', 110.0, 100.0, 0.0, 0.0, 0.2, 730], 17.46773]], [['regression dividend drift 1', ['C', 110.0, 100.0, 0.0, 0.015, 0.35, 365], 19.029274], ['regression dividend drift 2', ['P', 100.0, 95.0, 0.0, 0.03, 0.35, 7], 0.359876], ['partial repair probe 1', ['P', 90.0, 105.0, 0.05, 0.015, 0.1, 182], 13.153147], ['partial repair probe 2', ['P', 100.0, 105.0, 0.0, 0.015, 0.35, 91], 10.129304], ['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', 110.0, 100.0, 0.02, 0.0, 0.2, 730], 5.917793], ['normal control 2', ['C', 100.0, 105.0, 0.0, 0.0, 0.2, 365], 5.905593]], [['regression dividend drift 1', ['P', 100.0, 100.0, 0.02, 0.03, 0.1, 182], 3.034769], ['regression dividend drift 2', ['C', 110.0, 95.0, 0.0, 0.015, 0.35, 91], 16.662902], ['partial repair probe 1', ['P', 110.0, 105.0, 0.05, 0.03, 0.35, 91], 4.98959], ['partial repair probe 2', ['C', 110.0, 100.0, 0.02, 0.03, 0.35, 30], 10.869205], ['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', 100.0, 95.0, 0.05, 0.03, 0.35, 0], 5.0], ['normal control 2', ['C', 110.0, 95.0, 0.02, 0.0, 0.1, 30], 15.156036]], [['regression dividend drift 1', ['C', 90.0, 100.0, 0.05, 0.015, 0.1, 365], 1.303213], ['regression dividend drift 2', ['C', 110.0, 100.0, 0.05, 0.03, 0.1, 365], 12.247458], ['partial repair probe 1', ['C', 100.0, 105.0, 0.02, 0.03, 0.1, 91], 0.402157], ['partial repair probe 2', ['P', 90.0, 105.0, 0.02, 0.03, 0.35, 7], 15.012424], ['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', 90.0, 95.0, 0.0, 0.0, 0.35, 7], 5.298184], ['normal control 2', ['P', 100.0, 105.0, 0.05, 0.0, 0.35, 365], 13.823265]]]
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 dividend drift 12.3374492.338617Failed
regression dividend drift 29.9861699.987818Failed
partial repair probe 12.1641992.164477Failed
partial repair probe 216.51192916.810523Failed
boundary control 110.010.0Passed
boundary control 210.010.0Passed
normal control 10.00.0Passed
normal control 25.05.0Passed

SHA-256 / ff347af977efa352312b2ba5f20ea6f31a88213e2fb35335e7c022e42c02cf6f

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 dividend drift 1', ['P', 110.0, 105.0, 0.0, 0.03, 0.35, 30], 2.338617], ['regression dividend drift 2', ['C', 110.0, 105.0, 0.0, 0.015, 0.35, 91], 9.987818], ['partial repair probe 1', ['C', 100.0, 105.0, 0.05, 0.015, 0.35, 30], 2.164477], ['partial repair probe 2', ['P', 90.0, 105.0, 0.02, 0.03, 0.1, 730], 16.810523], ['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, 105.0, 0.05, 0.015, 0.2, 1], 0.0], ['normal control 2', ['P', 100.0, 105.0, 0.05, 0.0, 0.35, 0], 5.0]], [['regression dividend drift 1', ['C', 100.0, 100.0, 0.02, 0.015, 0.1, 182], 2.917342], ['regression dividend drift 2', ['P', 90.0, 100.0, 0.0, 0.015, 0.35, 730], 25.3049], ['partial repair probe 1', ['P', 100.0, 95.0, 0.02, 0.015, 0.2, 30], 0.558539], ['partial repair probe 2', ['P', 100.0, 105.0, 0.05, 0.03, 0.1, 730], 5.758366], ['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, 105.0, 0.02, 0.0, 0.2, 30], 5.505807], ['normal control 2', ['C', 110.0, 100.0, 0.0, 0.0, 0.2, 730], 17.46773]], [['regression dividend drift 1', ['C', 110.0, 100.0, 0.0, 0.015, 0.35, 365], 19.029274], ['regression dividend drift 2', ['P', 100.0, 95.0, 0.0, 0.03, 0.35, 7], 0.359876], ['partial repair probe 1', ['P', 90.0, 105.0, 0.05, 0.015, 0.1, 182], 13.153147], ['partial repair probe 2', ['P', 100.0, 105.0, 0.0, 0.015, 0.35, 91], 10.129304], ['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', 110.0, 100.0, 0.02, 0.0, 0.2, 730], 5.917793], ['normal control 2', ['C', 100.0, 105.0, 0.0, 0.0, 0.2, 365], 5.905593]], [['regression dividend drift 1', ['P', 100.0, 100.0, 0.02, 0.03, 0.1, 182], 3.034769], ['regression dividend drift 2', ['C', 110.0, 95.0, 0.0, 0.015, 0.35, 91], 16.662902], ['partial repair probe 1', ['P', 110.0, 105.0, 0.05, 0.03, 0.35, 91], 4.98959], ['partial repair probe 2', ['C', 110.0, 100.0, 0.02, 0.03, 0.35, 30], 10.869205], ['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', 100.0, 95.0, 0.05, 0.03, 0.35, 0], 5.0], ['normal control 2', ['C', 110.0, 95.0, 0.02, 0.0, 0.1, 30], 15.156036]], [['regression dividend drift 1', ['C', 90.0, 100.0, 0.05, 0.015, 0.1, 365], 1.303213], ['regression dividend drift 2', ['C', 110.0, 100.0, 0.05, 0.03, 0.1, 365], 12.247458], ['partial repair probe 1', ['C', 100.0, 105.0, 0.02, 0.03, 0.1, 91], 0.402157], ['partial repair probe 2', ['P', 90.0, 105.0, 0.02, 0.03, 0.35, 7], 15.012424], ['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', 90.0, 95.0, 0.0, 0.0, 0.35, 7], 5.298184], ['normal control 2', ['P', 100.0, 105.0, 0.05, 0.0, 0.35, 365], 13.823265]]]
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 dividend drift 12.3386172.338617Passed
regression dividend drift 29.9878189.987818Passed
partial repair probe 12.1644772.164477Passed
partial repair probe 216.81052316.810523Passed
boundary control 110.010.0Passed
boundary control 210.010.0Passed
normal control 10.00.0Passed
normal control 25.05.0Passed

SHA-256 / 6bbbc6ca1b6865e64b6c7df5e0d4bcf6657b83a53680644ff2c9aefced56f702

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

Case digest / cf3dd773e22b78fd0b83f540605f385454ec7e64debd8b92bb47734d902089cc