otc — OTC Instrument Pricing
The otc module prices the OTC structured products that SIP Global
structures around its commodity indices. All functions are pure analytics —
they compute NPV and Greeks given a forward curve. Position management
is handled by schema.OTCPosition and book.
Instrument selection by cluster:
import sipQuant as sq
import numpy as np
commoditySwap()
Fixed-float commodity swap. The fixed payer pays fixedPrice * notional
per period; the floating receiver pays the index value. NPV is computed as
the sum of discounted cashflow differences across all payment periods.
where \(F_i\) is the forward index price at payment date \(t_i\), \(K\) is the fixed price, and \(N\) is notional.
# Forward curve prices from commodity.localForwardCurve
index_curve = np.array([187.50, 189.00, 190.50, 192.00])
schedule = np.array([0.25, 0.50, 0.75, 1.00])
swap = sq.otc.commoditySwap(
fixedPrice=190.0,
indexCurve=index_curve,
notional=1000.0, # tonnes
schedule=schedule,
r=0.046,
)
print(f"NPV: ${swap['npv']:,.2f}")
print(f"Fixed leg PV: ${swap['fixedLegPV']:,.2f}")
print(f"Float leg PV: ${swap['floatLegPV']:,.2f}")
print(f"Delta: {swap['greeks']['delta']:.4f}")
print(f"DV01: {swap['greeks']['dv01']:.4f}")
Parameters
fixedPrice— float. Fixed leg price K.indexCurve— array-like, length n. Floating index prices at each payment date.notional— float. Contract notional.schedule— array-like, length n. Payment tenors in years.r— float. Flat discount rate (continuous).
Returns — dict: npv, fixedLegPV, floatLegPV, greeks (delta, dv01).
asianSwap()
Arithmetic average price swap. The floating leg pays the arithmetic mean of index prices observed over the averaging period. Averaging reduces the risk of price manipulation in thin markets — preferred over a point-in-time swap for all SIP index products.
where \(\bar{F}\) is the arithmetic mean of indexPrices.
# Weekly index observations over the averaging period
index_prices = np.array([185.0, 186.5, 187.0, 188.5, 187.5, 189.0, 188.0, 190.0])
asian_swap = sq.otc.asianSwap(
fixedPrice=187.0,
indexPrices=index_prices,
notional=500.0,
r=0.046,
T=0.25, # 3-month contract
)
print(f"NPV: ${asian_swap['npv']:,.2f}")
print(f"Average index: {asian_swap['averageIndex']:.2f}")
Parameters
fixedPrice— float.indexPrices— array-like. Observed or projected index prices over the averaging period.notional— float.r— float.T— float. Maturity in years.
Returns — dict: npv, averageIndex, fixedPrice, dv01.
collar()
Long cap (call) + short floor (put) using Black-Scholes analytics. Net collar price = cap premium − floor premium. Used to provide buyers price protection while capping upside participation.
collar_result = sq.otc.collar(
S=187.50, # current spot
capStrike=200.0, # buyer pays no more than $200/tonne
floorStrike=175.0, # seller receives no less than $175/tonne
T=0.50, # 6-month
r=0.046,
sigma=0.18, # 18% implied vol — typical for thin ag markets
notional=1000.0,
q=0.028, # convenience yield acts as dividend yield
)
print(f"Net collar price: ${collar_result['price']:,.2f}")
print(f"Cap premium: ${collar_result['capPrice']:,.2f}")
print(f"Floor premium: ${collar_result['floorPrice']:,.2f}")
print(f"Net delta: {collar_result['greeks']['delta']:.4f}")
Parameters
S— float. Spot price.capStrike— float. Cap (call) strike.floorStrike— float. Floor (put) strike.T— float. Time to expiry in years.r— float. Risk-free rate.sigma— float. Volatility.notional— float. Default 1.0.q— float. Continuous dividend / convenience yield.
Returns — dict: price, capPrice, floorPrice, greeks (delta, gamma, vega, theta, rho).
physicalForward()
Present value of a physically-settled forward contract, adjusted for storage costs and quality premium. The primary instrument for Cluster E (by-products), Cluster G (minerals), and Cluster S (construction materials) where the trade is a direct physical commitment rather than an index-linked instrument.
# Physical forward for Saskatchewan wheat straw delivery
fwd_result = sq.otc.physicalForward(
F=95.00, # forward price $/tonne
deliveryTenor=0.50, # 6-month delivery
r=0.046,
storageCost=0.015, # outdoor straw storage
qualityPremium=3.50, # premium for baled vs. loose straw
notional=200.0, # tonnes
)
print(f"PV: ${fwd_result['pv']:,.2f}")
print(f"Delta: {fwd_result['greeks']['delta']:.4f}")
Parameters
F— float. Forward/futures price.deliveryTenor— float. Time to delivery in years.r— float. Risk-free rate.storageCost— float. Annualised storage cost rate.qualityPremium— float. Quality/grade premium on top of F.notional— float. Contract notional.
Returns — dict: pv, forwardPrice, adjustedForward, greeks (delta, dv01).
swaption()
Swaption priced with Black’s formula on the forward swap rate.
A payer swaption (optType='call') gives the right to enter a fixed-price
swap as the fixed-price payer. Used when a counterparty wants optionality on
locking in a future index swap.
swaption_result = sq.otc.swaption(
fixedPrice=190.0,
indexCurve=index_curve,
notional=1000.0,
schedule=schedule,
r=0.046,
sigma=0.18,
T=0.25, # swaption expires in 3 months
optType='call', # payer swaption
)
print(f"Swaption price: ${swaption_result['price']:,.2f}")
print(f"Forward swap rate: {swaption_result['forwardSwapRate']:.2f}")
print(f"Vega: {swaption_result['greeks']['vega']:.4f}")
Parameters
fixedPrice— float. Fixed rate of the underlying swap.indexCurve— array-like. Forward index prices.notional— float.schedule— array-like. Payment tenors.r— float. Discount rate.sigma— float. Black volatility.T— float. Swaption expiry (must be ≤schedule[0]).optType— str.'call'(payer) or'put'(receiver).
Returns — dict: price, forwardSwapRate, annuity, greeks (delta, vega, theta).
asianOption()
Arithmetic-average Asian option priced by Monte Carlo simulation with antithetic variates for variance reduction. Use for exotic payoffs where the settlement is based on the average index over a period rather than a point-in-time price.
asian_opt = sq.otc.asianOption(
S=187.50,
K=190.0,
T=0.50,
r=0.046,
sigma=0.18,
nSims=50000,
nSteps=26, # 26 fortnightly steps = 6 months
optType='call',
q=0.028,
seed=42,
)
print(f"Price: ${asian_opt['price']:.4f}")
print(f"Stderr: {asian_opt['stderr']:.4f}")
print(f"Delta: {asian_opt['greeks']['delta']:.4f}")
print(f"Vega: {asian_opt['greeks']['vega']:.4f}")
Parameters
S— float. Spot price.K— float. Strike price.T— float. Maturity in years.r— float. Risk-free rate.sigma— float. Volatility.nSims— int. Simulation paths (antithetic: half base + half mirror). Default 10000.nSteps— int. Averaging time steps. Default 50.optType— str.'call'or'put'.q— float. Convenience yield.seed— int or None. RNG seed for reproducibility.
Returns — dict: price, stderr, greeks (delta, vega).
Note
Greeks are computed via finite difference (1% bump for delta, +0.01 for vega).
For production Greeks, use nSims >= 50000 to reduce finite-difference noise.