2
$\begingroup$

I am trying to run a delta-gamma hedge for a Black-Scholes model in Python.The Euler disceretizatioin of the paths is the simplest possible. I wrote the code below but the PnL looks undesirable and wrong.

I have 2 Options: The one that I am going short and an additional option with a longer maturity (1.5) for the hedge.

#install pandas
import math
import numpy as np
import scipy as sp
import numpy.random as npr  
import scipy.stats as scs
import matplotlib.pyplot as plt
import numpy.random as npr
import seaborn
seaborn.set_style("ticks")

%matplotlib inline

np.set_printoptions(suppress=True)

# sets the plotting style

#--------------------------

#functions 
def callprice(S,K,T,sigma,r):
    d1=(sp.log(S/K) + (r + 0.5 * sigma**2)*T) / (sigma * sp.sqrt(T))
    d2=(sp.log(S/K) + (r - 0.5 * sigma**2)*T) / (sigma * sp.sqrt(T))
    return S*scs.norm.cdf(d1) - math.exp(-r *T) * K * scs.norm.cdf(d2)

def deltafunc(S, K, T, sigma, r):
    d1=(sp.log(S/K) + (r + 0.5 * sigma**2)*T) / (sigma * sp.sqrt(T))
    return scs.norm.cdf(d1) 

def gamma(S, K, T, sigma, r):
    d1=(sp.log(S/K) + (r + 0.5 * sigma**2)*T) / (sigma * sp.sqrt(T))
    return scs.norm.pdf(d1) / (S * sigma * sp.sqrt(T))


S0 = 100
k  = 100 
K2 = 100 
T1 = 1   # time to maturity
T2 = 1.1 # time to maturity
sigma = 0.2 # vola
n = 10000 # number of simulations
m = 252  # number of realisations of stock
r = 0.05 # interest rate
dt = T1/m

s = np.zeros([n,m+1])
w = npr.standard_normal([n,m])
ttm1 = T1- np.arange(1, m+1, 1)/m
ttm2 = T2- np.arange(1, m+1, 1)/m
s[:,0] = S0

#simple Euler discretization of GBM

for i in range(1,m+1):
    s[:,i] = s[:,i-1]*((1 + r*dt) + sigma / np.sqrt(252) * w[:,i-1])

#Computation of greeks

bscall  = np.zeros([n,m+1])
deltabs = np.zeros([n,m+1])
gamma1  = np.zeros([n,m+1])
gamma2  = np.zeros([n,m+1])
delta2 = np.zeros([n,m+1])
ttm     = np.arange(1, m+1, 1)/m
mu = r


bscall[:,0]     = callprice(S0, k, T1, sigma, mu)
deltabs[:,0]    = deltafunc(S0, k, T1, sigma, mu)

#delta gamma
gamma1[:,0] = gamma(s[:,0], k, T1, sigma, mu)
gamma2[:,0] = gamma(s[:,0], k, T2, sigma, mu)
delta2[:,0] = deltafunc(s[:,0], k, T2, sigma, mu)

for i in range(1,m+1):
    bscall[:,i]  = callprice(s[:,i], k, T1-ttm[i-1], sigma, mu)
    deltabs[:,i] = deltafunc(s[:,i], k, T1-ttm[i-1], sigma, mu)
    gamma1[:,i]  = gamma(s[:,i], k, T1-ttm[i-1], sigma, mu)
    gamma2[:,i] = gamma(s[:,i], k, T2-ttm[i-1], sigma, mu)
    delta2[:,i] = deltafunc(s[:,i], k, T2-ttm[i-1], sigma, mu)

#coef between gammas 
h2 = gamma1/gamma2

#delta rebalance
strategy = deltabs - delta2*h2

#initialization
st               = s[:,0]
amount           = callprice(s[:,0], k, T1, sigma, mu)
delta            = deltabs[:,0] - delta2[:,0]*gamma1[:,0]/gamma2[:,0]
gammacoef        = gamma1[:,0]/gamma2[:,0]
Pnl              = amount - delta*st - gamma1[:,0]/gamma2[:,0]*callprice(s[:,0], k, T2, sigma, mu)
interest         = np.exp(r * dt)

for i in range(1, m):
    Pnl          = interest * Pnl
    newdelta     = deltabs[:,i] - delta2[:,i]*gamma1[:,i]/gamma2[:,i]
    newgammacoef = gamma1[:,i]/gamma2[:,i]
    Pnl          = Pnl - ((newdelta-delta)*s[:,i] + (newgammacoef-gammacoef)*callprice(s[:,i], k, T2-ttm[i-1], sigma, r))
    delta        = newdelta
    gammacoef    = newgammacoef

Pnl              = Pnl * interest

PnL_final        = Pnl + strategy[:,-2] * s[:,-1] + gamma1[:,-2]/gamma2[:,-2]*callprice(s[:,-1], k, T2-ttm[-1], sigma, r)/interest - np.max(s[:,-1]-k,0) 
PnL_final2       = [x/callprice(s[0,0], k, T1, sigma, mu) for x in PnL_final]


print(PnL_final)

plt.hist(PnL_final)
$\endgroup$
3
  • 1
    $\begingroup$ your np.max(s[:,-1]-k,0) might be incorrect, try something like np.maximum(s[:,-1] - k, np.zeros(n)) $\endgroup$ Commented Aug 25, 2019 at 12:46
  • $\begingroup$ Your euler discretization is wrong. Where did you take it from? $\endgroup$
    – will
    Commented Feb 7, 2020 at 22:59
  • 1
    $\begingroup$ I’m voting to close this question because it is primarily about code failure and code review. $\endgroup$
    – Attack68
    Commented Apr 6 at 6:21

2 Answers 2

1
$\begingroup$

I think your problem is here: T1-ttm[i-1] (or T2). Rather it should be just ttm[i-1].

In your code time to maturity increases with time, it obviously should be the other way around.

$\endgroup$
0
$\begingroup$

Problem is at the tail of this: PnL_final = Pnl + strategy[:,-2] * s[:,-1] + gamma1[:,-2]/gamma2[:,-2]*callprice(s[:,-1], k, T2-ttm[-1], sigma, r)/interest - np.max(s[:,-1]-k,0)

It should be a "+ np.max(s[:,-1]-k,0)" not "- np.max(s[:,-1]-k,0)". More basic error includes that the cost of this strategy is NOT just the premium of the call options, but also the margin required for short spot or capital to buy spot when doing delta-hedging part. Also, the second call option also requires capital to cover it varying premium on the way of gamma rebalancing.

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.