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.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression d2 volatility term 1 | -0.613446 | 1.69956 | Failed |
| regression d2 volatility term 2 | 0.594633 | 1.805544 | Failed |
| partial repair probe 1 | 13.067027 | 13.067027 | Passed |
| partial repair probe 2 | 5.016981 | 5.016981 | Passed |
| boundary control 1 | 10.0 | 10.0 | Passed |
| boundary control 2 | 10.0 | 10.0 | Passed |
| normal control 1 | 0.0 | 0.0 | Passed |
| normal control 2 | 10.0 | 10.0 | Passed |
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression d2 volatility term 1 | -0.404446 | 1.69956 | Failed |
| regression d2 volatility term 2 | -1.581095 | 1.805544 | Failed |
| partial repair probe 1 | 4.225537 | 13.067027 | Failed |
| partial repair probe 2 | 1.564997 | 5.016981 | Failed |
| boundary control 1 | 10.0 | 10.0 | Passed |
| boundary control 2 | 10.0 | 10.0 | Passed |
| normal control 1 | 0.0 | 0.0 | Passed |
| normal control 2 | 10.0 | 10.0 | Passed |
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression d2 volatility term 1 | 1.69956 | 1.69956 | Passed |
| regression d2 volatility term 2 | 1.805544 | 1.805544 | Passed |
| partial repair probe 1 | 13.067027 | 13.067027 | Passed |
| partial repair probe 2 | 5.016981 | 5.016981 | Passed |
| boundary control 1 | 10.0 | 10.0 | Passed |
| boundary control 2 | 10.0 | 10.0 | Passed |
| normal control 1 | 0.0 | 0.0 | Passed |
| normal control 2 | 10.0 | 10.0 | Passed |
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