Path: blob/master/src/FMNM/Heston_pricer.py
1700 views
#!/usr/bin/env python31# -*- coding: utf-8 -*-2"""3Created on Sun Apr 19 12:13:10 202045@author: cantaro866"""78from time import time9import numpy as np10import scipy as scp11import scipy.stats as ss1213from FMNM.CF import cf_Heston_good14from FMNM.cython.heston import Heston_paths15from FMNM.probabilities import Q1, Q216from functools import partial17from FMNM.FFT import fft_Lewis, IV_from_Lewis181920class Heston_pricer:21"""22Class to price the options with the Heston model by:23- Fourier-inversion.24- Monte Carlo.25"""2627def __init__(self, Option_info, Process_info):28"""29Process_info: of type VG_process. It contains the interest rate r30and the VG parameters (sigma, theta, kappa)3132Option_info: of type Option_param. It contains (S0,K,T) i.e. current price,33strike, maturity in years34"""35self.r = Process_info.mu # interest rate36self.sigma = Process_info.sigma # Heston parameter37self.theta = Process_info.theta # Heston parameter38self.kappa = Process_info.kappa # Heston parameter39self.rho = Process_info.rho # Heston parameter4041self.S0 = Option_info.S0 # current price42self.v0 = Option_info.v0 # spot variance43self.K = Option_info.K # strike44self.T = Option_info.T # maturity in years4546self.exercise = Option_info.exercise47self.payoff = Option_info.payoff4849def payoff_f(self, S):50if self.payoff == "call":51Payoff = np.maximum(S - self.K, 0)52elif self.payoff == "put":53Payoff = np.maximum(self.K - S, 0)54return Payoff5556def MC(self, N, paths, Err=False, Time=False):57"""58Heston Monte Carlo59N = time steps60paths = number of simulated paths61Err = return Standard Error if True62Time = return execution time if True63"""64t_init = time()6566S_T, _ = Heston_paths(67N=N,68paths=paths,69T=self.T,70S0=self.S0,71v0=self.v0,72mu=self.r,73rho=self.rho,74kappa=self.kappa,75theta=self.theta,76sigma=self.sigma,77)78S_T = S_T.reshape((paths, 1))79DiscountedPayoff = np.exp(-self.r * self.T) * self.payoff_f(S_T)80V = scp.mean(DiscountedPayoff, axis=0)81std_err = ss.sem(DiscountedPayoff)8283if Err is True:84if Time is True:85elapsed = time() - t_init86return V, std_err, elapsed87else:88return V, std_err89else:90if Time is True:91elapsed = time() - t_init92return V, elapsed93else:94return V9596def Fourier_inversion(self):97"""98Price obtained by inversion of the characteristic function99"""100k = np.log(self.K / self.S0) # log moneyness101cf_H_b_good = partial(102cf_Heston_good,103t=self.T,104v0=self.v0,105mu=self.r,106theta=self.theta,107sigma=self.sigma,108kappa=self.kappa,109rho=self.rho,110)111112limit_max = 2000 # right limit in the integration113114if self.payoff == "call":115call = self.S0 * Q1(k, cf_H_b_good, limit_max) - self.K * np.exp(-self.r * self.T) * Q2(116k, cf_H_b_good, limit_max117)118return call119elif self.payoff == "put":120put = self.K * np.exp(-self.r * self.T) * (1 - Q2(k, cf_H_b_good, limit_max)) - self.S0 * (1211 - Q1(k, cf_H_b_good, limit_max)122)123return put124else:125raise ValueError("invalid type. Set 'call' or 'put'")126127def FFT(self, K):128"""129FFT method. It returns a vector of prices.130K is an array of strikes131"""132K = np.array(K)133cf_H_b_good = partial(134cf_Heston_good,135t=self.T,136v0=self.v0,137mu=self.r,138theta=self.theta,139sigma=self.sigma,140kappa=self.kappa,141rho=self.rho,142)143144if self.payoff == "call":145return fft_Lewis(K, self.S0, self.r, self.T, cf_H_b_good, interp="cubic")146elif self.payoff == "put": # put-call parity147return (148fft_Lewis(K, self.S0, self.r, self.T, cf_H_b_good, interp="cubic")149- self.S0150+ K * np.exp(-self.r * self.T)151)152else:153raise ValueError("invalid type. Set 'call' or 'put'")154155def IV_Lewis(self):156"""Implied Volatility from the Lewis formula"""157158cf_H_b_good = partial(159cf_Heston_good,160t=self.T,161v0=self.v0,162mu=self.r,163theta=self.theta,164sigma=self.sigma,165kappa=self.kappa,166rho=self.rho,167)168if self.payoff == "call":169return IV_from_Lewis(self.K, self.S0, self.T, self.r, cf_H_b_good)170elif self.payoff == "put":171raise NotImplementedError172else:173raise ValueError("invalid type. Set 'call' or 'put'")174175176