Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
cantaro86
GitHub Repository: cantaro86/Financial-Models-Numerical-Methods
Path: blob/master/src/FMNM/Heston_pricer.py
1700 views
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Sun Apr 19 12:13:10 2020
5
6
@author: cantaro86
7
"""
8
9
from time import time
10
import numpy as np
11
import scipy as scp
12
import scipy.stats as ss
13
14
from FMNM.CF import cf_Heston_good
15
from FMNM.cython.heston import Heston_paths
16
from FMNM.probabilities import Q1, Q2
17
from functools import partial
18
from FMNM.FFT import fft_Lewis, IV_from_Lewis
19
20
21
class Heston_pricer:
22
"""
23
Class to price the options with the Heston model by:
24
- Fourier-inversion.
25
- Monte Carlo.
26
"""
27
28
def __init__(self, Option_info, Process_info):
29
"""
30
Process_info: of type VG_process. It contains the interest rate r
31
and the VG parameters (sigma, theta, kappa)
32
33
Option_info: of type Option_param. It contains (S0,K,T) i.e. current price,
34
strike, maturity in years
35
"""
36
self.r = Process_info.mu # interest rate
37
self.sigma = Process_info.sigma # Heston parameter
38
self.theta = Process_info.theta # Heston parameter
39
self.kappa = Process_info.kappa # Heston parameter
40
self.rho = Process_info.rho # Heston parameter
41
42
self.S0 = Option_info.S0 # current price
43
self.v0 = Option_info.v0 # spot variance
44
self.K = Option_info.K # strike
45
self.T = Option_info.T # maturity in years
46
47
self.exercise = Option_info.exercise
48
self.payoff = Option_info.payoff
49
50
def payoff_f(self, S):
51
if self.payoff == "call":
52
Payoff = np.maximum(S - self.K, 0)
53
elif self.payoff == "put":
54
Payoff = np.maximum(self.K - S, 0)
55
return Payoff
56
57
def MC(self, N, paths, Err=False, Time=False):
58
"""
59
Heston Monte Carlo
60
N = time steps
61
paths = number of simulated paths
62
Err = return Standard Error if True
63
Time = return execution time if True
64
"""
65
t_init = time()
66
67
S_T, _ = Heston_paths(
68
N=N,
69
paths=paths,
70
T=self.T,
71
S0=self.S0,
72
v0=self.v0,
73
mu=self.r,
74
rho=self.rho,
75
kappa=self.kappa,
76
theta=self.theta,
77
sigma=self.sigma,
78
)
79
S_T = S_T.reshape((paths, 1))
80
DiscountedPayoff = np.exp(-self.r * self.T) * self.payoff_f(S_T)
81
V = scp.mean(DiscountedPayoff, axis=0)
82
std_err = ss.sem(DiscountedPayoff)
83
84
if Err is True:
85
if Time is True:
86
elapsed = time() - t_init
87
return V, std_err, elapsed
88
else:
89
return V, std_err
90
else:
91
if Time is True:
92
elapsed = time() - t_init
93
return V, elapsed
94
else:
95
return V
96
97
def Fourier_inversion(self):
98
"""
99
Price obtained by inversion of the characteristic function
100
"""
101
k = np.log(self.K / self.S0) # log moneyness
102
cf_H_b_good = partial(
103
cf_Heston_good,
104
t=self.T,
105
v0=self.v0,
106
mu=self.r,
107
theta=self.theta,
108
sigma=self.sigma,
109
kappa=self.kappa,
110
rho=self.rho,
111
)
112
113
limit_max = 2000 # right limit in the integration
114
115
if self.payoff == "call":
116
call = self.S0 * Q1(k, cf_H_b_good, limit_max) - self.K * np.exp(-self.r * self.T) * Q2(
117
k, cf_H_b_good, limit_max
118
)
119
return call
120
elif self.payoff == "put":
121
put = self.K * np.exp(-self.r * self.T) * (1 - Q2(k, cf_H_b_good, limit_max)) - self.S0 * (
122
1 - Q1(k, cf_H_b_good, limit_max)
123
)
124
return put
125
else:
126
raise ValueError("invalid type. Set 'call' or 'put'")
127
128
def FFT(self, K):
129
"""
130
FFT method. It returns a vector of prices.
131
K is an array of strikes
132
"""
133
K = np.array(K)
134
cf_H_b_good = partial(
135
cf_Heston_good,
136
t=self.T,
137
v0=self.v0,
138
mu=self.r,
139
theta=self.theta,
140
sigma=self.sigma,
141
kappa=self.kappa,
142
rho=self.rho,
143
)
144
145
if self.payoff == "call":
146
return fft_Lewis(K, self.S0, self.r, self.T, cf_H_b_good, interp="cubic")
147
elif self.payoff == "put": # put-call parity
148
return (
149
fft_Lewis(K, self.S0, self.r, self.T, cf_H_b_good, interp="cubic")
150
- self.S0
151
+ K * np.exp(-self.r * self.T)
152
)
153
else:
154
raise ValueError("invalid type. Set 'call' or 'put'")
155
156
def IV_Lewis(self):
157
"""Implied Volatility from the Lewis formula"""
158
159
cf_H_b_good = partial(
160
cf_Heston_good,
161
t=self.T,
162
v0=self.v0,
163
mu=self.r,
164
theta=self.theta,
165
sigma=self.sigma,
166
kappa=self.kappa,
167
rho=self.rho,
168
)
169
if self.payoff == "call":
170
return IV_from_Lewis(self.K, self.S0, self.T, self.r, cf_H_b_good)
171
elif self.payoff == "put":
172
raise NotImplementedError
173
else:
174
raise ValueError("invalid type. Set 'call' or 'put'")
175
176