Options¶
See the Options guide for a narrative walkthrough.
Pricing¶
pricing
¶
Option pricing in pure JAX.
The Black-Scholes-Merton price is a plain differentiable function, so the Greeks
module gets every sensitivity from jax.grad without duplicating formulas. A
jitted Newton solver recovers implied volatility, and a binomial (Cox-Ross-
Rubinstein) lattice prices American-style options.
Convention: +1 for calls, -1 for puts (is_call boolean helpers are
provided for readability at call sites).
black_scholes_price
¶
black_scholes_price(
spot: Array,
strike: Array,
ttm: Array,
vol: Array,
rate: Array = 0.0,
div: Array = 0.0,
is_call: bool = True,
) -> Array
Black-Scholes-Merton price of a European option.
All array arguments broadcast, so this prices whole option chains at once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
Array
|
Underlying price and strike. |
required |
strike
|
Array
|
Underlying price and strike. |
required |
ttm
|
Array
|
Time to maturity in years. |
required |
vol
|
Array
|
Annualized volatility. |
required |
rate
|
Array
|
Continuous risk-free rate and dividend yield. |
0.0
|
div
|
Array
|
Continuous risk-free rate and dividend yield. |
0.0
|
is_call
|
bool
|
|
True
|
Source code in src/jaxfolio/options/pricing.py
price_call_chain
¶
price_call_chain(
spot: float,
strikes: Array,
ttms: Array,
vols: Array,
rate: float = 0.0,
div: float = 0.0,
) -> Array
Vectorized call prices across a chain of (strike, ttm, vol) triples.
ttms and vols may be scalars (broadcast to every strike) or arrays
aligned with strikes.
Source code in src/jaxfolio/options/pricing.py
implied_volatility
¶
implied_volatility(
price: float,
spot: float,
strike: float,
ttm: float,
rate: float = 0.0,
div: float = 0.0,
is_call: bool = True,
*,
initial_vol: float = 0.2,
max_iter: int = 50,
tol: float = 1e-08,
) -> Array
Recover implied volatility via jitted Newton iterations.
Vega (the derivative of price w.r.t. vol) comes from jax.grad on the
pricer, so the Newton step needs no hand-coded derivative. Returns NaN
when no volatility reproduces price to within tol (e.g. a price below
intrinsic value or a deep-OTM option with vanishing vega), so callers can
distinguish "no solution" from a genuinely tiny implied vol.
Source code in src/jaxfolio/options/pricing.py
binomial_american
¶
binomial_american(
spot: float,
strike: float,
ttm: float,
vol: float,
rate: float = 0.0,
div: float = 0.0,
is_call: bool = True,
*,
steps: int = 256,
) -> Array
Cox-Ross-Rubinstein binomial price for an American-style option.
Backward induction with early-exercise checks at every node. steps
controls the lattice resolution.
Source code in src/jaxfolio/options/pricing.py
Greeks¶
greeks
¶
Option Greeks via JAX automatic differentiation.
Rather than re-deriving closed-form Greek formulas (and risking them drifting out
of sync with the pricer), we differentiate :func:black_scholes_price directly:
- delta = d price / d spot
- gamma = d^2 price / d spot^2
- vega = d price / d vol
- theta = -d price / d ttm (per-year; divide by 365 for per-calendar-day)
- rho = d price / d rate
All are vmap-friendly, so :func:chain_greeks returns every Greek across a
whole option chain in one call.
delta
¶
Delta: sensitivity of price to the underlying spot.
gamma
¶
Gamma: second derivative of price w.r.t. spot (same for calls and puts).
Source code in src/jaxfolio/options/greeks.py
vega
¶
Vega: sensitivity of price to volatility (per 1.00 change in vol).
Source code in src/jaxfolio/options/greeks.py
theta
¶
Theta: time decay (per year). Negative for most long options.
Source code in src/jaxfolio/options/greeks.py
rho
¶
Rho: sensitivity of price to the risk-free rate.
all_greeks
¶
Return every first/second-order Greek for a single option as a dict.
Source code in src/jaxfolio/options/greeks.py
chain_greeks
¶
chain_greeks(
spot: float,
strikes: Array,
ttms: Array,
vols: Array,
rate: float = 0.0,
div: float = 0.0,
is_call: bool = True,
) -> dict[str, Array]
Vectorized Greeks across a chain of (strike, ttm, vol) triples.
Returns a dict of arrays (one entry per Greek), each aligned with the input
chain. Built from vmap over the single-option autodiff Greeks.
Source code in src/jaxfolio/options/greeks.py
Strategies¶
strategies
¶
Multi-leg options strategies: payoffs, P&L, and Greeks.
An :class:OptionLeg describes a single position (call/put, long/short, strike,
expiry, quantity). An :class:OptionStrategy is a collection of legs (optionally
plus a stock leg) with helpers to evaluate payoff at expiry, mark-to-model P&L at
a horizon, net Greeks, and the break-even points. A library of preset
constructors builds the common structures (covered call, collar, spreads,
straddle, iron condor, butterfly, calendar).
OptionLeg
dataclass
¶
OptionLeg(
kind: str,
strike: float,
quantity: float = 1.0,
expiry: float = 0.25,
premium: float | None = None,
)
A single option position.
Attributes:
| Name | Type | Description |
|---|---|---|
kind |
str
|
|
strike |
float
|
Strike price. |
quantity |
float
|
Signed contract count — positive = long, negative = short. |
expiry |
float
|
Time to expiry in years (used for mark-to-model and Greeks). |
premium |
float | None
|
Premium paid (long) or received (short) per contract. If |
StockLeg
dataclass
¶
A linear underlying position held alongside options (e.g. covered call).
OptionStrategy
dataclass
¶
A named collection of option (and optional stock) legs.
payoff_at_expiry
¶
Total strategy P&L at expiry across a grid of terminal spot prices.
Source code in src/jaxfolio/options/strategies.py
net_premium
¶
Net premium: negative = net debit (paid), positive = net credit.
value_at
¶
value_at(
spot: float,
vol: float,
rate: float = 0.0,
div: float = 0.0,
ttm_shift: float = 0.0,
) -> float
Mark-to-model value of all option legs at a horizon.
ttm_shift is subtracted from each leg's expiry to advance time (e.g.
ttm_shift=1/12 marks the book one month forward).
Source code in src/jaxfolio/options/strategies.py
pnl_at
¶
pnl_at(
spot: float,
vol: float,
rate: float = 0.0,
div: float = 0.0,
ttm_shift: float = 0.0,
) -> float
Mark-to-model P&L relative to the entry cost of the option legs.
Source code in src/jaxfolio/options/strategies.py
greeks
¶
Net position Greeks (sum of per-leg Greeks weighted by quantity).
Source code in src/jaxfolio/options/strategies.py
break_evens
¶
Approximate break-even spot prices (payoff sign changes).
Source code in src/jaxfolio/options/strategies.py
covered_call
¶
covered_call(
spot: float,
strike: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long stock + short call: income overlay that caps upside.
Source code in src/jaxfolio/options/strategies.py
protective_put
¶
protective_put(
spot: float,
strike: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long stock + long put: downside insurance.
Source code in src/jaxfolio/options/strategies.py
collar
¶
collar(
spot: float,
put_strike: float,
call_strike: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long stock + long put + short call: bounded payoff, often near-zero cost.
Source code in src/jaxfolio/options/strategies.py
bull_call_spread
¶
bull_call_spread(
spot: float,
lower: float,
upper: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long lower-strike call + short upper-strike call: capped bullish debit.
Source code in src/jaxfolio/options/strategies.py
bear_put_spread
¶
bear_put_spread(
spot: float,
upper: float,
lower: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long upper-strike put + short lower-strike put: capped bearish debit.
Source code in src/jaxfolio/options/strategies.py
straddle
¶
straddle(
spot: float,
strike: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long call + long put at the same strike: a bet on large moves either way.
Source code in src/jaxfolio/options/strategies.py
strangle
¶
strangle(
spot: float,
put_strike: float,
call_strike: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long OTM put + long OTM call: cheaper volatility bet than a straddle.
Source code in src/jaxfolio/options/strategies.py
iron_condor
¶
iron_condor(
spot: float,
put_long: float,
put_short: float,
call_short: float,
call_long: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Short strangle wrapped in long protective wings: a range-bound credit trade.
Strikes must satisfy put_long < put_short < call_short < call_long.
Source code in src/jaxfolio/options/strategies.py
butterfly
¶
butterfly(
spot: float,
lower: float,
middle: float,
upper: float,
*,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Long butterfly with calls: peak payoff pinned at the middle strike.
Source code in src/jaxfolio/options/strategies.py
calendar_spread
¶
calendar_spread(
spot: float,
strike: float,
*,
near_expiry: float = 0.08,
far_expiry: float = 0.33,
vol: float = 0.25,
rate: float = 0.0,
) -> OptionStrategy
Short near-dated + long far-dated call at one strike: a theta/vega play.
Because the legs have different expiries, use :meth:OptionStrategy.pnl_at
(mark-to-model) rather than expiry payoff to analyze this structure.
Source code in src/jaxfolio/options/strategies.py
Overlays¶
overlay
¶
Options overlays on top of an optimized equity portfolio.
Bridges the optimizer output (:class:PortfolioResult) and the options layer:
apply a covered-call or collar overlay to the largest holdings, aggregate the net
Greeks of the resulting book, and produce a combined at-expiry payoff for the
overlaid position. This is what makes the two halves of the library compose.
OverlayBook
dataclass
¶
OverlayBook(
strategies: dict[str, OptionStrategy],
weights: dict[str, float],
spots: dict[str, float],
)
A basket of per-asset option strategies scaled by portfolio weights.
Attributes:
| Name | Type | Description |
|---|---|---|
strategies |
dict[str, OptionStrategy]
|
Mapping |
weights |
dict[str, float]
|
Portfolio weight of each overlaid asset (used to scale payoffs/Greeks). |
spots |
dict[str, float]
|
Reference spot price per asset. |
net_greeks
¶
Weighted net Greeks across the whole overlay book.
Source code in src/jaxfolio/options/overlay.py
payoff_curve
¶
Weighted portfolio P&L across a grid of relative spot shocks.
shock_grid is a multiplier applied to every asset's spot (e.g.
np.linspace(0.7, 1.3, 200) sweeps -30% to +30%). Returns the
weight-scaled aggregate P&L of the overlaid holdings.
Source code in src/jaxfolio/options/overlay.py
covered_call_overlay
¶
covered_call_overlay(
result: PortfolioResult,
spots: dict[str, float],
*,
top_n: int = 5,
moneyness: float = 1.05,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OverlayBook
Write covered calls on the top_n largest holdings.
moneyness sets the call strike relative to spot (1.05 = 5% OTM).
Assets without a provided spot price are skipped.
Source code in src/jaxfolio/options/overlay.py
collar_overlay
¶
collar_overlay(
result: PortfolioResult,
spots: dict[str, float],
*,
top_n: int = 5,
put_moneyness: float = 0.95,
call_moneyness: float = 1.05,
expiry: float = 0.25,
vol: float = 0.25,
rate: float = 0.0,
) -> OverlayBook
Wrap the top_n largest holdings in protective collars.
Bounds each holding's outcome between put_moneyness and
call_moneyness times spot — capping both tail loss and upside.