iPython Cookbook - Analytic Pricing

A collection of various analytic pricing formulas, to be added to as and when needed


In [148]:
import numpy as np
import matplotlib.pyplot as plt

Black Scholes Pricing - Simple

European Call Option

In the below formula, $K$ is the option strike, and $T$ its maturity (in years). $df$ and $F$ are the discount factor to maturity and the forward at maturity respectively (in absence of dividends / foreign interest $df\times F$ equals the spot price), and $\sigma$ is the annualised volatility (eg 0.2 for 20%)

$$ \begin{eqnarray} \mathrm{Call}(K,T; df,F,\sigma) &=& df \times (F N(d_1) - K N(d_2)) \\ d_1 &=& \frac{\ln (F/K) + 0.5 \sigma^2 T}{\sigma \sqrt{T}} \\ d_2 &=& \frac{\ln (F/K) - 0.5 \sigma^2 T}{\sigma \sqrt{T}} \end{eqnarray} $$

In [149]:
from scipy.stats import norm

def bscall(strike=100,mat=1,fwd=100,sig=0.1,df=1):
    lnfs = log(1.0*fwd/strike)
    sig2t = sig*sig*mat
    sigsqrt = sig*sqrt(mat)
    d1 = (lnfs + 0.5 * sig2t) / sigsqrt
    d2 = (lnfs - 0.5 * sig2t) / sigsqrt
    fv = fwd * norm.cdf (d1) - strike * norm.cdf (d2)
    return df * fv

bscall(fwd=100, strike=100, sig=0.1, mat=1, df=1)


Out[149]:
3.987761167674492

European Put Option

In the below formula, $K$ is the option strike, and $T$ its maturity (in years). $df$ and $F$ are the discount factor to maturity and the forward at maturity respectively (in absence of dividends / foreign interest $df\times F$ equals the spot price), and $\sigma$ is the annualised volatility (eg 0.2 for 20%)

$$ \begin{eqnarray} \mathrm{Put}(K,T; df,F,\sigma) &=& df \times (K N(-d_2) - F N(-d_1)) \\ d_1 &=& \frac{\ln (F/K) + 0.5 \sigma^2 T}{\sigma \sqrt{T}} \\ d_2 &=& \frac{\ln (F/K) - 0.5 \sigma^2 T}{\sigma \sqrt{T}} \end{eqnarray} $$

In [150]:
from scipy.stats import norm

def bsput(strike=100,mat=1,fwd=100,sig=0.1,df=1):
    lnfs = log(1.0*fwd/strike)
    sig2t = sig*sig*mat
    sigsqrt = sig*sqrt(mat)
    d1 = (lnfs + 0.5 * sig2t) / sigsqrt
    d2 = (lnfs - 0.5 * sig2t) / sigsqrt
    fv = strike * norm.cdf (-d2) - fwd * norm.cdf (-d1)
    return df * fv

bsput(fwd=100, strike=100, sig=0.1, mat=1, df=1)


Out[150]:
3.987761167674492

European Digital

The standard European digital call option pays one unit of the currency if and only if the spot price at expiry as above the strike $K$, ie the payoff is a step function. The price is given by the following formula ($d_2$ is defined as above) $$ \mathrm{DCall}(K,T;df,F,\sigma)=df\times N(d_2) $$ The price for a digitial put is $df\times(1-N(d_2))$


In [151]:
from scipy.stats import norm

def bsdcall(strike=100,mat=1,fwd=100,sig=0.1,df=1):
    lnfs = log(1.0*fwd/strike)
    sig2t = sig*sig*mat
    sigsqrt = sig*sqrt(mat)
    d2 = (lnfs - 0.5 * sig2t) / sigsqrt
    fv = norm.cdf(d2)
    return df * fv

def bsdput(strike=100,mat=1,fwd=100,sig=0.1,df=1):
    lnfs = log(1.0*fwd/strike)
    sig2t = sig*sig*mat
    sigsqrt = sig*sqrt(mat)
    d2 = (lnfs - 0.5 * sig2t) / sigsqrt
    fv = 1.0 - norm.cdf(d2)
    return df * fv

bsdcall(fwd=100, strike=100, sig=0.1, mat=1, df=1), bsdput(fwd=100, strike=100, sig=0.1, mat=1, df=1)


Out[151]:
(0.48006119416162751, 0.51993880583837249)

The reverse European digital call option pays one unit of the underlying asset if and only if the spot price at expiry as above the strike $K$. The price is given by the following formula ($d_1$ is defined as above) $$ \mathrm{RDCall}(K,T;df,F,\sigma)=df\times F \times N(d_1) $$ The price for the corresponding put is as above. Note that in the absence of dividends / foreign interest $df\times F=S$


In [152]:
from scipy.stats import norm

def bsdrcall(strike=100,mat=1,fwd=100,sig=0.1,df=1):
    lnfs = log(1.0*fwd/strike)
    sig2t = sig*sig*mat
    sigsqrt = sig*sqrt(mat)
    d1 = (lnfs + 0.5 * sig2t) / sigsqrt
    fv = fwd * norm.cdf (d1)
    return df * fv

def bsdrput(strike=100,mat=1,fwd=100,sig=0.1,df=1):
    lnfs = log(1.0*fwd/strike)
    sig2t = sig*sig*mat
    sigsqrt = sig*sqrt(mat)
    d1 = (lnfs + 0.5 * sig2t) / sigsqrt
    fv = fwd * (1.0 - norm.cdf (d1))
    return df * fv

bsdrcall(fwd=100, strike=100, sig=0.1, mat=1, df=1), bsdrput(fwd=100, strike=100, sig=0.1, mat=1, df=1)


Out[152]:
(51.993880583837246, 48.006119416162754)

Licence and version

Copyright Stefan Loesch / oditorium 2014; all rights reserved

License: AGPL v3.0


In [160]:
import sys
print(sys.version)


3.4.0 (default, Apr 11 2014, 13:05:11) 
[GCC 4.8.2]

In [160]: