Full documentation is available at https://option-combos.readthedocs.io/
This package computes Black Scholes options values and Greeks for options and option combos with a number of valuable features:
The functions cover a comprehensive set of Greeks:
The first order Greeks include (a) several variants of delta including delta driftless, delta forward and delta dual, (b) rho’s with respect to domestic and foreign interest rates, (c) theta per day and vega per percentage point change in volatility.
Important second order Greeks including gamma, gamma dual, vanna, volga and charm
The most useful third order Greek, color
Since the asset is allowed to pay a continuous dividend yield, foreign currency options, options on futures and options on stock indices are covered.
Values and Greeks can be computed for an array of options (using a Pandas DataFrame).
The package handles a portfolio of options (option combinations) where different options are held long or short positions with different weights. The aggregate value and Greeks can be computed for the entire portfolio.
Option portfolios can contain forward contracts and zero coupon bonds. For example, a portfolio might include self financing strategies like buying a call option and investing the present value of the exercise price in a zero coupon bond.
It is very easy to create common option combinations. For example, a straddle can be created in a single line as
straddle = combo.call(K=100) + combo.put(K=100)
and a butterfly can be created asbutterfly = combo.call(K=90) + combo.call(K=110) - 2 * combo.call(K=100)
. This illustrates the following features enabled by operator overloading:Option combinations can be created by “adding” two options (combos)
Short options are created by using a negative sign
Weights can be assigned by simply multiplying an option (combo) by the weight.
Plotting functions are provided to plot payoffs, profits, values and Greeks of various options (combos).
Multiple Greeks of a single combo can be plotted on a single graph. For example, the gamma, vega and theta of a butterfly can be overlaid in a single plot.
Different things can be plotted in different plots in a grid in the same figure. For example, the payoff and profit of a strangle can be shown in one plot, and the delta in a separate plot by the side.
The same Greek can be plotted for different combos in a single plot. This allows, for example, the gamma of a straddle and a strangle to be compared in a single plot.
Interactive plot that includes sliders for changing the strikes of each option. For example, an interactive plot of a butterfly can help choose the high, mid and low strikes to achieve a desired option price or gamma/vega/theta profile.
Basic Black Scholes¶
- option_combos.GBS.mywhere(condition, x, y)¶
same as numpy.where except it works with scalars as well
This function uses numpy.where if numpy array is received else it uses a simple if else
- class option_combos.GBS.GBS(S=None, K=None, sigma=None, ttm=None, r=None, q=None, optType=None)¶
A Black Scholes Option class
Important methods include ‘value’ for option value as well as various Greeks like ‘delta’, ‘gamma’, ‘volga’, ‘vanna’
- Parameters:
S (float or numpy array) – The current market price of the underlying This can be changed subsequently using the set_S method
K (float or numpy array) – The strike price of the option
sigma (float or numpy array) – The annualized volatility in decimal (0.25 for 25%)
ttm (float or numpy array) – Time to maturity in years
r (float or numpy array) – The (domestic) risk free rate This is continuously compounded annualized, and in decimal
q (float or numpy array, optional) – The dividend yield or foreign risk free rate This is continuously compounded annualized, and in decimal
optType (instrument.call [+1] or instrument.put [-1], optional) – Whether call or put option
Notes
If any of the parameters is a numpy array, the class instance behaves like an array of options and all its methods return a numpy array of values.
- pre_compute()¶
Precompute elements of option pricing and greek formulas
Called from __init__, set_S and set_X. Should be called after changing any option parameter. The following are precomputed: d1, d2, N(+/-d1), N(+/-d2) DFr and DFq (the discount factors) Fwd (forward price)
- set_S(S)¶
Change market price of underlying. Then call pre_compute
- set_K(K)¶
Change strike price of option. Then call pre_compute
- set_ttm(ttm)¶
Change maturity of option. Then call pre_compute
- set_sigma(sigma)¶
Change volatility of option. Then call pre_compute
- set_r(r)¶
Change risk free rate of option. Then call pre_compute
- set_q(q)¶
Change dividend yield of option. Then call pre_compute
- value()¶
Compute the option value (NPV is an alias for value)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().value().round(10) 2.423056836
>>> GBS(S=101, ttm=1).NPV().round(10) 9.823259516
>>> sigmas = numpy.array([15, 20, 25]) / 100 >>> GBS(S=101, sigma=sigmas, ttm=1).value().round(8) ... array([ 7.94559796, 9.82325952, 11.71625574])
- NPV()¶
Compute the option value (NPV is an alias for value)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().value().round(10) 2.423056836
>>> GBS(S=101, ttm=1).NPV().round(10) 9.823259516
>>> sigmas = numpy.array([15, 20, 25]) / 100 >>> GBS(S=101, sigma=sigmas, ttm=1).value().round(8) ... array([ 7.94559796, 9.82325952, 11.71625574])
- payoff(ST=None)¶
Compute the option payoff
- Parameters:
ST (float or numpy array or None (for self.S)) – The market price of the underlying at maturity
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> prices = numpy.array([99, 100, 101]) >>> GBS(S=101, ttm=1).payoff(prices) array([0, 0, 1]) >>> GBS(S=101, ttm=1, optType=instrument.put).payoff(prices) array([1, 0, 0])
- profit(ST=None)¶
Compute the option profit
- Parameters:
ST (float or numpy array) – The market price of the underlying at maturity
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> prices = numpy.array([99, 100, 101]) >>> GBS(S=101, ttm=1).profit(prices).round(6) array([-9.82326, -9.82326, -8.82326]) >>> GBS(S=101, ttm=1, optType=instrument.put).profit(prices).round(6) array([-4.946136, -5.946136, -5.946136])
- Delta()¶
Compute the option delta (dV/dS)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).Delta().round(8) 0.60558311
- DeltaFwd()¶
Compute the option delta dV/dF where F is the forward price
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).DeltaFwd().round(8) 0.58768543
- DeltaDriftless()¶
Compute the option delta (dV/dS) without drift
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).DeltaDriftless().round(8) 0.6178167
- DeltaDual()¶
Compute the option dual delta (dV/dK)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).DeltaDual().round(8) -0.51340635
- Theta()¶
Compute the option theta (dV/dt). Divide by 365 to get daily theta. Note t = -ttm
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).Theta().round(8) -5.11977695
- Theta_daily()¶
Compute the option theta (dV/dt) with t in days not years. Note t = -ttm
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).Theta_daily().round(8) -0.01402679
- Vega()¶
Compute the option vega (dV/dsigma). Divide by 100 to get vega per 1% change in sigma
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().Vega().round(8) 11.4673916
- Vega_percent()¶
Compute the option vega (dV/dsigma) per 1% change in sigma
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().Vega_percent().round(8) 0.11467392
- RhoD()¶
Compute the option rho (dV/dr). Divide by 100 to get RhoD per 1% change in r
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().RhoD().round(8) 4.19712579
- RhoF()¶
Compute the option foreign rho or psi (dV/dq). Divide by 100 to get RhoF per 1% change in q.
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().RhoF().round(8) -4.39904719
- Gamma()¶
Compute the option gamma (d^2V/dS^2)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).Gamma().round(8) 0.0185081
- GammaDual()¶
Compute the option dual gamma (d^2V/dK^2)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).GammaDual().round(8) 0.01888012
- Charm()¶
Compute the option charm (d^2V / dS dt) or (d delta / dt) or (d theta / dS). Note t = -ttm
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).Charm().round(8) -0.02532113
- Vanna()¶
Compute the option vanna (d^2V / dsigma dS) or (d vega / d dS) or (d delta / d sigma)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).Vanna().round(8) -0.1864676
- Volga()¶
Compute the option volga (d^2V/dsigma^2)
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS(S=101, ttm=1).Volga().round(8) 5.6452911
- Color()¶
Compute the option color (d^3V / dttm dS^2) or (d gamma / d ttm). Note this is ttm not t.
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().Color().round(8) -0.41635232
- option_combos.GBS.GBSImplied(price, S=None, K=None, ttm=None, r=None, q=None, optType=None)¶
Compute Black Scholes implied volatility
- Parameters:
P (option price (premium)) –
S (float or numpy array) – The current market price of the underlying This can be changed subsequently using the set_S method
K (float or numpy array) – The strike price of the option
ttm (float or numpy array) – Time to maturity in years
r (float or numpy array) – The (domestic) risk free rate This is continuously compounded annualized, and in decimal
q (float or numpy array, optional) – The dividend yield or foreign risk free rate This is continuously compounded annualized, and in decimal
optType (instrument.call [+1] or instrument.put [-1], optional) – Whether call or put option
- Return type:
float
Examples
>>> 100 * round(GBSImplied(price=3), 6) 25.0308
Extended Black Scholes with bonds and forwards¶
- class option_combos.GBSx.GBSx(S=None, K=None, sigma=None, ttm=None, r=None, q=None, instrumentType=None)¶
An extended Black Scholes class that includes bond and forward/futures
Modifies methods like ‘NPV’, ‘delta’, ‘gamma’, ‘volga’, ‘vanna’ inherited from GBS to handle bond and forward/futures
- Parameters:
S (float or numpy array) – The current market price of the underlying
K (float or numpy array) – The strike price of the option
sigma (float or numpy array) – The annualized volatility in decimal (0.25 for 25%)
ttm (float or numpy array) – Time to maturity in years
r (float or numpy array) – The (domestic) risk free rate This is continuously compounded annualized, and in decimal
q (float or numpy array, optional) – The dividend yield or foreign risk free rate This is continuously compounded annualized, and in decimal
instrumentType (int) –
instrument.call: call option
instrument.put: put option
instrument.bond: zero coupon face value=K, maturity=ttm
instrument.forward: forward contract to buy at K
- instrument.exposure: an unhedged exposure
(for example input purchase) this is a long or short zero strike call except that no premium has been received only profit() method is modified for this
- value()¶
Compute the instrument value (NPV is an alias for value)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(K=100, ttm=1, r=numpy.array([0, 0.05, 0.20]), ... instrumentType=instrument.bond ... ).value().round(6) array([100. , 95.122942, 81.873075])
>>> GBSx(K=numpy.array([90, 100, 110]), ttm=1, ... instrumentType=instrument.forward ... ).value().round(6) array([12.409219, 2.896925, -6.615369])
>>> GBSx(K=numpy.array([90, 100, 110]), ttm=1, ... instrumentType=instrument.exposure ... ).value().round(6) array([0, 0, 0])
- NPV()¶
Compute the instrument value (NPV is an alias for value)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(K=100, ttm=1, r=numpy.array([0, 0.05, 0.20]), ... instrumentType=instrument.bond ... ).value().round(6) array([100. , 95.122942, 81.873075])
>>> GBSx(K=numpy.array([90, 100, 110]), ttm=1, ... instrumentType=instrument.forward ... ).value().round(6) array([12.409219, 2.896925, -6.615369])
>>> GBSx(K=numpy.array([90, 100, 110]), ttm=1, ... instrumentType=instrument.exposure ... ).value().round(6) array([0, 0, 0])
- payoff(ST=None)¶
Compute the portfolio payoff
- Parameters:
ST (float or numpy array or None (for self.S)) – The market price of the underlying at maturity
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> prices = numpy.array([99, 100, 101]) >>> GBSx(S=101, ttm=1).payoff(prices) array([0, 0, 1])
>>> GBSx(instrumentType=instrument.bond).payoff() 100
>>> GBSx(instrumentType=instrument.forward).payoff(110) 10
- profit(ST=None)¶
Compute the portfolio profit
- Parameters:
ST (float or numpy array or None (for self.S)) – The market price of the underlying at maturity
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> prices = numpy.array([99, 100, 101]) >>> GBSx(S=101, ttm=1).profit(prices).round(6) array([-9.82326, -9.82326, -8.82326]) >>> GBSx(S=101, ttm=1, instrumentType=instrument.put).profit( ... prices).round(6) array([-4.946136, -5.946136, -5.946136])
- Delta()¶
Compute the portfolio delta (dV/dS)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).Delta().round(8) 0.60558311 >>> GBSx(instrumentType=instrument.forward).Delta().round(6) 0.998335
Bond has zero delta >>> GBSx(instrumentType=instrument.bond).Delta() 0
- DeltaFwd()¶
Compute the portfolio delta dV/dF where F is the forward price
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(instrumentType=instrument.forward).DeltaFwd().round(6) 0.995842 >>> GBSx(S=101, ttm=1).DeltaFwd().round(8) 0.58768543
- DeltaDriftless()¶
Compute the portfolio delta (dV/dS) without drift
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).DeltaDriftless().round(8) 0.6178167
Driftless delta of forward is exactly 1
>>> GBSx(instrumentType=instrument.forward).DeltaDriftless() 1
- DeltaDual()¶
Compute the portfolio dual delta (dV/dK)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).DeltaDual().round(8) -0.51340635
- Theta()¶
Compute the portfolio theta (dV/dt).
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).Theta().round(8) -5.11977695
Most Greeks of a bond are zero, but theta is non zero
>>> GBSx(instrumentType=instrument.bond).Theta().round(6) 4.97921
- Theta_daily()¶
Compute the option theta (dV/dt) with t in days not years. Note t = -ttm
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).Theta_daily().round(8) -0.01402679
- Vega()¶
Compute the option vega (dV/dsigma). Divide by 100 to get vega per 1% change in sigma
- Return type:
float or numpy array (depending on the GBS inputs)
Examples
>>> GBS().Vega().round(8) 11.4673916
Forward has zero vega
>>> GBSx(instrumentType=instrument.forward).Vega() 0
- Vega_percent()¶
Compute the option vega (dV/dsigma) per 1% change in sigma
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBS().Vega_percent().round(8) 0.11467392
- RhoD()¶
Compute the option rho (dV/dr). Divide by 100 to get RhoD per 1% change in r
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx().RhoD().round(8) 4.19712579
- RhoF()¶
Compute the option foreign rho or psi (dV/dq). Divide by 100 to get RhoF per 1% change in q.
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx().RhoF().round(8) -4.39904719
- Gamma()¶
Compute the portfolio gamma (d^2V/dS^2)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).Gamma().round(8) 0.0185081
Forward has zero gamma
>>> GBSx(instrumentType=instrument.forward).Gamma() 0
- GammaDual()¶
Compute the portfolio dual gamma (d^2V/dK^2)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).GammaDual().round(8) 0.01888012
- Charm()¶
Compute the portfolio charm (d^2V / dS dt) or (d delta / dt) or (d theta / dS). Note t = -ttm
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).Charm().round(8) -0.02532113
- Vanna()¶
Compute the portfolio vanna (d^2V / dsigma dS) or (d vega / d dS) or (d delta / d sigma)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).Vanna().round(8) -0.1864676
- Volga()¶
Compute the portfolio volga (d^2V/dsigma^2)
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx(S=101, ttm=1).Volga().round(8) 5.6452911
- Color()¶
Compute the portfolio color (d^3V / dttm dS^2) or (d gamma / d ttm). Note this is ttm not t.
- Return type:
float or numpy array (depending on the GBSx inputs)
Examples
>>> GBSx().Color().round(8) -0.41635232 >>> GBSx(instrumentType=instrument.forward).Color() 0
Option Portfolios¶
- class option_combos.portfolio.option_portfolio(S, K, sigma, ttm, r, q=0, instrumentType=1, weight=1)¶
A Black Scholes Option Portfolio class
Modifies methods like ‘NPV’, ‘delta’, ‘gamma’, ‘volga’, ‘vanna’ inherited from GBSx to compute the value for the portfolio
- Parameters:
S (float or numpy array) – The current market price of the underlying
K (float or numpy array) – The strike price of the option
sigma (float or numpy array) – The annualized volatility in decimal (0.25 for 25%)
ttm (float or numpy array) – Time to maturity in years
r (float or numpy array) – The (domestic) risk free rate This is continuously compounded annualized, and in decimal
q (float or numpy array, optional) – The dividend yield or foreign risk free rate This is continuously compounded annualized, and in decimal
instrumentType (instrument.call, instrument.put etc.) – Whether call or put option or other instrument
weight (float or numpy array) – Number of options in the portfolio (long if positive, short if negative)
Notes
It is intended that one or all of the parameters is a numpy array. Otherwise, the base class GBSx should be adequate
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1])
This portfolio is used in all the examples below for this class
- value()¶
Compute the portfolio value (NPV is an alias for value)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.value().round(6) 25.804862
Verify by taking each option separately
>>> p.weight [2, 1] >>> GBSx.value(p).round(6) array([8.918504, 7.967853])
- NPV()¶
Compute the portfolio value (NPV is an alias for value)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.value().round(6) 25.804862
Verify by taking each option separately
>>> p.weight [2, 1] >>> GBSx.value(p).round(6) array([8.918504, 7.967853])
- payoff(ST=None)¶
Compute the portfolio payoff
- Parameters:
ST (float or numpy array or None (for self.S)) – The market price of the underlying at maturity
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.payoff() 2
Verify by taking each option separately
>>> p.weight [2, 1] >>> GBSx.payoff(p) array([1, 0])
- profit(ST=None)¶
Compute the portfolio profit
- Parameters:
ST (float or numpy array or None (for self.S)) – The market price of the underlying at maturity
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.profit(ST=110).round(6) 5.195138
Verify by taking each option separately
>>> p.weight [2, 1] >>> (GBSx.payoff(p, ST=110) - GBSx.value(p)).round(6) array([2.081496, 1.032147])
- Delta()¶
Compute the portfolio delta (dV/dS)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Delta().round(6) 1.698643
Verify by taking each option separately
>>> p.weight [2, 1] >>> GBSx.Delta(p).round(6) array([0.579358, 0.539926])
- DeltaFwd()¶
Compute the portfolio delta dV/dF where F is the forward price
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.DeltaFwd().round(6) 1.681741
- DeltaDriftless()¶
Compute the portfolio delta (dV/dS) without drift
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.DeltaDriftless().round(6) 1.698643
- DeltaDual()¶
Compute the portfolio dual delta (dV/dK)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.DeltaDual().round(6) -1.44594
- Theta()¶
Compute the portfolio theta (dV/dt).
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Theta().round(6) -13.230481
- Theta_daily()¶
Compute the portfolio theta (dV/dt). t is in days not years
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Theta_daily().round(6) -0.036248
- Vega()¶
Compute the option vega (dV/dsigma). Divide by 100 to get vega per 1% change in sigma
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Vega().round(6) 117.898867
- Vega_percent()¶
Compute the option vega (dV/dsigma) per 1% change in sigma
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Vega_percent().round(6) 1.178989
- RhoD()¶
Compute the option rho (dV/dr). Divide by 100 to get RhoD per 1% change in r
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.RhoD().round(6) 144.059404
- RhoF()¶
Compute the portfolio foreign rho or psi (dV/dq).
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.RhoF().round(6) -169.864267
- Gamma()¶
Compute the portfolio gamma (d^2V/dS^2)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Gamma().round(6) 0.058949
- GammaDual()¶
Compute the portfolio dual gamma (d^2V/dK^2)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.GammaDual().round(6) 0.059352
- Charm()¶
Compute the portfolio charm (d^2V / dS dt) or (d delta / dt) or (d theta / dS). Note t = -ttm
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Charm().round(6) -0.078649
- Vanna()¶
Compute the portfolio vanna (d^2V / dsigma dS) or (d vega / d dS) or (d delta / d sigma)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Vanna().round(6) 0.196994
- Volga()¶
Compute the portfolio volga (d^2V/dsigma^2)
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Volga().round(6) -5.835487
- Color()¶
Compute the portfolio color (d^3V / dttm dS^2) or (d gamma / d ttm). Note this is ttm not t.
Examples
>>> p = option_portfolio(S=100, K=array([99, 101]), sigma=0.2, ... ttm=1, r=0.01, q=0, weight=[2, 1]) >>> p.Color().round(6) -0.030064
Option Combos¶
- class option_combos.combos.combo(df, name='', ksigmas=None, S0=None, sigma0=None)¶
A Black Scholes Option Combo class
Inherits methods like ‘NPV’, ‘delta’, ‘gamma’, ‘volga’, ‘vanna’ from option_portfolio (ultimately from GBS)
Instance Variables¶
- dfPandas DataFrame containing combo data
(see documentation of __init__)
- namestring
Combo name used in __repr__ and in the plots
- ksigmasfloat
Width of x-axis (in standard deviations) in plots
Constructors¶
The __init__ constructor is not intended to be used directly. The following static methods are easier to use:
- general constructor
combo.combo(K, [instrumentType], [weight], [ttm], [name])
- specific constructors
combo.call(K, [ttm], [name]): call option
combo.put(K, [ttm], [name]): put option
combo.forward(K, [ttm], [name]): forward contract
combo.underlying(): call option with zero strike
combo.exposure(): same as underlying but with value set to 0
ZC_Bond(FV, [ttm], [name]): zero coupon bond
Overloaded Operators¶
‘+’ create new combo containing the positions of two combos
‘-’ (unary minus) new combo is short the first combo
‘-’ (subtraction) new combo is long first combo and short second combo
- ‘*’ (scalar multiply) left term is a float and second term is a combo
creates new combo with positions multiplied by the number
New Methods¶
- The new methods (not inherited from option_portfolio) are:
set_name: set (change) the name of the combo
set_one_strike: change one of the strikes used to change striked interactively
plot_payoff: plots payoff and optionally profit and value This is a wrapper around plot_any
plot_any: plots any set of quantities (value, greeks)
plot_interactive: plots_any with sliders
- set_name(newname)¶
Change name of combo
- Parameters:
newname (string) – new name of combo
- Return type:
Examples
- set_one_strike(i, newk)¶
Change strike of one instrument in the combo
- Parameters:
i (int) – row number of instrument to change
newk (float) – new strike
- Return type:
Examples
- static combo(K, instrumentType=1, weight=1, ttm=None, name='', component_names=None)¶
Convenience constructor without DataFrame as argument
- Parameters:
K (float or array of floats) – strike price
instrumentType (int) – type of instrument (e.g. instrument.put)
weight (float) – number of options (negative number for ttm)
ttm (float) – time to maturity in years
name (string) – name of the combo
component_names (string) – name of the component
- Return type:
Examples
- static call(K=None, ttm=None, name=None, instrumentType=1)¶
Construct combo with only one call option
- Parameters:
K (float) – strike price
ttm (float) – time to maturity in years
name (string or None) – name of combo
instrumentType (int) – type of instrument (e.g. instrument.call or instrument.exposure)
- Return type:
Examples
>>> combo.call(120) combo: Call@120
- static put(K=None, ttm=None, name=None)¶
Construct combo with only one put option
- Parameters:
K (float) – strike price
ttm (float) – time to maturity in years
name (string or None) – name of combo
- Return type:
Examples
>>> combo.put(90) combo: Put@90
- static underlying(name=None)¶
Construct combo of only one zero strike forward (underlying)
- Parameters:
name (string or None) – name of combo
- Return type:
Examples
>>> combo.underlying() combo: Underlying
- static exposure(name=None)¶
Construct combo of only one exposure to underlying
- Parameters:
name (string or None) –
- Return type:
Examples
>>> combo.exposure() combo: Exposure
- static ZC_Bond(FV=None, ttm=None, name=None)¶
Construct combo of only one zero coupon bond
- Parameters:
FV (float) – face value of bond
ttm (float) – maturity in years
name (string) – name of combo
- Return type:
Examples
>>> combo.ZC_Bond(FV=100,ttm=3) combo: 3Y Bond (100)
- static forward(K=None, ttm=None, name=None)¶
Construct combo with only one forward contract
- Parameters:
K (float) – strike price of forward
ttm (float) – time to maturity in years
name (string or None) – name of combo
- Return type:
Examples
>>> combo.forward(105) combo: Forward@105
- decomposition()¶
Return list of combos consisting of this combo and its components
- Return type:
list of combos
Examples
>>> (combo.call(100) - combo.put(100)).decomposition() [combo: Call@100, combo: -Put@100, combo: Call@100-Put@100]
- compute(flist, extra_strikes=[])¶
- Parameters:
flist (list of strings) – each string is the name of a combo method For example, [‘combo.NPV’, ‘comb.payoff’, ‘combo.Delta’] Values returned by this method are plotted
extra_strikes (list of float) – additional dummy strikes to include while setting x axis limits These are passed on to the _make_S_array method
- Returns:
This DataFrame has one column for each string in flist Each column contains the payoff, profit, value or greek of combo for the set of set of underlying prices returned by _make_S_array
- Return type:
Pandas DataFrame
Examples
>>> combo.call(100).compute(['payoff']).round(2) ... payoff 82.679492 0.00 99.000000 0.00 100.000000 0.00 101.000000 1.00 117.320508 17.32
- plot_any(flist, axis=None, title=None, xlabel='Asset Price', ylabel=None, legend=True, strikes=True, spot=True, name_mapping=None, extra_strikes=[], ylim=None)¶
Plot one graph (payoff, premium or greek) for one combo
- Parameters:
flist (list of strings) – each string is the name of a combo method For example, [‘combo.NPV’, ‘comb.payoff’, ‘combo.Delta’] Values returned by this method are plotted
axis (matplotlib Axis object or None) – matplotlib Axis object to be used for plotting. If None, plt.gca() is used
title (string or None) – If not None, this is used as the title for plot
xlabel (string) – X axis label
ylabel (string) – Y axis label
legend (boolean) – If True, plot includes legend
strikes (boolean) – whether to draw vertical lines at the strikes
spot (boolean) – whether to draw vertical lines at the current spot
name_mapping (Dictionary) – maps method names of this class to label in plots
extra_strikes (list of float) – additional dummy strikes to include while setting x axis limits These are passed on to the compute method
ylim (tuple of two floats) – lower and upper bounds on the y-axis to override defaults useful to force same axes in different plots
- Returns:
This DataFrame has one column for each string in flist Each column contains the payoff, profit, value or greek of combo for the set of set of underlying prices returned by _make_S_array
- Return type:
Pandas DataFrame
- plot_payoff(profit=True, value=False, axis=None, title=None, xlabel='Asset Price', ylabel=None, legend=True, strikes=True, spot=True, name_mapping=None, extra_strikes=[], ylim=None)¶
Plot payoff (and optionally profit and value) of combo
- Parameters:
profit (boolean) – if True, profit is also plotted
value (boolean) – if True, value is also plotted
axis (matplotlib Axis object or None) – matplotlib Axis object to be used for plotting. If None, plt.gca() is used
title (string or None) – If not None, this is used as the title for plot
xlabel (string) – X axis label
ylabel (string) – Y axis label
strikes (boolean) – whether to draw vertical lines at the strikes
spot (boolean) – whether to draw vertical lines at the current spot
legend (boolean) – If True, plot includes legend
name_mapping (Dictionary) – maps method names of this class to label in plots
extra_strikes (list of float) – additional dummy strikes to include while setting x axis limits These are passed on to the compute method
ylim (tuple of two floats) – lower and upper bounds on the y-axis to override defaults useful to force same axes in different plots
- Returns:
This DataFrame has one column for each string in flist Each column of this DataFrame contains payoff/profit/value for the set of underlying prices returned by _make_S_array
- Return type:
Pandas DataFrame
- plot_many(fl_list=None, layout=None, title=None, xlabel='Asset Price', ylabel=None, legend=True, strikes=True, spot=True, name_mapping=None, extra_strikes=[], ylim=None)¶
- Plot many graphs for same combo
for different variables (payoff, premium, greeks)
- Parameters:
Combo (instrument or bundle) –
fl_list (list) – This is a list of sublists of function names. Each sublist is plotted in a separate subplot by calling plot_any method. Each function is a combo method.
layout (tuple of two ints or None) – nr and nc arguments to the matplotlib add_subplot command If None, an automatic choice is made
title (string or None) – If not None, this is used as the title for plot
xlabel (string) – X axis label
ylabel (string) – Y axis label
strikes (boolean) – whether to draw vertical lines at the strikes
spot (boolean) – whether to draw vertical lines at the current spot
legend (boolean) – If True, plot includes legend
name_mapping (Dictionary) – maps method names of this class to label in plots
- interactive_plot(flist, title=None, xlabel='Asset Price', ylabel=None, inplace=False, legend=True, strikes=True, spot=True, name_mapping=None, extra_strikes=[], ylim=None)¶
Interactive plot with sliders to change strikes
- Parameters:
flist (list of strings) – each string is the name of a combo method For example, [‘NPV’, ‘payoff’, ‘Delta’] Values returned by this method are plotted
title (string or None) – If not None, this is used as the title for plot
xlabel (string) – X axis label
ylabel (string) – Y axis label
inplace (boolean) – if False, a copy of the combo is used so that the interactive sliders do not alter the original combo
legend (boolean) – If True, plot includes legend
strikes (boolean) – whether to draw vertical lines at the strikes
spot (boolean) – whether to draw vertical lines at the current spot
name_mapping (Dictionary) – maps method names of this class to label in plots
extra_strikes (list of float) – additional dummy strikes to include while setting x axis limits These are passed on to the compute method
ylim (tuple of two floats) – lower and upper bounds on the y-axis to override defaults useful to force same axes in different plots
inplace – if False, a copy of the combo is used so that the interactive sliders do not alter the original combo
- Returns:
This is original combo if inplace is False Else it is the interactively altered combo
- Return type:
- plot_decomposition(flist=None, layout=None, name_mapping=None)¶
- Plot graphs of same variables (payoff, premium, greeks)
for combo and its components
- Parameters:
flist (list of string) – Each string is name of a GBSx method whose result is plotted.
layout (tuple of two ints or None) – nr and nc arguments to the matplotlib add_subplot command If None, an automatic choice is made
name_mapping (Dictionary) – maps method names of this class to label in plots
- option_combos.combos.plot_many_combos(combos, flist=None, layout=None, decompose=True, title=None, xlabel='Asset Price', ylabel=None, legend=True, strikes=True, spot=True, name_mapping=None)¶
- Plot graphs of same variables (payoff, premium, greeks)
for different combos
- Parameters:
combos (combo or list of combos) –
flist (list of string) – Each string is name of a GBSx method whose result is plotted.
layout (tuple of two ints or None) – nr and nc arguments to the matplotlib add_subplot command If None, an automatic choice is made
decompose (boolean) – If True and combos is a single combo (not a list), the combo is decomposed into components and each component is plotted
title (string or None) – If not None, this is used as the title for plot
xlabel (string) – X axis label
ylabel (string) – Y axis label
strikes (boolean) – whether to draw vertical lines at the strikes
spot (boolean) – whether to draw vertical lines at the current spot
legend (boolean) – If True, plot includes legend
name_mapping (Dictionary) – maps method names of this class to label in plots
Default values¶
- class option_combos.defaults.defaults¶
Default values for GBS/GBSx constructors and combo plots
The first set of defaults allow a GBS or GBSx class to be instantiated without giving values for any arguments.
The second set of defaults provide default settings for plotting a combo
- S = 100¶
default value for current market price of the underlying
- K = 100¶
default value for Strike price
- sigma = 0.2¶
Annualized volatility in decimal (0.25 for 25%)
- months = 0.08333333333333333¶
convert months into years in option maturity
- days = 0.0027397260273972603¶
convert days into years in option maturity
- ttm = 0.08333333333333333¶
Default time to maturity in years
- r = 0.05¶
(Domestic) risk free rate, decimal annlzd cont. compounded
- q = 0.02¶
Dividend yield or foreign risk free rate dec annlzd cont comp
- instrumentType = 1¶
default instrument type
- instrumentType_name = 'call'¶
default instrument type by name
- ksigmas = 3¶
default Width of x-axis (in standard deviations) in plots
- nlinspace = 20¶
by default x-axis includes 2*nlinspace+1 points between end points
- name_mapping = {}¶
Dictionary to rename method names to label in plots
- payoff_only = ['payoff']¶
fl_list argument for plot_many to plot only payoff
- payoff = ['payoff', 'profit']¶
fl_list argument for plot_many to plot payoff and profit
- value = ['value', 'payoff']¶
fl_list argument for plot_many to plot payoff and value
- profit_value = ['payoff', 'profit', 'value']¶
fl_list argument for plot_many to plot payoff profit and value
- greeks = [['Delta'], ['Gamma'], ['Vega'], ['Theta']]¶
fl_list argument for plot_many to plot greeks
- all_list = [['payoff', 'profit'], ['value', 'payoff'], ['Delta'], ['Gamma'], ['Vega'], ['Theta']]¶
fl_list argument for plot_many to plot payoff value and greeks
- all_list2 = [['payoff'], ['value', 'payoff'], ['Delta'], ['Gamma'], ['Vega'], ['Theta']]¶
fl_list argument for plot_many to plot payoff and greeks
Merton Model for Credit Risk¶
- option_combos.merton_model.merton(DebtBV, maturity, r, DivYld=0, frequency=inf, Assets=nan, sigmaA=nan, EquityMV=nan, DebtMV=nan, DebtYTM=nan, CreditSpread=nan, coupon=nan, index_from_Series=False)¶
Merton (structural) credit model.
- Given data on two of the following variables, compute the third
debt market value, YTM and credit spread, or
equity market value, or
asset volatility
- Parameters:
DebtBV (None or float or sequence) – The book value of the Debt
maturity (float or sequence) – Maturity of zero coupon debt in years
r (float or sequence) – The risk free rate This is annualized, and in percent
DivYld (float or sequence) – The dividend yield This is annualized, and in percent
frequency (integer or np.Inf or sequence) – The frequency of compounding of interest rates and spreads
Assets (None or float or sequence) – The current market price of the assets of the firm
sigmaA (None or float or sequence) – The annualized asset volatility in percent
EquityMV (None or float or sequence) – The market value of the equity
DebtMV (None or float or sequence) – The market value of the debt
DebtYTM (None or float or sequence) – The yield to maturity of the debt
CreditSpread (None or float or sequence) – The credit spread of the debt in basis points
coupon (None or float or sequence) – The coupon rate on the debt annualized, and in percent. If None, the risk free rate is assumed. Face value of zero coupon debt is computed by assuming that the coupon is compounded and paid at maturity. If DebtBV is already the face value of zero coupon debt, provide an explicit coupon rate if 0.
index_from_Series (boolean) – if true the returned DataFrame is indexed with the index of the first Pandas Series among the input arguments
- Returns:
Input variables and model values of other variables
- Return type:
Pandas DataFrame
Notes
If both debt market and equity market information are given, sigmaA is calibrated from the given data. If sigmaA and information from either debt or equity market is given, the asset value is calibrated from the given information and then data for the missing market is computed. Equity market information is given as EquityMV Debt market information can be given as DebtMV, DebtYTM or CreditSpread
EWMA Volatility Estimation¶
- option_combos.EWMA.EWMA(df, input_name='Price', vol_name='Sigma', ret_name='lnret', input_is_price=True, Lambda=0.94, burn_in=20, sigma_init=None, sigma_init_sample=20, inplace=True)¶
Compute time varying historical volatility using EWMA method.
EWMA (Exponentially Weighted Moving Average) is also sometimes called the RiskMetrics method (because it was first popularized by Riskmetrics) or the IGarch (Integrated Garch) method (because it is similar to the Garch method except that the volatility is assumed to follow a unit root process instead of being a stationary process).
- Parameters:
df (Pandas DataFrame) – One column must contain prices/returns and the index must be the date
input_name (string) – Column name of df that contains price/return
vol_name (string) – Column name of df in which to store estimated volatitlity
ret_name (string) – Column name of df in which to store returns (if input is price)
input_is_price (boolean) – Whether the input column is price (True) or return (False)
Lambda (float) – Smoothing parameter of exponential moving average
burn_in (int) – Number of initial values of volatility to be set to nan
sigma_init (float or None) – Initial volatility (if None sample volatility is used)
sigma_init_sample (int) – Length of initial sample to compute initial volatility (used only if sigma_init is None)
inplace (boolean) – If true df is modified in place and returned. Else copy is made
- Returns:
Input DataFrame with added column(s) containing the estimated volatility and if necessary the log return
- Return type:
Pandas DataFrame
Check analytical Greeks numerically¶
- option_combos.GBS_greek_test.check(S, K, sigma, ttm, r, q, optType, delta=1e-06, tolerance=5e-05, verbose=True)¶
Check analytic greeks of a specific option by numerical differentiation
- Parameters:
S (float) – The current market price of the underlying
K (float) – The strike price of the option
sigma (float) – The annualized volatility in decimal (0.25 for 25%)
ttm (float) – Time to maturity in years
r (float) – The (domestic) risk free rate This is continuously compounded annualized, and in decimal
q (float) – The dividend yield or foreign risk free rate This is continuously compounded annualized, and in decimal
optType – instrument.call, instrument.put, instrument.forward, instrument.bond
delta (float) – numerical differentiation uses values delta apart
tolerance (float) – tolerance for discrepancy between analytic and numerical derivative (discrepancy is regarded as significant only if both absolute and relative error must exceed this tolerance)
verbose (boolean) – if true error details are printed
- Returns:
int
- Return type:
error count (number of greeks with discrepancy > tolerance)
Examples
>>> check(S=93.112533, K=106.693664, sigma=0.260802, ... ttm=108.625926, r=0.072272, q=0.073218, optType=instrument.put, ... delta=1e-6, tolerance=5e-5, verbose=True) ... RhoD=-4.180261. Numl=-4.180501. abserr=0.000240. relerr=0.000057 1 errors in excess of 5e-05 1
- option_combos.GBS_greek_test.test_GBS_greeks_by_numerical_differentiation(delta=1e-06, tolerance=5e-05, samplesize=50, verbose=True)¶
Check analytic Greeks of a random sample of options by numerical differentiation
- Parameters:
delta (float) – numerical differentiation uses values delta apart
tolerance (float) – tolerance for discrepancy between analytic and numerical derivative
samplesize (int) – number of options (random sample) to be checked
verbose (boolean) – if true error details are printed
- Returns:
first element is the number of options which had at least one greek with discrepancy exceeding tolerance, second element is the total number of greeks across all options that had discrepancy exceeding tolerance
- Return type:
tuple of two ints
Notes
S and K are sampled from normal distribution with mean=100 and sd=10
r and q are sampled from normal distribution with mean=5% and sd=3%
ln(sigma) is sampled from normal distribution with mean=-1.5 and sd=0.5
ln(ttm) is sampled from normal distribution with mean=0 and sd=2
the instrument type is sampled from [call, put, forward, bond] with probabilities [35%, 35%, 15%, 15%].