Option Pricing Techniques¶
As with other option pricing techniques Monte Carlo methods are used to price options using what is essentially a three step process.
- Step 1: Simulate potential price paths of the underlying asset.
- Step 2: Calculate the option payoff for each of these price paths.
- Step 3: Average the payoff and discount back to today to determine the option price.
Applying Euler discretization of SDE, we get
$$ S_{t+\delta t} = S_t * \left(1+r\delta t + \sigma \sqrt{\delta t} w_t \right) $$
# Import Required Libraries
import pandas as pd
from numpy import *
import scipy.stats as ss
# Set max row to 300
pd.set_option('display.max_rows', 300)
# Libraries for plotting
import matplotlib.pyplot as plt
import cufflinks as cf
cf.set_config_file(offline=True)
# Ignore warnings
import warnings
warnings.filterwarnings('ignore')
# line color and style for plots
dash_styles = ['solid', 'dash']*5
color_styles = sorted(['black', 'brightblue', 'brightred', 'green', 'darkviolet'] * 2)
# define simulation function
def simulate_path(s0, mu, sigma, horizon, timesteps, n_sims):
# set the seed
random.seed(2023)
# read the params
S0 = s0
r = mu
T = horizon
t = timesteps
n = n_sims
# define dt
dt = T/t
# Simulating 'n' asset price paths with 't' timesteps
S = zeros((t+1, n))
S[0] = S0
for i in range(1, t+1):
z = random.standard_normal(n) # psuedo random numbers
S[i]=S[i-1]+r*S[i-1]*dt+sigma * sqrt(dt)*S[i-1]*z # Euler-Maruyama scheme
return S
# Assign simulated price path to dataframe for analysis and plotting
price_path = pd.DataFrame(simulate_path(100,0.05,0.2,1,252,100000))
# Verify the generated price paths
price_path.head()
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 99990 | 99991 | 99992 | 99993 | 99994 | 99995 | 99996 | 99997 | 99998 | 99999 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | ... | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 |
1 | 100.916466 | 99.611029 | 98.757603 | 100.317489 | 99.891132 | 98.581948 | 103.364080 | 101.834833 | 100.144446 | 96.087080 | ... | 100.526533 | 98.860239 | 98.837148 | 100.039456 | 98.913105 | 99.580159 | 99.246204 | 99.383916 | 98.362717 | 100.002582 |
2 | 101.102047 | 99.252871 | 98.060186 | 100.326270 | 98.603518 | 100.717457 | 104.176433 | 100.222994 | 101.468809 | 95.026936 | ... | 101.555214 | 97.144692 | 99.130006 | 100.251700 | 97.617909 | 99.474348 | 98.328044 | 100.179019 | 98.775283 | 99.668132 |
3 | 100.572272 | 100.383399 | 98.151705 | 100.305081 | 100.957863 | 101.003838 | 105.040394 | 96.817626 | 100.584172 | 93.812262 | ... | 100.687368 | 95.671818 | 98.864215 | 100.339384 | 98.261258 | 101.356891 | 97.348343 | 100.076692 | 98.885967 | 98.173543 |
4 | 100.103597 | 100.482743 | 99.225147 | 100.341161 | 100.908313 | 100.437038 | 104.973611 | 96.873934 | 99.199344 | 92.857468 | ... | 103.588192 | 96.954031 | 100.491272 | 99.724911 | 98.236881 | 100.712394 | 97.737062 | 99.770981 | 97.046760 | 97.968690 |
5 rows × 100000 columns
# Plot the histogram of the simulated price path at maturity
price_path.iloc[-1].hist(bins=100)
plt.ylabel('frequency')
plt.xlabel('Asset price at maturity')
plt.title('Histogram of the simulated price path at maturity')
plt.xlim(0, 400)
plt.show()
# Plot simulated price paths,1-20th
price_path.iloc[:,:20].iplot(title='Simulated Underlying Asset Price Paths', xTitle='Time Steps', yTitle='Price')
A call option gives the holder of the option the right to buy the asset at a pre-defined price. A call buyer makes money if the price of the asset at maturity, denoted by ST , is above the strike price K, otherwise it’s worth nothing.
$ C_T = max(0,S_T −K) $
The price of an option using a Monte Carlo simulation is the expected value of its future payoff. So at any date before maturity, denoted by t, the option’s value is the present value of the expectation of its payoff at maturity, T.
$ C = PV (E[max(0,S_T −K)]) $
Under the risk-neutral framework, we assume the asset is going to earn, on average, the risk-free interest rate. Hence, the option value at time t would simply be the discounted value of the expected payoff.
$ C = e^{-r(T-t)} * (E[max(0, S_T - K)]) $
Asian and Look back options are path-dependent options. The discounted value of the expected pay off will be
$C = e^{-r(T-t)}(E[max(0,S_{\text{Avg}} −K)])$ for Asian options
$C = e^{-r(T-t)}(E[max(0,S_{\text{max}} −K)])$ for Lookback options or
$C = e^{-r(T-t)}(E[max(0,S_{\text{min}} −K)])$ for Lookback options
I will be using $max$ for pricing Lookback options here.
def caculate_exotic_price(S_path,sampling_period,E,r,horizon):
S=S_path #simulated price path data
sp=sampling_period #sampling_period refers the days sampling once
T=horizon
final_price=S.iloc[-1] #final price at maturity
path_mean=S.iloc[sp::sp].mean(axis=0) # MEAN related to sample period
path_max=S.iloc[sp::sp].max(axis=0) # MAX related to sample period
path_min=S.iloc[sp::sp].min(axis=0) # MIN related to sample period
# Calculate the discounted value of the expeced payoff
#vanilla
C0 = exp(-r*T) * mean(maximum(final_price - E, 0))
P0 = exp(-r*T) * mean(maximum(E - final_price, 0))
#fixed Asian
fix_Asian_C = exp(-r*T) * mean(maximum(path_mean - E, 0))
fix_Asian_P = exp(-r*T) * mean(maximum(E - path_mean, 0))
# floating Asisn
float_Asian_C = exp(-r*T) * mean(maximum(path_mean - final_price, 0))
float_Asian_P = exp(-r*T) * mean(maximum(final_price - path_mean, 0))
# fixed look
fix_Lookback_C = exp(-r*T) * mean(maximum(path_max - E, 0))
fix_Lookback_P = exp(-r*T) * mean(maximum(E - path_min, 0))
# floating Lookback
float_Lookback_C = exp(-r*T) * mean(maximum(path_max - final_price, 0))
float_Lookback_P = exp(-r*T) * mean(maximum(final_price - path_min, 0))
# the calculated results are returned as a list
return [C0,P0, \
fix_Asian_C,fix_Asian_P, \
float_Asian_C,float_Asian_P,\
fix_Lookback_C,fix_Lookback_P,\
float_Lookback_C,float_Lookback_P]
# Assign simulated price path to dataframe for analysis and plotting
price_path = pd.DataFrame(simulate_path(100, 0.05, 0.20, 1, 252, 100000)) # timesteps=252 meaning simulating by days
# Verify the generated price paths
price_path.tail()
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 99990 | 99991 | 99992 | 99993 | 99994 | 99995 | 99996 | 99997 | 99998 | 99999 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
248 | 83.625902 | 75.827722 | 96.600573 | 103.596788 | 106.015185 | 147.020837 | 108.247054 | 86.245161 | 146.001810 | 98.963360 | ... | 104.219166 | 96.538980 | 104.257557 | 129.044406 | 83.385164 | 164.666929 | 83.411607 | 89.556030 | 61.695214 | 137.059986 |
249 | 82.015420 | 76.972786 | 96.294851 | 103.555391 | 106.868361 | 150.234926 | 107.513052 | 85.295482 | 148.012494 | 99.377709 | ... | 105.629601 | 96.199775 | 102.848104 | 128.312085 | 84.227749 | 164.295674 | 84.452631 | 89.853093 | 61.860018 | 138.444789 |
250 | 80.642913 | 76.783025 | 95.154389 | 105.616379 | 107.497258 | 149.945284 | 107.222721 | 86.734576 | 148.618368 | 98.820653 | ... | 107.406821 | 94.912560 | 102.935111 | 125.641846 | 83.604510 | 163.470033 | 83.007683 | 91.172556 | 61.333441 | 136.355664 |
251 | 80.782976 | 76.713537 | 94.691231 | 103.588088 | 108.632172 | 151.506379 | 107.393998 | 85.837756 | 147.199309 | 100.592983 | ... | 107.665608 | 96.874877 | 102.839756 | 122.933012 | 83.634889 | 163.939416 | 81.774788 | 91.142776 | 62.203926 | 137.327203 |
252 | 79.896474 | 76.152872 | 96.269968 | 102.360518 | 106.431434 | 153.371441 | 107.719045 | 86.611925 | 147.370448 | 98.748978 | ... | 107.623348 | 97.718515 | 102.937203 | 123.649104 | 85.340604 | 166.349697 | 80.660933 | 91.513198 | 63.571316 | 137.789066 |
5 rows × 100000 columns
variable_range=[1,5,21,63,126,252] #Sampling by 1 Day,1 Week,1 Month,1 quarter,semi-year,1 year
option_prices=[]# set a list to save data
for d in variable_range:
result_list=caculate_exotic_price(price_path,d,100,0.05,1) # for different sampling periods caculate extotic price
option_prices.append(result_list)# put caculate reslut into the list
df=pd.DataFrame(option_prices)# to dataframe
df.columns=["European Call", "European Put", \
"Fixed Asian Call", "Fixed Asian put",\
"Floating Asian Call","Floating Asian Put",\
"Fixed Lookback Call","Fixed Lookback Put",\
"Floating Lookback Call","Floating Lookback Put"]
df.index=variable_range
df.index.name="Sampling Period"
##################################### visualize ####################################################
df.iplot(title='Option price with change in sampling time', xTitle='Sampling Period in days', yTitle='Price',colors=color_styles, width=3, dash=dash_styles)
round(df, 2)# keep 4 decimals
European Call | European Put | Fixed Asian Call | Fixed Asian put | Floating Asian Call | Floating Asian Put | Fixed Lookback Call | Fixed Lookback Put | Floating Lookback Call | Floating Lookback Put | |
---|---|---|---|---|---|---|---|---|---|---|
Sampling Period | ||||||||||
1 | 10.5 | 5.58 | 5.82 | 3.38 | 3.38 | 5.85 | 18.39 | 11.76 | 13.45 | 16.63 |
5 | 10.5 | 5.58 | 5.86 | 3.40 | 3.37 | 5.82 | 17.34 | 11.01 | 12.42 | 15.79 |
21 | 10.5 | 5.58 | 6.19 | 3.56 | 3.20 | 5.48 | 15.81 | 9.81 | 10.38 | 13.93 |
63 | 10.5 | 5.58 | 6.98 | 3.93 | 2.81 | 4.68 | 13.81 | 8.26 | 7.39 | 10.73 |
126 | 10.5 | 5.58 | 8.16 | 4.49 | 2.20 | 3.44 | 12.23 | 7.00 | 4.40 | 6.88 |
252 | 10.5 | 5.58 | 10.50 | 5.58 | 0.00 | 0.00 | 10.50 | 5.58 | 0.00 | 0.00 |
variable_range=range(60,155,5)
option_prices=[]
for s0 in variable_range:
price_path = pd.DataFrame(simulate_path(s0, 0.05, 0.20, 1, 252, 100000)) # timesteps=252 meaning simulating by days
result_list=caculate_exotic_price(price_path,21,100,0.05,1)
option_prices.append(result_list)
##################################### make table ####################################################
df=pd.DataFrame(option_prices)
df.columns=["European Call", "European Put", \
"Fixed Asian Call", "Fixed Asian put",\
"Floating Asian Call","Floating Asian Put",\
"Fixed Lookback Call","Fixed Lookback Put",\
"Floating Lookback Call","Floating Lookback Put"]
df.index=variable_range
df.index.name="S0"
##################################### visualize ####################################################
df.iplot(title='Option price with change in S0', xTitle='S0', yTitle='Price',colors=color_styles, width=3, dash=dash_styles)
round(df, 2)
European Call | European Put | Fixed Asian Call | Fixed Asian put | Floating Asian Call | Floating Asian Put | Fixed Lookback Call | Fixed Lookback Put | Floating Lookback Call | Floating Lookback Put | |
---|---|---|---|---|---|---|---|---|---|---|
S0 | ||||||||||
60 | 0.06 | 35.16 | 0.00 | 36.47 | 1.92 | 3.29 | 0.07 | 43.46 | 6.23 | 8.36 |
65 | 0.18 | 30.28 | 0.00 | 31.58 | 2.08 | 3.56 | 0.23 | 39.16 | 6.75 | 9.06 |
70 | 0.45 | 25.55 | 0.01 | 26.71 | 2.24 | 3.83 | 0.61 | 34.85 | 7.26 | 9.75 |
75 | 0.99 | 21.08 | 0.08 | 21.88 | 2.40 | 4.11 | 1.36 | 30.55 | 7.78 | 10.45 |
80 | 1.89 | 16.98 | 0.28 | 17.20 | 2.56 | 4.38 | 2.66 | 26.24 | 8.30 | 11.15 |
85 | 3.25 | 13.34 | 0.79 | 12.82 | 2.72 | 4.66 | 4.67 | 21.94 | 8.82 | 11.84 |
90 | 5.13 | 10.22 | 1.84 | 8.99 | 2.88 | 4.93 | 7.52 | 17.65 | 9.34 | 12.54 |
95 | 7.56 | 7.64 | 3.62 | 5.87 | 3.04 | 5.20 | 11.25 | 13.51 | 9.86 | 13.24 |
100 | 10.50 | 5.58 | 6.19 | 3.56 | 3.20 | 5.48 | 15.81 | 9.81 | 10.38 | 13.93 |
105 | 13.91 | 3.99 | 9.52 | 2.00 | 3.36 | 5.75 | 20.94 | 6.85 | 10.90 | 14.63 |
110 | 17.71 | 2.80 | 13.45 | 1.04 | 3.52 | 6.03 | 26.36 | 4.67 | 11.42 | 15.33 |
115 | 21.84 | 1.92 | 17.80 | 0.50 | 3.68 | 6.30 | 31.86 | 3.13 | 11.93 | 16.02 |
120 | 26.22 | 1.30 | 22.41 | 0.23 | 3.84 | 6.57 | 37.37 | 2.07 | 12.45 | 16.72 |
125 | 30.78 | 0.86 | 27.17 | 0.10 | 4.00 | 6.85 | 42.90 | 1.34 | 12.97 | 17.42 |
130 | 35.49 | 0.56 | 32.00 | 0.04 | 4.16 | 7.12 | 48.42 | 0.86 | 13.49 | 18.11 |
135 | 40.29 | 0.37 | 36.86 | 0.01 | 4.32 | 7.39 | 53.94 | 0.55 | 14.01 | 18.81 |
140 | 45.16 | 0.24 | 41.74 | 0.01 | 4.48 | 7.67 | 59.46 | 0.34 | 14.53 | 19.51 |
145 | 50.08 | 0.15 | 46.63 | 0.00 | 4.64 | 7.94 | 64.98 | 0.21 | 15.05 | 20.20 |
150 | 55.03 | 0.09 | 51.51 | 0.00 | 4.80 | 8.22 | 70.50 | 0.13 | 15.57 | 20.90 |
price_path = pd.DataFrame(simulate_path(100, 0.05, 0.20, 1, 252, 100000)) # reset
variable_range=range(50,155,5)
option_prices=[]
for E in variable_range:
result_list=caculate_exotic_price(price_path,21,E,0.05,1)
option_prices.append(result_list)
##################################### make table ####################################################
df=pd.DataFrame(option_prices)
df.columns=["European Call", "European Put", \
"Fixed Asian Call", "Fixed Asian put",\
"Floating Asian Call","Floating Asian Put",\
"Fixed Lookback Call","Fixed Lookback Put",\
"Floating Lookback Call","Floating Lookback Put"]
df.index=variable_range
df.index.name="E"
##################################### visualize ####################################################
names=["European Call","European Put","Fixed Asian Call","Fixed Asian put","Fixed Lookback Call","Fixed Lookback Put"]
df=df[names]
df.iplot(title='Option price with change in E', xTitle='E', yTitle='Price',colors=color_styles, width=3, dash=['solid', 'dash','solid', 'dash','solid', 'dash'])
round(df, 2)
European Call | European Put | Fixed Asian Call | Fixed Asian put | Fixed Lookback Call | Fixed Lookback Put | |
---|---|---|---|---|---|---|
E | ||||||
50 | 52.48 | 0.00 | 50.19 | 0.00 | 62.85 | 0.00 |
55 | 47.72 | 0.00 | 45.44 | 0.00 | 58.10 | 0.00 |
60 | 42.97 | 0.01 | 40.68 | 0.00 | 53.34 | 0.02 |
65 | 38.25 | 0.04 | 35.93 | 0.00 | 48.58 | 0.06 |
70 | 33.58 | 0.13 | 31.17 | 0.00 | 43.83 | 0.18 |
75 | 29.01 | 0.32 | 26.43 | 0.02 | 39.07 | 0.48 |
80 | 24.63 | 0.69 | 21.73 | 0.08 | 34.32 | 1.07 |
85 | 20.51 | 1.33 | 17.19 | 0.28 | 29.56 | 2.14 |
90 | 16.74 | 2.32 | 12.95 | 0.80 | 24.82 | 3.85 |
95 | 13.39 | 3.72 | 9.23 | 1.84 | 20.16 | 6.38 |
100 | 10.50 | 5.58 | 6.19 | 3.56 | 15.81 | 9.81 |
105 | 8.07 | 7.91 | 3.91 | 6.03 | 12.03 | 13.99 |
110 | 6.09 | 10.69 | 2.32 | 9.20 | 8.95 | 18.57 |
115 | 4.51 | 13.87 | 1.30 | 12.93 | 6.54 | 23.29 |
120 | 3.29 | 17.40 | 0.69 | 17.08 | 4.69 | 28.05 |
125 | 2.36 | 21.22 | 0.35 | 21.50 | 3.32 | 32.80 |
130 | 1.67 | 25.29 | 0.17 | 26.07 | 2.32 | 37.56 |
135 | 1.16 | 29.54 | 0.08 | 30.74 | 1.60 | 42.31 |
140 | 0.80 | 33.94 | 0.03 | 35.45 | 1.09 | 47.07 |
145 | 0.55 | 38.44 | 0.01 | 40.19 | 0.74 | 51.83 |
150 | 0.37 | 43.02 | 0.01 | 44.93 | 0.49 | 56.58 |
variable_range=arange(0.05,0.40,0.01)
option_prices=[]
for Sig in variable_range:
price_path = pd.DataFrame(simulate_path(100, 0.05, Sig, 1, 252, 100000)) # timesteps=252 meaning simulating by days
result_list=caculate_exotic_price(price_path,21,100,0.05,1)
option_prices.append(result_list)
##################################### make table ####################################################
df=pd.DataFrame(option_prices)
df.columns=["European Call", "European Put", \
"Fixed Asian Call", "Fixed Asian put",\
"Floating Asian Call","Floating Asian Put",\
"Fixed Lookback Call","Fixed Lookback Put",\
"Floating Lookback Call","Floating Lookback Put"]
df.index=variable_range
df.index.name="sigma"
##################################### visualize ####################################################
df.iplot(title='Option price with change in Volatility ', xTitle='Vol', yTitle='Price',colors=color_styles, width=3, dash=dash_styles)
Heston model for stochastic volatility¶
The Heston process is described by the SDE:
$$ \begin{cases} dS_t = \mu S_t dt + \sqrt{v_t} S_t dW^1_t \\ dv_t = \kappa (\theta - v_t) dt + \sigma \sqrt{v_t} dW^2_t \end{cases}$$
The stock price follows a "geometric Brownian motion" with a stochastic volatility.
The parameters are:
- $\mu$ drift of the stock process
- $\kappa$ mean reversion coefficient of the variance process
- $\theta$ long term mean of the variance process
- $\sigma$ volatility coefficient of the variance process
- $\rho$ correlation between $W^1$ and $W^2$ i.e. $$ dW^1_t dW^2_t = \rho dt $$
We will also require that $2\kappa \theta > \sigma^2$ (Feller condition).
The Euler method can be obtained by using Ito's lemma $ln S_t$ $$ v_{t+dt} = v_t + \kappa(\theta - v_t)dt + \sigma\sqrt(v_t dt) Z_v \\ S_{t+dt} = S_t * exp((r - \frac{1}{2} v_t)dt + \sqrt(v_t dt) Z_s) $$
To generate $Z_v$ and $Z_S$ with correlation $\rho$ we generate two independent standard normal variable $Z_1$ and $Z_2$, and we set $Z_v = Z1$ and $Z_S = \rho Z_1 + \sqrt(1-\rho)^2 Z_2$.
To avoid negative variances we must apply the full truncation scheme by replacing $v_t$ everywhere with $|v_t|$.
# define simulation function for stochastic volatility
def simulate_path_sv(s0, mu, horizon, timesteps, n_sims, volvol, kappa, rho):
# set the seed
random.seed(2023)
# read the params
S0 = s0
r = mu
T = horizon
t = timesteps
n = n_sims
# define dt
dt = T/t
#rho = 0.6 # correlation coefficient
#kappa = 2 # mean reversion coefficient
theta = 0.04 # long-term variance
# simulate path
S = zeros((t+1,n))
S[0] = S0
v = zeros((t+1,n))
v[0] = 0.04
for i in range(1, t+1):
# Generate random Brownian Motion
z1 = random.standard_normal(n) # psuedo random numbers
z2 = random.standard_normal(n) # psuedo random numbers
W_v = z1
W_S = rho*z1 + sqrt(1 - rho*rho) * z2
# Euler discretization of v_t
v[i] = maximum( zeros(n), v[i-1] + kappa*(theta - v[i-1]) * dt + volvol * sqrt(v[i-1] * dt) * W_v)
# Euler discretization of SDE
S[i] = S[i-1] * exp( (r - 0.5*v[i-1])*dt + sqrt(v[i-1]*dt) * W_S)
return S
# Assign simulated price path to dataframe for analysis and plotting
price_path = pd.DataFrame(simulate_path_sv(100,0.05,1,252,100000, 0.4, 2, 0.6))
# Verify the generated price paths
price_path.head()
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 99990 | 99991 | 99992 | 99993 | 99994 | 99995 | 99996 | 99997 | 99998 | 99999 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | ... | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 |
1 | 100.683448 | 99.464538 | 98.682492 | 100.181788 | 98.893757 | 100.870041 | 102.666231 | 99.818953 | 101.135151 | 96.805848 | ... | 101.124961 | 97.933658 | 99.524592 | 100.177686 | 98.299079 | 99.647838 | 98.799013 | 100.254826 | 99.339495 | 99.718520 |
2 | 99.945981 | 100.195158 | 99.531965 | 100.181610 | 100.256683 | 100.597858 | 103.173847 | 97.661437 | 99.479355 | 95.614572 | ... | 102.982239 | 98.070345 | 100.597226 | 99.724128 | 98.634632 | 100.245476 | 98.521237 | 99.944258 | 98.046813 | 98.645791 |
3 | 99.683888 | 99.338538 | 98.095665 | 101.008841 | 96.855748 | 100.345477 | 105.495043 | 97.603989 | 98.047109 | 95.489134 | ... | 103.794795 | 98.220274 | 101.982000 | 99.122856 | 100.905605 | 100.589018 | 97.021455 | 101.100073 | 96.274585 | 96.454135 |
4 | 99.194870 | 98.447574 | 97.498160 | 98.997072 | 97.945392 | 100.191981 | 108.018307 | 97.304107 | 99.697690 | 95.448173 | ... | 103.380656 | 98.186150 | 101.988699 | 100.195150 | 100.468666 | 98.715772 | 94.380848 | 103.317409 | 96.351390 | 96.440158 |
5 rows × 100000 columns
# Plot the histogram of the simulated price path at maturity
price_path.iloc[-1].hist(bins=100)
plt.ylabel('frequency')
plt.xlabel('Asset price at maturity with stochatic volatility model')
plt.title('Histogram of the simulated price path at maturity')
plt.xlim(0, 400)
plt.show()
price_path.iloc[:,:20].iplot(title='Simulated Underlying Asset Price Paths with stochastic volatility assumption', xTitle='Time Steps', yTitle='Price')
variable_range=arange(0.00,1,0.1)
option_prices=[]
for v in variable_range:
SV_price_path = pd.DataFrame(simulate_path_sv(s0=100, mu=0.05, horizon=1, timesteps=252, n_sims=100000, volvol=v, kappa=2, rho=0.6 ))
result_path=caculate_exotic_price(SV_price_path,21,100,0.05,1)
option_prices.append(result_path)
##################################### make table ####################################################
df=pd.DataFrame(option_prices)
df.columns=["European Call", "European Put", \
"Fixed Asian Call", "Fixed Asian put",\
"Floating Asian Call","Floating Asian Put",\
"Fixed Lookback Call","Fixed Lookback Put",\
"Floating Lookback Call","Floating Lookback Put"]
df.index=variable_range
df.index.name="vol of vol"
##################################### visualize ####################################################
df.iplot(title='Option price with change in vol of vol', xTitle='vol of vol', yTitle='Price',colors=color_styles, width=3, dash=dash_styles)
round(df, 2)
European Call | European Put | Fixed Asian Call | Fixed Asian put | Floating Asian Call | Floating Asian Put | Fixed Lookback Call | Fixed Lookback Put | Floating Lookback Call | Floating Lookback Put | |
---|---|---|---|---|---|---|---|---|---|---|
vol of vol | ||||||||||
0.0 | 10.45 | 5.58 | 6.18 | 3.55 | 3.21 | 5.45 | 15.75 | 9.80 | 10.36 | 13.88 |
0.1 | 10.38 | 5.51 | 6.15 | 3.51 | 3.18 | 5.42 | 15.96 | 9.54 | 10.57 | 13.65 |
0.2 | 10.26 | 5.38 | 6.10 | 3.45 | 3.11 | 5.35 | 16.07 | 9.20 | 10.66 | 13.32 |
0.3 | 10.11 | 5.22 | 6.03 | 3.37 | 3.01 | 5.24 | 16.08 | 8.79 | 10.65 | 12.91 |
0.4 | 9.92 | 5.03 | 5.94 | 3.28 | 2.88 | 5.11 | 15.99 | 8.35 | 10.53 | 12.48 |
0.5 | 9.76 | 4.85 | 5.85 | 3.18 | 2.76 | 5.00 | 15.86 | 7.96 | 10.39 | 12.10 |
0.6 | 9.64 | 4.72 | 5.77 | 3.09 | 2.69 | 4.93 | 15.78 | 7.67 | 10.29 | 11.81 |
0.7 | 9.58 | 4.65 | 5.71 | 3.02 | 2.65 | 4.90 | 15.78 | 7.48 | 10.27 | 11.63 |
0.8 | 9.57 | 4.64 | 5.67 | 2.98 | 2.66 | 4.91 | 15.85 | 7.39 | 10.35 | 11.54 |
0.9 | 9.60 | 4.66 | 5.65 | 2.96 | 2.69 | 4.94 | 16.00 | 7.36 | 10.49 | 11.52 |
variable_range=arange(-1,1.1,0.1)
option_prices=[]
for p in variable_range:
SV_price_path = pd.DataFrame(simulate_path_sv(s0=100, mu=0.05, horizon=1, timesteps=252, n_sims=100000, volvol=0.4, kappa=2, rho=p ))
result_path=caculate_exotic_price(SV_price_path,21,100,0.05,1)
option_prices.append(result_path)
##################################### make table ####################################################
df=pd.DataFrame(option_prices)
df.columns=["European Call", "European Put", \
"Fixed Asian Call", "Fixed Asian put",\
"Floating Asian Call","Floating Asian Put",\
"Fixed Lookback Call","Fixed Lookback Put",\
"Floating Lookback Call","Floating Lookback Put"]
df.index=variable_range.round(1)
df.index.name="rho"
##################################### visualize ####################################################
df.iplot(title='Option price with change in Correlation Coefficient', xTitle='Correlation Coefficient', yTitle='Prices',colors=color_styles, width=3, dash=dash_styles)
round(df, 2)
European Call | European Put | Fixed Asian Call | Fixed Asian put | Floating Asian Call | Floating Asian Put | Fixed Lookback Call | Fixed Lookback Put | Floating Lookback Call | Floating Lookback Put | |
---|---|---|---|---|---|---|---|---|---|---|
rho | ||||||||||
-1.0 | 10.34 | 5.38 | 6.13 | 3.48 | 2.96 | 5.27 | 13.62 | 10.29 | 8.19 | 14.23 |
-0.9 | 10.35 | 5.37 | 6.14 | 3.47 | 2.96 | 5.27 | 13.76 | 10.18 | 8.31 | 14.15 |
-0.8 | 10.35 | 5.37 | 6.13 | 3.46 | 2.96 | 5.27 | 13.89 | 10.08 | 8.44 | 14.07 |
-0.7 | 10.35 | 5.36 | 6.13 | 3.45 | 2.97 | 5.27 | 14.03 | 9.98 | 8.57 | 13.98 |
-0.6 | 10.34 | 5.36 | 6.12 | 3.44 | 2.97 | 5.27 | 14.17 | 9.87 | 8.71 | 13.88 |
-0.5 | 10.32 | 5.34 | 6.11 | 3.43 | 2.96 | 5.26 | 14.31 | 9.76 | 8.85 | 13.79 |
-0.4 | 10.30 | 5.33 | 6.10 | 3.42 | 2.96 | 5.26 | 14.46 | 9.65 | 8.99 | 13.69 |
-0.3 | 10.29 | 5.31 | 6.09 | 3.41 | 2.96 | 5.25 | 14.61 | 9.53 | 9.13 | 13.58 |
-0.2 | 10.26 | 5.30 | 6.08 | 3.40 | 2.96 | 5.24 | 14.76 | 9.42 | 9.28 | 13.48 |
-0.1 | 10.24 | 5.28 | 6.07 | 3.39 | 2.95 | 5.23 | 14.91 | 9.30 | 9.43 | 13.37 |
-0.0 | 10.21 | 5.25 | 6.05 | 3.37 | 2.94 | 5.22 | 15.06 | 9.18 | 9.58 | 13.26 |
0.1 | 10.18 | 5.23 | 6.04 | 3.36 | 2.94 | 5.21 | 15.21 | 9.05 | 9.73 | 13.14 |
0.2 | 10.14 | 5.20 | 6.02 | 3.35 | 2.93 | 5.19 | 15.36 | 8.92 | 9.88 | 13.02 |
0.3 | 10.10 | 5.17 | 6.01 | 3.33 | 2.92 | 5.17 | 15.52 | 8.79 | 10.04 | 12.90 |
0.4 | 10.05 | 5.13 | 5.98 | 3.31 | 2.91 | 5.16 | 15.67 | 8.65 | 10.20 | 12.77 |
0.5 | 9.99 | 5.08 | 5.96 | 3.30 | 2.89 | 5.14 | 15.83 | 8.51 | 10.36 | 12.63 |
0.6 | 9.92 | 5.03 | 5.94 | 3.28 | 2.88 | 5.11 | 15.99 | 8.35 | 10.53 | 12.48 |
0.7 | 9.85 | 4.97 | 5.91 | 3.25 | 2.86 | 5.09 | 16.15 | 8.18 | 10.70 | 12.32 |
0.8 | 9.77 | 4.91 | 5.87 | 3.23 | 2.85 | 5.06 | 16.31 | 8.00 | 10.88 | 12.15 |
0.9 | 9.67 | 4.84 | 5.83 | 3.20 | 2.84 | 5.04 | 16.47 | 7.81 | 11.05 | 11.96 |
1.0 | 9.54 | 4.76 | 5.77 | 3.17 | 2.84 | 5.01 | 16.60 | 7.62 | 11.23 | 11.74 |