theta

Binary options

Computes Theta for binary cash-or-nothing call and put options using the Black-Scholes model (per day).

Avg. gas

3,161

Max abs. error

1e-14

Signature

solidity
function theta(
    uint128 spot,
    uint128 strike,
    uint32  timeToExp,
    uint64  volatility,
    uint64  rate
) internal pure returns (int128 thetaCall, int128 thetaPut)

Parameters

NameTypeDescription
spotuint128Current spot price, 18-decimal fixed-point.
strikeuint128Strike price, 18-decimal fixed-point. Precision-tuned for the no-arbitrage band against spot — see Bounds.
timeToExpuint32Time to expiration in seconds. timeToExp == 0 is allowed (handled as expired).
volatilityuint64Annualized implied volatility, 18-decimal fixed-point (e.g. 60% → 6e17).
rateuint64Annualized risk-free rate, 18-decimal fixed-point.

Returns

NameTypeDescription
thetaCallint128Binary call theta per day for unit payout in 18-decimal fixed-point. Signed.
thetaPutint128Binary put theta per day for unit payout in 18-decimal fixed-point. Signed.

Bounds

BoundValue
MIN_SPOT1e-6 smallest allowed spot price (1e12)
MAX_SPOT1e15 largest allowed spot price (1e33)
MAX_STSP_RATIO5× (strike must lie within [spot/5, spot·5])
MAX_EXPIRATION32 years (1,009,152,000 seconds)
MAX_RATE400% 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. Binary theta is signed and can be either sign depending on moneyness.
  • Volatility has no explicit revert — it's bounded only by its uint64 type (max ≈ 1.84e19, i.e. ~1840% annualized).
  • Fast-path on expiration: when timeToExp == 0, returns (0, 0).
  • Composes five DeFiMath primitives — ln, sqrtTime (specialized sqrt for years), expPositive (the discount factor), exp (the density φ(d₂)), and stdNormCDF (the carry term). Its higher gas reflects that fuller composition.
  • Pure internal function; no external calls, no storage. Inlined into the caller's bytecode at compile time.

How it works

Binary theta is the derivative of the cash-or-nothing price with respect to the passage of time. DeFiMath returns it per day — the annualized figure divided by 365:

Θcall=1365[rerTΦ(d2)+erTφ(d2)(d12TrσT)]\Theta_{call} = \frac{1}{365}\left[ r \, e^{-rT} \Phi(d_2) + e^{-rT} \varphi(d_2)\left(\frac{d_1}{2T} - \frac{r}{\sigma\sqrt{T}}\right) \right]
Θput=1365[rerTΦ(d2)erTφ(d2)(d12TrσT)]\Theta_{put} = \frac{1}{365}\left[ r \, e^{-rT} \Phi(-d_2) - e^{-rT} \varphi(d_2)\left(\frac{d_1}{2T} - \frac{r}{\sigma\sqrt{T}}\right) \right]

The shared decay term e^(−rT)·φ(d₂)·(d₁/2T − r/σ√T) is computed once and reused for both; only the sign and the carry term r·e^(−rT)·Φ(±d₂) differ. The density uses Math.exp, the discount factor Math.expPositive, the carry CDF Math.stdNormCDF, and √T / ln(spot/strike) use Math.sqrtTime / Math.ln.

On the supported domain the magnitude stays well below 1, so the suite enforces an absolute error only — 1e-14 per day — with no relative bound. Head-to-head measurements live in defimath-compare.

Errors

ErrorTrigger
SpotLowerBoundErrorspot ≤ MIN_SPOT
SpotUpperBoundErrorspot ≥ MAX_SPOT
StrikeLowerBoundErrorstrike · 5 < spot
StrikeUpperBoundErrorspot · 5 < strike
TimeToExpiryUpperBoundErrortimeToExp ≥ MAX_EXPIRATION
RateUpperBoundErrorrate ≥ MAX_RATE

Example

solidity
import "defimath-lib/contracts/derivatives/BinaryOptions.sol";

(int128 thetaCall, int128 thetaPut) = BinaryOptions.theta(
    1000e18,         // spot = $1,000
    1050e18,         // strike = $1,050
    30 days,         // 30 days to expiry
    0.60e18,         // 60% annualized vol
    0.05e18          // 5% risk-free rate
);
// thetaCall, thetaPut per day (signed by moneyness)