Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
cantaro86
GitHub Repository: cantaro86/Financial-Models-Numerical-Methods
Path: blob/master/src/FMNM/cython/heston.pyx
1700 views
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Tue Oct 15 17:46:10 2019
5
6
@author: cantaro86
7
"""
8
9
import numpy as np
10
import scipy.stats as ss
11
cimport numpy as np
12
cimport cython
13
from libc.math cimport isnan
14
15
16
cdef extern from "math.h":
17
double sqrt(double m)
18
double exp(double m)
19
double log(double m)
20
double fabs(double m)
21
22
23
24
@cython.boundscheck(False) # turn off bounds-checking for entire function
25
@cython.wraparound(False) # turn off negative index wrapping for entire function
26
cpdef Heston_paths(int N, int paths, double T, double S0, double v0,
27
double mu, double rho, double kappa, double theta, double sigma ):
28
"""
29
Generates random values of stock S and variance v at maturity T.
30
This function uses the "abs" method for the variance.
31
32
OUTPUT:
33
Two arrays of size equal to "paths".
34
35
int N = time steps
36
int paths = number of paths
37
double T = maturity
38
double S0 = spot price
39
double v0 = spot variance
40
double mu = drift
41
double rho = correlation coefficient
42
double kappa = mean reversion coefficient
43
double theta = long-term variance
44
double sigma = Vol of Vol - Volatility of instantaneous variance
45
"""
46
47
cdef double dt = T/(N-1)
48
cdef double dt_sq = sqrt(dt)
49
50
assert(2*kappa * theta > sigma**2) # Feller condition
51
52
cdef double[:] W_S # declaration Brownian motion for S
53
cdef double[:] W_v # declaration Brownian motion for v
54
55
# Initialize
56
cdef double[:] v_T = np.zeros(paths) # values of v at T
57
cdef double[:] S_T = np.zeros(paths) # values of S at T
58
cdef double[:] v = np.zeros(N)
59
cdef double[:] S = np.zeros(N)
60
61
cdef int t, path
62
for path in range(paths):
63
# Generate random Brownian Motions
64
W_S_arr = np.random.normal(loc=0, scale=1, size=N-1 )
65
W_v_arr = rho * W_S_arr + sqrt(1-rho**2) * np.random.normal(loc=0, scale=1, size=N-1 )
66
W_S = W_S_arr
67
W_v = W_v_arr
68
S[0] = S0 # stock at 0
69
v[0] = v0 # variance at 0
70
71
for t in range(0,N-1):
72
v[t+1] = fabs( v[t] + kappa*(theta - v[t])*dt + sigma * sqrt(v[t]) * dt_sq * W_v[t] )
73
S[t+1] = S[t] * exp( (mu - 0.5*v[t])*dt + sqrt(v[t]) * dt_sq * W_S[t] )
74
75
S_T[path] = S[N-1]
76
v_T[path] = v[N-1]
77
78
return np.asarray(S_T), np.asarray(v_T)
79
80
81
82
83
cpdef Heston_paths_log(int N, int paths, double T, double S0, double v0,
84
double mu, double rho, double kappa, double theta, double sigma ):
85
"""
86
Generates random values of stock S and variance v at maturity T.
87
This function uses the log-variables. NaN and abnormal numbers are ignored.
88
89
OUTPUT:
90
Two arrays of size smaller or equal of "paths".
91
92
INPUT:
93
int N = time steps
94
int paths = number of paths
95
double T = maturity
96
double S0 = spot price
97
double v0 = spot variance
98
double mu = drift
99
double rho = correlation coefficient
100
double kappa = mean reversion coefficient
101
double theta = long-term variance
102
double sigma = Vol of Vol - Volatility of instantaneous variance
103
"""
104
105
cdef double dt = T/(N-1)
106
cdef double dt_sq = sqrt(dt)
107
108
cdef double X0 = log(S0) # log price
109
cdef double Y0 = log(v0) # log-variance
110
111
assert(2*kappa * theta > sigma**2) # Feller condition
112
cdef double std_asy = sqrt( theta * sigma**2 /(2*kappa) )
113
114
cdef double[:] W_S # declaration Brownian motion for S
115
cdef double[:] W_v # declaration Brownian motion for v
116
117
# Initialize
118
cdef double[:] Y_T = np.zeros(paths)
119
cdef double[:] X_T = np.zeros(paths)
120
cdef double[:] Y = np.zeros(N)
121
cdef double[:] X = np.zeros(N)
122
123
cdef int t, path
124
cdef double v, v_sq
125
cdef double up_bound = log( (theta + 10*std_asy) ) # mean + 10 standard deviations
126
cdef int warning = 0
127
cdef int counter = 0
128
129
# Generate paths
130
for path in range(paths):
131
# Generate random Brownian Motions
132
W_S_arr = np.random.normal(loc=0, scale=1, size=N-1 )
133
W_v_arr = rho * W_S_arr + sqrt(1-rho**2) * np.random.normal(loc=0, scale=1, size=N-1 )
134
W_S = W_S_arr
135
W_v = W_v_arr
136
X[0] = X0 # log-stock
137
Y[0] = Y0 # log-variance
138
139
for t in range(0,N-1):
140
v = exp(Y[t]) # variance
141
v_sq = sqrt(v) # square root of variance
142
143
Y[t+1] = Y[t] + (1/v)*( kappa*(theta - v) - 0.5*sigma**2 )*dt + sigma * (1/v_sq) * dt_sq * W_v[t]
144
X[t+1] = X[t] + (mu - 0.5*v)*dt + v_sq * dt_sq * W_S[t]
145
146
if ( Y[-1] > up_bound or isnan(Y[-1]) ):
147
warning = 1
148
counter += 1
149
X_T[path] = 10000
150
Y_T[path] = 10000
151
continue
152
153
X_T[path] = X[-1]
154
Y_T[path] = Y[-1]
155
156
if (warning==1):
157
print("WARNING. ", counter, " paths have been removed because of the overflow.")
158
print("SOLUTION: Use a bigger value N.")
159
160
Y_arr = np.asarray(Y_T)
161
Y_good = Y_arr[ Y_arr < up_bound ]
162
X_good = np.asarray(X_T)[ Y_arr < up_bound ]
163
164
return np.exp(X_good), np.exp(Y_good)
165
166