#!pip install "git+https://github.com/SaremS/side-projects.git#egg=stochastic_volatility_model&subdirectory=stoch-vola/model"
Stochastic Volatility model in C++ (using pybind11)
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from findiff import FinDiff
from stochastic_volatility_model import StochasticVolatilityModel
= ['^DJI']
tickers
# Download the data from yfinance
= yf.download(tickers, start="2022-01-01", end="2024-10-25")
df
= df["Adj Close"]
dfp = np.log(dfp).diff().dropna()
dfr
= (16,6))
plt.figure(figsize
plt.plot(dfr)=0.5) plt.grid(alpha
[*********************100%***********************] 1 of 1 completed
from scipy.stats import norm
class RandomVolatility:
def __init__(self, alpha, beta, sigma):
self.alpha = alpha
self.beta = beta
self.sigma = sigma
def particle_filter(self, y, M=100, seed=321):
np.random.seed(seed)= len(y)
T
= self.alpha
alpha = np.tanh(self.beta)
beta = np.exp(self.sigma)
q_sigma
= np.random.normal(size=(T+1,M)) * q_sigma
particles
for t in range(1,T+1):
= alpha + beta * (particles[t-1,:] - alpha)
q_mus = np.random.normal(size=(M,))*q_sigma + q_mus
particles_t = particles_t
particles[t,:]
= norm(loc=0.0, scale=np.exp(particles_t/2))
obs_dists
= obs_dists.pdf(y[t-1])
w_t
= w_t/np.sum(w_t)
w_t
= np.random.choice(np.arange(M),M,p=w_t,replace=True)
a_t = particles[:,a_t]
particles
return particles[1:,:]
def particle_filter_ll(self, y, M=100, seed=123):
= self.particle_filter(y, M, seed)
particles
= norm(loc=0.0, scale=np.exp(particles/2))
obs_dists
= obs_dists.pdf(y.reshape(-1,1)).mean(1)
like ==0] = np.min(like)
like[like
return np.log(like).mean()
%%time
##Python
*2, 5.0, 0.0).particle_filter_ll(dfr.values,M=100) RandomVolatility(np.log(np.std(dfr.values))
CPU times: user 593 ms, sys: 8.88 ms, total: 602 ms
Wall time: 604 ms
3.428327859504868
%%time
##C++
*2, 5.0, 0.0).logLikelihood(dfr.values,100,321) StochasticVolatilityModel(np.log(np.std(dfr.values))
CPU times: user 79.3 ms, sys: 2.11 ms, total: 81.4 ms
Wall time: 82 ms
0.17236234874419082
from scipy.optimize import minimize
= dfr.values
dfrv
= np.array([np.log(np.std(dfr.values))*2, 5.0, 0.0])
xn = minimize(lambda x: -StochasticVolatilityModel(*x).logLikelihood(dfrv,100,321), xn) result
= StochasticVolatilityModel(*result.x).particleFilter(dfrv,1000,123)
parts = parts.getParticles() ps
= np.mean(np.exp(np.array(ps)/2),1)
means = np.quantile(np.exp(np.array(ps)/2),0.05,1)
lower = np.quantile(np.exp(np.array(ps)/2),0.95,1) upper
= plt.subplots(2, 1, figsize=(16, 8))
fig, axs
0].set_title("Volatility Estimates")
axs[0].plot(dfr.index, means, lw=2.5, label="Estimated Volatility - Stochastic Volatility Model")
axs[0].grid(alpha=0.5)
axs[0].fill_between(dfr.index, upper, lower,alpha=0.35)
axs[0].plot(dfr.rolling(20).std(), lw=2.5, label="Estimated Volatility - 20 days rolling standard deviation")
axs[0].legend()
axs[
1].set_title("Observed returns")
axs[1].plot(dfr, label="^DJI")
axs[1].grid(alpha=0.5) axs[