Path: blob/master/src/FMNM/cython/heston.pyx
1700 views
#!/usr/bin/env python31# -*- coding: utf-8 -*-2"""3Created on Tue Oct 15 17:46:10 201945@author: cantaro866"""78import numpy as np9import scipy.stats as ss10cimport numpy as np11cimport cython12from libc.math cimport isnan131415cdef extern from "math.h":16double sqrt(double m)17double exp(double m)18double log(double m)19double fabs(double m)20212223@cython.boundscheck(False) # turn off bounds-checking for entire function24@cython.wraparound(False) # turn off negative index wrapping for entire function25cpdef Heston_paths(int N, int paths, double T, double S0, double v0,26double mu, double rho, double kappa, double theta, double sigma ):27"""28Generates random values of stock S and variance v at maturity T.29This function uses the "abs" method for the variance.3031OUTPUT:32Two arrays of size equal to "paths".3334int N = time steps35int paths = number of paths36double T = maturity37double S0 = spot price38double v0 = spot variance39double mu = drift40double rho = correlation coefficient41double kappa = mean reversion coefficient42double theta = long-term variance43double sigma = Vol of Vol - Volatility of instantaneous variance44"""4546cdef double dt = T/(N-1)47cdef double dt_sq = sqrt(dt)4849assert(2*kappa * theta > sigma**2) # Feller condition5051cdef double[:] W_S # declaration Brownian motion for S52cdef double[:] W_v # declaration Brownian motion for v5354# Initialize55cdef double[:] v_T = np.zeros(paths) # values of v at T56cdef double[:] S_T = np.zeros(paths) # values of S at T57cdef double[:] v = np.zeros(N)58cdef double[:] S = np.zeros(N)5960cdef int t, path61for path in range(paths):62# Generate random Brownian Motions63W_S_arr = np.random.normal(loc=0, scale=1, size=N-1 )64W_v_arr = rho * W_S_arr + sqrt(1-rho**2) * np.random.normal(loc=0, scale=1, size=N-1 )65W_S = W_S_arr66W_v = W_v_arr67S[0] = S0 # stock at 068v[0] = v0 # variance at 06970for t in range(0,N-1):71v[t+1] = fabs( v[t] + kappa*(theta - v[t])*dt + sigma * sqrt(v[t]) * dt_sq * W_v[t] )72S[t+1] = S[t] * exp( (mu - 0.5*v[t])*dt + sqrt(v[t]) * dt_sq * W_S[t] )7374S_T[path] = S[N-1]75v_T[path] = v[N-1]7677return np.asarray(S_T), np.asarray(v_T)7879808182cpdef Heston_paths_log(int N, int paths, double T, double S0, double v0,83double mu, double rho, double kappa, double theta, double sigma ):84"""85Generates random values of stock S and variance v at maturity T.86This function uses the log-variables. NaN and abnormal numbers are ignored.8788OUTPUT:89Two arrays of size smaller or equal of "paths".9091INPUT:92int N = time steps93int paths = number of paths94double T = maturity95double S0 = spot price96double v0 = spot variance97double mu = drift98double rho = correlation coefficient99double kappa = mean reversion coefficient100double theta = long-term variance101double sigma = Vol of Vol - Volatility of instantaneous variance102"""103104cdef double dt = T/(N-1)105cdef double dt_sq = sqrt(dt)106107cdef double X0 = log(S0) # log price108cdef double Y0 = log(v0) # log-variance109110assert(2*kappa * theta > sigma**2) # Feller condition111cdef double std_asy = sqrt( theta * sigma**2 /(2*kappa) )112113cdef double[:] W_S # declaration Brownian motion for S114cdef double[:] W_v # declaration Brownian motion for v115116# Initialize117cdef double[:] Y_T = np.zeros(paths)118cdef double[:] X_T = np.zeros(paths)119cdef double[:] Y = np.zeros(N)120cdef double[:] X = np.zeros(N)121122cdef int t, path123cdef double v, v_sq124cdef double up_bound = log( (theta + 10*std_asy) ) # mean + 10 standard deviations125cdef int warning = 0126cdef int counter = 0127128# Generate paths129for path in range(paths):130# Generate random Brownian Motions131W_S_arr = np.random.normal(loc=0, scale=1, size=N-1 )132W_v_arr = rho * W_S_arr + sqrt(1-rho**2) * np.random.normal(loc=0, scale=1, size=N-1 )133W_S = W_S_arr134W_v = W_v_arr135X[0] = X0 # log-stock136Y[0] = Y0 # log-variance137138for t in range(0,N-1):139v = exp(Y[t]) # variance140v_sq = sqrt(v) # square root of variance141142Y[t+1] = Y[t] + (1/v)*( kappa*(theta - v) - 0.5*sigma**2 )*dt + sigma * (1/v_sq) * dt_sq * W_v[t]143X[t+1] = X[t] + (mu - 0.5*v)*dt + v_sq * dt_sq * W_S[t]144145if ( Y[-1] > up_bound or isnan(Y[-1]) ):146warning = 1147counter += 1148X_T[path] = 10000149Y_T[path] = 10000150continue151152X_T[path] = X[-1]153Y_T[path] = Y[-1]154155if (warning==1):156print("WARNING. ", counter, " paths have been removed because of the overflow.")157print("SOLUTION: Use a bigger value N.")158159Y_arr = np.asarray(Y_T)160Y_good = Y_arr[ Y_arr < up_bound ]161X_good = np.asarray(X_T)[ Y_arr < up_bound ]162163return np.exp(X_good), np.exp(Y_good)164165166