Derivatives

This notebook walks through AbaQuant’s core derivatives-pricing toolkit: vanilla options (Black–Scholes and Black-76), Greeks, binomial trees, forward contracts, exotic options, and composable option strategies.

Sections:

  1. Vanilla option pricing

  2. Greek ladders (first- and second-order)

  3. Binomial-tree models (European vs. American)

  4. Forward contracts

  5. Exotic options

  6. Composable option strategies

Setup

import abaquant
print(f"AbaQuant version: {abaquant.__version__}")
AbaQuant version: 1.0.0rc1
from abaquant.derivatives.exotics import (
    asset_or_nothing_options,
    cash_or_nothing_options,
    down_and_out_barrier_option,
    exchange_options,
    geometric_asian_options,
)
from abaquant.derivatives.forwards import forward_contract_value, forward_price, fx_forward_price
from abaquant.derivatives.strategies import OptionStrategy, strategy_profile
from abaquant.derivatives.trees import binomial_tree, crr_binomial_tree
from abaquant.derivatives.vanilla import (
    black_76,
    black_scholes,
    calculate_greeks,
    implied_volatility_bsm,
    second_order_greeks,
)

1. Vanilla option pricing

black_scholes prices European options under the classic lognormal model. black_76 prices options on forwards/futures. implied_volatility_bsm inverts a market price to recover the volatility the market is implying.

call_price = black_scholes(100.0, 100.0, 0.05, 0.20, 1.0, is_call=True)
put_price = black_scholes(100.0, 100.0, 0.05, 0.20, 1.0, is_call=False)
future_option = black_76(102.0, 100.0, 0.05, 0.20, 1.0, is_call=True)
solved_volatility = implied_volatility_bsm(call_price, 100.0, 100.0, 0.05, 1.0)

print(f"European call price:      {call_price:.4f}")
print(f"European put price:       {put_price:.4f}")
print(f"Black-76 call price:      {future_option:.4f}")
print(f"Implied volatility (BSM): {solved_volatility:.4f}")
European call price:      10.4506
European put price:       5.5735
Black-76 call price:      8.6414
Implied volatility (BSM): 0.2000

2. Greek ladders

First-order Greeks (delta, gamma, vega, theta, rho) describe local sensitivities. Second-order Greeks (vanna, vomma, …) capture how those sensitivities themselves change.

first_order = calculate_greeks(100.0, 100.0, 0.05, 0.20, 1.0, is_call=True)
second_order = second_order_greeks(100.0, 100.0, 0.05, 0.0, 0.20, 1.0, is_call=True)

print("First-order Greeks:")
for greek in ("delta", "gamma", "vega"):
    print(f"  {greek:8s}: {first_order[greek]:.6f}")

print("\nSecond-order Greeks:")
for greek in ("vanna", "vomma"):
    print(f"  {greek:8s}: {second_order[greek]:.6f}")
First-order Greeks:
  delta   : 0.636831
  gamma   : 0.018762
  vega    : 0.375240

Second-order Greeks:
  vanna   : -0.281430
  vomma   : 0.098501

3. Binomial-tree models

Trees are useful for American-exercise options and for pedagogical inspection of the underlying lattice. We compare European vs. American exercise on the same put, then price a call with the Cox–Ross–Rubinstein (CRR) convention.

european_price, _ = binomial_tree(100.0, 100.0, 1.0, 0.05, 0.20, 80, option_type="put")
american_price, _ = binomial_tree(
    100.0, 100.0, 1.0, 0.05, 0.20, 80, option_type="put", american=True
)
crr_price, _, _ = crr_binomial_tree(100.0, 100.0, 0.05, 0.20, 1.0, 80, is_call=True)

print(f"European put (tree): {european_price:.4f}")
print(f"American put (tree): {american_price:.4f}  (>= European due to early-exercise value)")
print(f"CRR call:             {crr_price:.4f}")
European put (tree): 5.5486
American put (tree): 6.0801  (>= European due to early-exercise value)
CRR call:             10.4256

4. Forward contracts

Forward pricing under carry, an FX forward via interest-rate parity, and the mark-to-market value of an existing forward position.

equity_fwd = forward_price(100.0, 0.05, 1.0)
fx_fwd = fx_forward_price(18.0, 0.07, 0.04, 1.0)
long_fwd_value = forward_contract_value(105.0, 100.0, 0.05, 0.01, 0.5)

print(f"Equity forward price:        {equity_fwd:.4f}")
print(f"FX forward price:            {fx_fwd:.4f}")
print(f"Long forward contract value: {long_fwd_value:.4f}")
Equity forward price:        105.1271
FX forward price:            18.5482
Long forward contract value: 6.9453

5. Exotic options

A sample of closed-form exotic payoffs: digitals, geometric Asians, a down-and-out barrier, and an exchange (Margrabe-style) option.

exotic_prices = {
    "cash_or_nothing_call": cash_or_nothing_options(100.0, 100.0, 10.0, 1.0, 0.05, 0.20),
    "asset_or_nothing_call": asset_or_nothing_options(100.0, 100.0, 1.0, 0.05, 0.20),
    "geometric_asian_call": geometric_asian_options(100.0, 100.0, 1.0, 0.05, 0.20),
    "down_and_out_call": down_and_out_barrier_option(100.0, 100.0, 80.0, 1.0, 0.05, 0.20),
    "exchange_option": exchange_options(100.0, 95.0, 0.01, 0.02, 0.20, 0.25, 0.4, 1.0),
}
for name, price in exotic_prices.items():
    print(f"{name:24s}: {price:.4f}")
cash_or_nothing_call    : 5.3232
asset_or_nothing_call   : 63.6831
geometric_asian_call    : 5.5468
down_and_out_call       : 10.3513
exchange_option         : 6.8970

6. Composable option strategies

OptionStrategy lets you build multi-leg strategies (spreads, straddles, condors, …) and inspect payoff, profit, and break-even diagnostics.

strategy = OptionStrategy.bull_call_spread(
    lower_strike=100.0,
    upper_strike=115.0,
    lower_premium=6.0,
    upper_premium=2.0,
)
table = strategy.profile(points=6)
table[["spot_price", "gross_payoff", "net_profit"]].head()
spot_price gross_payoff net_profit
0 0.0 0.0 -4.0
1 46.0 0.0 -4.0
2 92.0 0.0 -4.0
3 138.0 15.0 11.0
4 184.0 15.0 11.0
print(f"Profit at spot=125:  {strategy.payoff(125.0):.4f}")
print(f"Maximum profit:      {strategy.max_profit():.4f}")
print(f"Maximum loss:        {strategy.max_loss():.4f}")
print(f"Break-even point(s): {strategy.break_even_points()}")
Profit at spot=125:  11.0000
Maximum profit:      11.0000
Maximum loss:        -4.0000
Break-even point(s): [104.0]

A legacy dictionary-based strategy helper is also available for quick one-off payoff tables:

legacy_table = strategy_profile(
    spot=100.0,
    legs=[
        {"option_type": "call", "position": 1, "strike": 100.0, "premium": 6.0},
        {"option_type": "call", "position": -1, "strike": 115.0, "premium": 2.0},
    ],
    points=4,
)
legacy_table[["S_T", "Net Payoff"]]
S_T Net Payoff
0 50.000000 -4.0
1 83.333333 -4.0
2 116.666667 11.0
3 150.000000 11.0

Takeaway

This covers the core vanilla, tree-based, forward, exotic, and strategy-building blocks in abaquant.derivatives. For advanced stochastic models (Heston, SABR, Merton jump-diffusion, NIG, Variance-Gamma), see notebook 03 — Derivatives: Advanced Models.