theta
Black-ScholesComputes Theta of the option using the Black-Scholes model (time decay per day).
Avg. gas
3,101
Max abs. error
1.9e-12
when |θ| < 1
Max rel. error
5e-12
when |θ| ≥ 1
Signature
function theta(
uint128 spot,
uint128 strike,
uint32 timeToExp,
uint64 volatility,
uint64 rate
) internal pure returns (int128 thetaCall, int128 thetaPut)Parameters
| Name | Type | Description |
|---|---|---|
| spot | uint128 | Current spot price, 18-decimal fixed-point. |
| strike | uint128 | Strike price, 18-decimal fixed-point. Precision-tuned for the no-arbitrage band against spot — see Bounds. |
| timeToExp | uint32 | Time to expiration in seconds. timeToExp == 0 is allowed (handled as expired). |
| volatility | uint64 | Annualized implied volatility, 18-decimal fixed-point (e.g. 60% → 6e17). |
| rate | uint64 | Annualized risk-free rate, 18-decimal fixed-point. |
Returns
| Name | Type | Description |
|---|---|---|
| thetaCall | int128 | Call theta per day in 18-decimal fixed-point. Typically ≤ 0 (value decays as time passes). |
| thetaPut | int128 | Put theta per day in 18-decimal fixed-point. |
Bounds
| Bound | Value |
|---|---|
| MIN_SPOT | 1e-6 smallest allowed spot price (1e12) |
| MAX_SPOT | 1e15 largest allowed spot price (1e33) |
| MAX_STSP_RATIO | 5× (strike must lie within [spot/5, spot·5]) |
| MAX_EXPIRATION | 32 years (1,009,152,000 seconds) |
| MAX_RATE | 400% annual (4e18) |
Behavior
- Validates all five inputs against module-wide constants and reverts with a typed error on any violation.
- Returns theta per day (the annual figure divided by 365) for both call and put, sharing the common time-decay term across the two.
- Volatility has no explicit revert — it's bounded only by its
uint64type (max ≈1.84e19, i.e. ~1840% annualized). TheMIN_VOL_IV/MAX_VOL_IVconstants apply only to the impliedVolatility solver, not the greeks. - Fast-path on expiration: when
timeToExp == 0, returns(0, 0). - Composes four DeFiMath primitives — ln,
sqrtTime(specialized sqrt for years),expPositive(the discount factore^(−rT)),exp(the densityφ(d₁)), and stdNormCDF (the carry term). Its higher gas reflects that fuller composition. - Pure
internalfunction; no external calls, no storage. Inlined into the caller's bytecode at compile time.
How it works
theta is the derivative of option value with respect to the passage of time. DeFiMath returns it per day — the annualized Black-Scholes theta divided by 365:
The shared time-decay term S·φ(d₁)·σ / (2√T) is computed once and reused for both call and put; only the sign and the carry term r·K·e^(−rT)·Φ(±d₂) differ. The density φ(d₁) uses Math.exp, the discount factor e^(−rT) uses Math.expPositive, the carry CDF uses Math.stdNormCDF, and √T / ln(spot/strike) use Math.sqrtTime / Math.ln.
Precision follows the dual-metric rule: a relative bound of 5e-12 where |θ| ≥ 1 and an absolute bound of 1.9e-12 where |θ| < 1. Both are enforced at spot = $1,000 across a full sweep of strike, time, vol, and rate — head-to-head measurements live in defimath-compare.
Errors
| Error | Trigger |
|---|---|
| SpotLowerBoundError | spot ≤ MIN_SPOT |
| SpotUpperBoundError | spot ≥ MAX_SPOT |
| StrikeLowerBoundError | strike · 5 < spot |
| StrikeUpperBoundError | spot · 5 < strike |
| TimeToExpiryUpperBoundError | timeToExp ≥ MAX_EXPIRATION |
| RateUpperBoundError | rate ≥ MAX_RATE |
Example
import "defimath-lib/contracts/derivatives/BlackScholes.sol";
(int128 thetaCall, int128 thetaPut) = BlackScholes.theta(
1000e18, // spot = $1,000
980e18, // strike = $980
60 days, // 60 days to expiry
0.60e18, // 60% annualized vol
0.05e18 // 5% risk-free rate
);
// thetaCall ≈ -0.45e18 per day (about -$0.45/day)