/* ============================================================ Black-Scholes calculator — functional ============================================================ */ function CalcBlackScholesPage() { const [type, setType] = useState('call'); const [S, setS] = useState(100); const [K, setK] = useState(100); const [days, setDays] = useState(60); const [r, setR] = useState(13.75); const [q, setQ] = useState(0); const [sigma, setSigma] = useState(28); const T = days / 365; const res = IBDMath.bs(+S, +K, T, +r / 100, +q / 100, +sigma / 100, type); // Sensitivity: price vs spot const sensitivity = useMemo(() => { const sMin = +S * 0.7, sMax = +S * 1.3; const pts = []; for (let i = 0; i <= 60; i++) { const s = sMin + (sMax - sMin) * (i / 60); const r1 = IBDMath.bs(s, +K, T, +r / 100, +q / 100, +sigma / 100, type); pts.push({ s, p: r1.price }); } return pts; }, [S, K, days, r, q, sigma, type]); return (
{/* Result header */}
Resultado · {type === 'call' ? 'Call' : 'Put'} europeia
{IBDMath.fmtBRL(res.price)}
Prêmio teórico · σ {sigma}% · T {days} dias · r {r}%
moneyness
{(((+S - +K) / +K) * 100).toLocaleString('pt-BR', {maximumFractionDigits: 2})}%
S/K = {(+S / +K).toFixed(4)}
{/* Greeks */}
Gregas
{/* Sensitivity chart */}

Sensibilidade do prêmio ao preço à vista

S ∈ [{(S*0.7).toFixed(2)} … {(S*1.3).toFixed(2)}]
{/* Decomposition */}

Decomposição do prêmio

{(() => { const intrinsic = type === 'call' ? Math.max(+S - +K, 0) : Math.max(+K - +S, 0); const time = res.price - intrinsic; return ( <>
Valor intrínseco
{IBDMath.fmtBRL(intrinsic)}
max({type === 'call' ? 'S−K' : 'K−S'}, 0)
Valor extrínseco
{IBDMath.fmtBRL(time)}
prêmio − intrínseco
Volatilidade implícita usada
{(+sigma).toFixed(2)}%
ann. · base 252 / 365
); })()}
{/* Formula */}
Fórmula utilizada
d₁ = [ ln(S/K) + (r − q + σ²/2)·T ] / (σ·√T) = {IBDMath.fmtNum(res.d1, 4)}
d₂ = d₁ − σ·√T = {IBDMath.fmtNum(res.d2, 4)}
{type === 'call' ? 'C = S·e^(−qT)·N(d₁) − K·e^(−rT)·N(d₂)' : 'P = K·e^(−rT)·N(−d₂) − S·e^(−qT)·N(−d₁)'}
); } function NumField({ label, value, setValue, unit, step, hint }) { return (
setValue(e.target.value === '' ? '' : +e.target.value)} className="mono" style={{padding: 12, border: 'none', background: 'var(--bg-elev)', fontSize: 15, color: 'var(--fg)', outline: 'none', width: '100%'}} /> {unit}
{hint &&
{hint}
}
); } function Greek({ name, label, value, sub }) { return (
{name}
{value}
{label} · {sub}
); } function SensitivityChart({ points, S, K, type }) { const w = 720, h = 280, pad = { l: 50, r: 16, t: 16, b: 36 }; const iw = w - pad.l - pad.r, ih = h - pad.t - pad.b; const xs = points.map(p => p.s); const ys = points.map(p => p.p); const xMin = Math.min(...xs), xMax = Math.max(...xs); const yMin = 0, yMax = Math.max(...ys) * 1.05; const x = s => pad.l + ((s - xMin) / (xMax - xMin)) * iw; const y = v => pad.t + ih - ((v - yMin) / (yMax - yMin)) * ih; const path = points.map((p, i) => (i === 0 ? 'M' : 'L') + x(p.s).toFixed(2) + ',' + y(p.p).toFixed(2)).join(' '); // intrinsic line const intrPath = points.map((p, i) => { const v = type === 'call' ? Math.max(p.s - K, 0) : Math.max(K - p.s, 0); return (i === 0 ? 'M' : 'L') + x(p.s).toFixed(2) + ',' + y(v).toFixed(2); }).join(' '); const xTicks = 6, yTicks = 5; return (
{/* grid */} {Array.from({length: yTicks + 1}, (_, i) => { const yy = pad.t + (ih / yTicks) * i; const v = yMax - (yMax / yTicks) * i; return ( {v.toFixed(2)} ); })} {Array.from({length: xTicks + 1}, (_, i) => { const xx = pad.l + (iw / xTicks) * i; const v = xMin + ((xMax - xMin) / xTicks) * i; return ( {v.toFixed(0)} ); })} {/* intrinsic */} {/* premium */} {/* current S */} S = {S} {/* strike K */} K {/* axes labels */} PREÇO À VISTA (S)
Prêmio teórico Valor intrínseco S atual
); } window.CalcBlackScholesPage = CalcBlackScholesPage; window.NumField = NumField;