%matplotlib inline
import numpy as np
import yfinance as yf
from arch import arch_model
import matplotlib.pyplot as plt
plt.rc('figure',figsize=(16,6))
plt.rc('font',family='sans-serif')
plt.rc('font',size=14)
data=yf.download('AAPL',start='2020-01-01',end='2022-10-31')
[*********************100%***********************] 1 of 1 completed
data
Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|
Date | ||||||
2020-01-02 | 74.059998 | 75.150002 | 73.797501 | 75.087502 | 73.683563 | 135480400 |
2020-01-03 | 74.287498 | 75.144997 | 74.125000 | 74.357498 | 72.967216 | 146322800 |
2020-01-06 | 73.447502 | 74.989998 | 73.187500 | 74.949997 | 73.548630 | 118387200 |
2020-01-07 | 74.959999 | 75.224998 | 74.370003 | 74.597504 | 73.202736 | 108872000 |
2020-01-08 | 74.290001 | 76.110001 | 74.290001 | 75.797501 | 74.380280 | 132079200 |
... | ... | ... | ... | ... | ... | ... |
2022-10-24 | 147.190002 | 150.229996 | 146.000000 | 149.449997 | 149.449997 | 75981900 |
2022-10-25 | 150.089996 | 152.490005 | 149.360001 | 152.339996 | 152.339996 | 74732300 |
2022-10-26 | 150.960007 | 151.990005 | 148.039993 | 149.350006 | 149.350006 | 88194300 |
2022-10-27 | 148.070007 | 149.050003 | 144.130005 | 144.800003 | 144.800003 | 109180200 |
2022-10-28 | 148.199997 | 157.500000 | 147.820007 | 155.740005 | 155.740005 | 164762400 |
713 rows × 6 columns
adjusted_closes=data['Adj Close']
returns=100*adjusted_closes.pct_change().dropna()
returns.plot()
<AxesSubplot:xlabel='Date'>
(returns**2).plot()
<AxesSubplot:xlabel='Date'>
model=arch_model(returns)
Calling arch_model like this does three things:
Uses a constant mean
Assumes a GARCH(1, 0, 1) volatility model
Uses a normal distribution for the standardized errors
Then fit the model
res = model.fit()
Iteration: 1, Func. Count: 6, Neg. LLF: 2858.147147760594 Iteration: 2, Func. Count: 16, Neg. LLF: 19148.66777569176 Iteration: 3, Func. Count: 23, Neg. LLF: 1969.642834550345 Iteration: 4, Func. Count: 30, Neg. LLF: 1773.3051684941222 Iteration: 5, Func. Count: 37, Neg. LLF: 1531.87509421799 Iteration: 6, Func. Count: 43, Neg. LLF: 1529.717329092487 Iteration: 7, Func. Count: 48, Neg. LLF: 1529.716499633174 Iteration: 8, Func. Count: 53, Neg. LLF: 1529.7164421794673 Iteration: 9, Func. Count: 58, Neg. LLF: 1529.716435351741 Iteration: 10, Func. Count: 63, Neg. LLF: 1529.716433288234 Iteration: 11, Func. Count: 67, Neg. LLF: 1529.7164332882217 Optimization terminated successfully (Exit mode 0) Current function value: 1529.716433288234 Iterations: 11 Function evaluations: 67 Gradient evaluations: 11
print(res.summary())
Constant Mean - GARCH Model Results ============================================================================== Dep. Variable: Adj Close R-squared: 0.000 Mean Model: Constant Mean Adj. R-squared: 0.000 Vol Model: GARCH Log-Likelihood: -1529.72 Distribution: Normal AIC: 3067.43 Method: Maximum Likelihood BIC: 3085.71 No. Observations: 712 Date: Tue, Nov 01 2022 Df Residuals: 711 Time: 15:46:32 Df Model: 1 Mean Model ========================================================================== coef std err t P>|t| 95.0% Conf. Int. -------------------------------------------------------------------------- mu 0.1972 7.607e-02 2.593 9.518e-03 [4.815e-02, 0.346] Volatility Model ========================================================================== coef std err t P>|t| 95.0% Conf. Int. -------------------------------------------------------------------------- omega 0.2462 9.903e-02 2.486 1.290e-02 [5.213e-02, 0.440] alpha[1] 0.1302 3.234e-02 4.026 5.662e-05 [6.684e-02, 0.194] beta[1] 0.8250 3.737e-02 22.076 5.395e-108 [ 0.752, 0.898] ========================================================================== Covariance estimator: robust
fig=res.plot('D')
# get the variance forecast
forecast = res.forecast(horizon=1, reindex=False)
variance_forecast = forecast.variance.iloc[-1][0]
variance_forecast
11.517069881883414
# compute the annualized volatility forecast
volatility_forecast = np.sqrt(variance_forecast)
annualized_volatility_forecast = volatility_forecast * np.sqrt(252) / 100
annualized_volatility_forecast
0.5387301374746563
returns['2022'].std()* np.sqrt(252) / 100
0.35065659897325996