-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGARCH-python-code.py
More file actions
164 lines (133 loc) · 5.88 KB
/
GARCH-python-code.py
File metadata and controls
164 lines (133 loc) · 5.88 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# My GARCH Volatility Model - V2 with more exploration
# --- Imports and Setup ---
import numpy as np
import matplotlib.pyplot as plt
import math
import random
print("=== My First Volatility Model ===")
# ================================================
# STEP 1: Make up some data with volatility clustering
# ================================================
print("\n--- STEP 1: Creating a time series with changing volatility ---")
# set the seed so our random numbers are the same each time
random.seed(101)
np.random.seed(101)
# number of days to simulate
n_days = 1000
# GARCH parameters to create the data
# these are the 'true' parameters for our fake data
omega = 0.05 # baseline variance
alpha = 0.2 # how much last period's shock matters
beta = 0.75 # how much last period's volatility matters
# NOTE TO SELF: alpha + beta must be < 1 or the model might explode. 0.2 + 0.75 = 0.95, so that's ok.
# lists to store our results
true_variances = []
list_of_returns = []
# set the starting variance
initial_variance = omega / (1 - alpha - beta)
true_variances.append(initial_variance)
list_of_returns.append(0) # start with a zero return
# loop for each day to generate the next return
for i in range(1, n_days):
last_variance = true_variances[-1]
last_return_sq = list_of_returns[-1]**2
current_variance = omega + alpha * last_return_sq + beta * last_variance
current_volatility = math.sqrt(current_variance)
random_shock = random.gauss(0, 1)
current_return = current_volatility * random_shock
true_variances.append(current_variance)
list_of_returns.append(current_return)
print(f"✅ Created {n_days} days of synthetic data.")
# ================================================
# STEP 2: Look at the data we made
# ================================================
print("\n--- STEP 2: Visualizing the data ---")
# Plot the returns
print("... Generating Returns Plot ...")
plt.figure(figsize=(12, 5))
plt.plot(list_of_returns, label='Daily Returns')
plt.title('Synthetic Daily Returns with Volatility Clustering')
plt.legend()
plt.show()
# NOTE TO SELF: the plot looks spiky, just like the examples in the lecture notes. Big spikes are clustered together.
# --- NEW VISUALIZATION ---
# Sometimes looking at squared returns can make the clusters easier to see
print("... Generating Squared Returns Plot ...")
squared_returns = [r**2 for r in list_of_returns]
plt.figure(figsize=(12, 5))
plt.plot(squared_returns, label='Squared Daily Returns', color='orange')
plt.title('Squared Returns')
plt.legend()
plt.show()
# ================================================
# STEP 3: Build a Simple Model to Estimate Volatility
# ================================================
print("\n--- STEP 3: Building a Simple Volatility Model (EWMA) ---")
print("I'll use an Exponentially Weighted Moving Average (EWMA).")
# This is a common value for the EWMA lambda (decay factor)
lambda_decay = 0.94
# todo: try changing this lambda value later to see what happens. Maybe 0.9 or 0.97?
modelled_variances = []
modelled_variances.append(true_variances[0]) # Start with the true variance
for i in range(1, n_days):
last_model_var = modelled_variances[-1]
last_return_sq = list_of_returns[i-1]**2
next_variance = lambda_decay * last_model_var + (1 - lambda_decay) * last_return_sq
modelled_variances.append(next_variance)
print("✅ Simple volatility model created.")
# ================================================
# STEP 4: Compare our model to the real volatility
# ================================================
print("\n--- STEP 4: Comparing Our Model to Reality ---")
# convert all variances to volatility for plotting
true_volatility = [math.sqrt(v) for v in true_variances]
modelled_volatility = [math.sqrt(v) for v in modelled_variances]
print("... Generating Comparison Plot ...")
plt.figure(figsize=(12, 6))
plt.plot(true_volatility, label='True Volatility', color='gray', alpha=0.7, linestyle='--')
plt.plot(modelled_volatility, label='Our Simple Model Estimate', color='blue', alpha=0.8)
plt.title('Comparison: True Volatility vs. Our Simple Model')
plt.legend()
plt.show()
# --- NEW ANALYSIS ---
# Let's see how wrong our model was on average
print("\n... Additional Analysis ...")
errors = [abs(true_volatility[i] - modelled_volatility[i]) for i in range(n_days)]
avg_error = np.mean(errors)
print(f"The average difference between our model and reality was: {avg_error:.4f}")
# Plot the errors
print("... Generating Model Error Plot ...")
plt.figure(figsize=(12, 5))
plt.plot(errors, label='Model Error (Absolute)')
plt.title('How wrong was our model each day?')
plt.legend()
plt.show()
# ================================================
# STEP 5: Make a simple forecast
# ================================================
print("\n--- STEP 5: Making a Forecast ---")
forecast_days = 30
# get the last known values from our data
last_known_variance = modelled_variances[-1]
last_known_return_sq = list_of_returns[-1]**2
# list to hold our forecast
forecasted_variance = []
# loop to create the forecast
for i in range(forecast_days):
# The forecast formula is a bit different because we don't know the future returns
# We assume the future return will be equal to the variance, which is a GARCH property
next_variance = lambda_decay * last_known_variance + (1 - lambda_decay) * last_known_variance
forecasted_variance.append(next_variance)
# update the last known variance for the next loop
last_known_variance = next_variance
forecasted_volatility = [math.sqrt(v) for v in forecasted_variance]
print(f"✅ Forecasted volatility for the next {forecast_days} days.")
print("... Generating Forecast Plot ...")
plt.figure(figsize=(10, 5))
plt.plot(forecasted_volatility)
plt.title('30-Day Volatility Forecast')
plt.xlabel('Days into the Future')
plt.ylabel('Forecasted Volatility')
plt.show()
print("\n--- Project Complete ---")
print("The forecast shows volatility slowly returning to a long-term average.")