-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.py
114 lines (94 loc) · 4.22 KB
/
index.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
import pandas as pd
class IRM:
def __init__(self, theta: float, mu: float, sigma: float, r0: float):
"""
Initialize the interest rate model parameters.
:param theta: Speed of reversion
:param mu: Long-term mean level
:param sigma: Volatility
:param r0: Initial interest rate
"""
self.theta = theta
self.mu = mu
self.sigma = sigma
self.r0 = r0
def vasicek_milstein_path(self, T: float, N: int, n_paths: int):
"""
Simulate vasicek paths using the Milstein scheme.
:param T: Time horizon
:param N: Number of time steps
:param n_paths: Number of simulated paths
:return: Simulated paths
"""
dt = T / N
rates = np.zeros((N + 1, n_paths))
rates[0] = self.r0
for i in range(1, N + 1):
dW = np.random.normal(0, np.sqrt(dt), n_paths)
rates[i] = rates[i - 1] + self.theta * (self.mu - rates[i - 1]) * dt + self.sigma * dW + 0.5 * self.sigma**2 * (dW**2 - dt)
return rates
def CIR_milstein_path(self, T: float, N: int, n_paths: int):
"""
Simulate Cox–Ingersoll–Ross paths using the Milstein scheme.
:param T: Time horizon
:param N: Number of time steps
:param n_paths: Number of simulated paths
:return: Simulated paths
"""
dt = T / N
rates = np.zeros((N + 1, n_paths))
rates[0] = self.r0
for i in range(1, N + 1):
dW = np.random.normal(0, np.sqrt(dt), n_paths)
rates[i] = rates[i - 1] + self.theta * (self.mu - rates[i - 1]) * dt + self.sigma * np.sqrt(rates[i - 1]) * dW + 0.5 * self.sigma**2 * (dW**2 - dt) / (rates[i - 1])
return rates
def calibrate(self, market_data: np.ndarray, path_method = 'vasicek_milstein_path'):
"""
Calibrate the model parameters to market data.
:param market_data: Array of market data for calibration
:param path_method: A name of path method to be used for calibration, if none chosen, vasicek_milstein_path is the default
Options: vasicek_milstein_path, CIR_milstein_path
"""
def objective(params):
theta, mu, sigma = params
model = IRM(theta, mu, sigma, self.r0)
method = getattr(model, path_method)
simulated_data = method(T=len(market_data)-1, N=len(market_data)-1, n_paths=1)
simulated_data = simulated_data.flatten()
return np.sum((market_data - simulated_data)**2)
initial_guess = [self.theta, np.mean(market_data), np.std(market_data)]
result = minimize(objective, initial_guess, bounds=[(0, None), (0, None), (0, None)])
self.theta, self.mu, self.sigma = result.x
print(f"Calibrated parameters: theta={self.theta}, mu={self.mu}, sigma={self.sigma}")
def plot_paths(self, paths: np.ndarray, title: str = "Simulated Interest Rate Paths"):
"""
Plot the simulated interest rate paths.
:param paths: Simulated paths to plot
:param title: Title of the plot
"""
plt.figure(figsize=(10, 6))
for path in paths.T:
plt.plot(path)
plt.title(title)
plt.xlabel("Time steps")
plt.ylabel("Interest Rate")
plt.show()
# Example usage
# Define the file path
file_path = './market_data_PL.csv'
# Read the CSV file into a DataFrame
data = pd.read_csv(file_path, header=None, names=['Date', 'Period', 'Value'])
# Convert the 'Value' column to float
data['Value'] = data['Value'].astype(float)
market_data = list(map(lambda value: value[2], data.values))
model = IRM(r0=market_data[0], theta=0.5, mu=0.03, sigma=0.02)
model.calibrate(market_data)
milstein_paths = model.vasicek_milstein_path(T=10, N=1_000_000, n_paths=10)
model.plot_paths(milstein_paths, title='vasicek')
model = IRM(r0=market_data[0], theta=0.5, mu=0.03, sigma=0.02)
model.calibrate(market_data, 'CIR_milstein_path')
milstein_paths = model.CIR_milstein_path(T=10, N=1_000_000, n_paths=10)
model.plot_paths(milstein_paths, title="CIR_milstein_path")