Я пытаюсь сделать прогноз волатильности акций в будущем (скажем, на 90 дней). Кажется, что GARCH - традиционно используемая модель для этого.
Я реализовал это ниже, используя библиотеку Python arch
. Все, что я делаю, объясняется в комментариях, единственное, что нужно изменить, чтобы запустить код, - это указывать свои собственные ежедневные цены, а не то, где я получаю их из своего собственного API.
import utils
import numpy as np
import pandas as pd
import arch
import matplotlib.pyplot as plt
ticker = 'AAPL' # Ticker to retrieve data for
forecast_horizon = 90 # Number of days to forecast
# Retrive prices from IEX API
prices = utils.dw.get(filename=ticker, source='iex', iex_range='5y')
df = prices[['date', 'close']]
df['daily_returns'] = np.log(df['close']).diff() # Daily log returns
df['monthly_std'] = df['daily_returns'].rolling(21).std() # Standard deviation across trading month
df['annual_vol'] = df['monthly_std'] * np.sqrt(252) # Annualize monthly standard devation
df = df.dropna().reset_index(drop=True)
# Convert decimal returns to %
returns = df['daily_returns'] * 100
# Fit GARCH model
am = arch.arch_model(returns[:-forecast_horizon])
res = am.fit(disp='off')
# Calculate fitted variance values from model parameters
# Convert variance to standard deviation (volatility)
# Revert previous multiplication by 100
fitted = 0.1 * np.sqrt(
res.params['omega'] +
res.params['alpha[1]'] *
res.resid**2 +
res.conditional_volatility**2 *
res.params['beta[1]']
)
# Make forecast
# Convert variance to standard deviation (volatility)
# Revert previous multiplication by 100
forecast = 0.1 * np.sqrt(res.forecast(horizon=forecast_horizon).variance.values[-1])
# Store actual, fitted, and forecasted results
vol = pd.DataFrame({
'actual': df['annual_vol'],
'model': np.append(fitted, forecast)
})
# Plot Actual vs Fitted/Forecasted
plt.plot(vol['actual'][:-forecast_horizon], label='Train')
plt.plot(vol['actual'][-forecast_horizon - 1:], label='Test')
plt.plot(vol['model'][:-forecast_horizon], label='Fitted')
plt.plot(vol['model'][-forecast_horizon - 1:], label='Forecast')
plt.legend()
plt.show()
Для Apple получается следующий график:
![enter image description here](https://i.stack.imgur.com/cjtW4.png)
Очевидно, что установленные значения постоянно намного ниже, чем фактические значения, и это приводит к тому, что прогноз также является огромной недооценкой (это плохой пример, учитывая, что волатильность Apple была необычно высокой в этот тестовый период, но со всеми компании, которые я стараюсь, модель всегда недооценивает установленные значения).
Я все делаю правильно, а модель GARCH просто не очень мощная, или моделирование волатильности очень сложно? Или я делаю какую-то ошибку?