Find market mispricings like the pros with GARCH
![](https://cdn.prod.website-files.com/6606adcab6ed6464b674ad71/6661e81fd5bf3dfaa11294e6_pyquant-newsletter-12.webp)
Find market mispricings like the pros with GARCH
Find market mispricings like the pros with GARCH
In today’s issue, I’m going to show you how to forecast volatility with GARCH.
Professional options traders don’t make bets that stocks will go up or down. They look for mispricings in the market. Mispricing happens when the market price is different than what a model says the price should be.
If the price of an option is $1.50 and the model shows it should be $1.75, a trader would buy the option “cheap” and wait for it to rise to $1.75.
Derivatives models use volatility to determine the value. So quants spend most of their time building the best volatility forecasts they can to find market mispricings. If you're interested in using Python to price options, you might like my ebook.
And you can use the same tools as the quants.
GARCH is widely viewed as a better gauge of volatility than the standard deviation
Stock returns have two interesting features that GARCH models well:
- Variance error terms are autocorrelated (dependent on each other)
- Periods of high volatility tend to cluster
Dr. Tim Bollerslev developed GARCH in 1986 to address the problem of forecasting volatility in asset prices. It’s used in quant finance for risk management, derivatives pricing, and portfolio optimization.
By the end of this issue, you’ll know how to:
- Get stock price data
- Fit a GARCH model
- Forecast volatility
- Find mispricings
I’m going to show you how to do it all in Python.
Step by step.
Step 1: Get stock price data
Start by importing the libraries and getting the data. I like to use yfinance for getting stock data and NumPy for math functions. I use the excellent library arch to forecast volatility.
To control plot formatting, set options like figure size and font.
1%matplotlib inline
2import numpy as np
3import yfinance as yf
4from arch import arch_model
5
6import matplotlib.pyplot as plt
7plt.rc("figure", figsize=(16, 6))
8plt.rc("font", family="sans-serif")
9plt.rc("font", size=14)
After the imports, grab some data.
1data = yf.download("AAPL", start="2020-01-01", end="2022-07-31")
Compute the simple returns and multiply by 100 to avoid the scaling warning from arch_model.
1adjusted_closes = data['Adj Close']
2returns = 100 * adjusted_closes.pct_change().dropna()
Step 2: Fit a GARCH model
Fitting a GARCH model is one line of code.
1model = 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
You can adjust these values - and even build your own mean and variance models - as inputs. Check out the documentation if you're interested.
After you define the model, fit it.
1res = model.fit()
The library uses an iterative algorithm called maximum likelihood estimation to fit the model parameters. Details of each iteration prints to the screen.
Step 3: Forecast volatility
Now the model is fit. Check the summary.
![Find market mispricings like the pros with GARCH](https://cdn.prod.website-files.com/6606adcab6ed6464b674ad71/66c8fcb357644a8b6dfb4849_662df5a24b5440799210d88a_K4GEtEsFlMRGwgpVjR_U8OFTh_ob7VVF9NNYZSGqjMNSa1znj69a1_-gfaYuIOpSMfdrDLpM7Jt1f2yfyHjIyytbtLu0j905rYAzjBZnZ4z_4XaafwajFTCsIeDxbD3kXIWl2J4%253Ds0-d-e1-ft.jpeg)
It shows the statistical significance of each of the coefficients. They all have very small p-values. We can assume the results are not due to random chance.
You can visualize the standardized residuals and conditional volatility.
![Find market mispricings like the pros with GARCH](https://cdn.prod.website-files.com/6606adcab6ed6464b674ad71/66c8fcb457644a8b6dfb4866_662df5a24b5440799210d886_VPF5eKuLotMmwy60bzxOWl-IUaWXM36dzRLHZQYkEI9qa2sdsfAiXcaEo6qrod5ayTfPzibA0R2sjM_Xt0Nk-qEsUyx3HUYXl_kigWnEHi0aC85cpF7KUQhzuh39HtH6bQpaqyA%253Ds0-d-e1-ft.jpeg)
Control the number of forecasts with the horizon argument. I use the first forecast in this example.
1# get the variance forecast
2forecast = res.forecast(horizon=1, reindex=False)
3variance_forecast = forecast.variance.iloc[-1][0]
4
5# compute the annualized volatility forecast
6volatility_forecast = np.sqrt(variance_forecast)
7annualized_volatility_forecast = volatility_forecast * np.sqrt(252) / 100
The library returns the variance forecast. To convert that to a volatility number, take the sqaure root. Then annualize it.
Step 3: Find a mispricing
Compare the standard deviation of returns to the GARCH volatility forecast. There’s a 10.7% difference. Use an options calculator and value an option using both volatility inputs.
![Find market mispricings like the pros with GARCH](https://cdn.prod.website-files.com/6606adcab6ed6464b674ad71/66c8fcb357644a8b6dfb4836_662df5a14b5440799210d87d_R0VcAdzCYQULRS38NZJmdFq5PYoG3CxIGJtV1lLl9JgZWGI2AlROBdlEMocb6A7Ej5ZJTEZ97rw7ehcdxk2NuQojMWeY_a3FCyTX-Pcmhn2-QxWXxBAKI2vP6URyFLQSAcinnlM%253Ds0-d-e1-ft.jpeg)
The value of a call option using the GARCH forecast for volatility is $10.12.
![Find market mispricings like the pros with GARCH](https://cdn.prod.website-files.com/6606adcab6ed6464b674ad71/66c8fcb357644a8b6dfb4839_662df5a14b5440799210d881_MFjMfn7_YvdUpzYG1H2h8ctxLX1YAGKEn4GuDq0mASICQx6G6-UjDMNWSNl7LvPCD0I0akCyMrqRV9uTJoUYRYadF5hKL7I59uycJT0ycoRByD6_r3DMCiyZ3bzO3oC3_uAopyI%253Ds0-d-e1-ft.jpeg)
The value of a call option using historical volatility is $11.22.
If you believe the GARCH model is more accurate than the historical volatility in forecasting volatility, you’d sell this call option.
![Man with glasses and a wristwatch, wearing a white shirt, looking thoughtfully at a laptop with a data screen in the background.](https://cdn.prod.website-files.com/6604815bfffc39e4941bd158/66070439083cb3ca5c1d1c34_cta%20image.webp)