Custom Volatility Model Using Rolling Standard Deviation of Returns
Summary
This QuantConnect example implements a custom security volatility model using a rolling window of daily returns. At each qualifying price update, it computes the return since the last stored price, adds it to the window, and, once the window is ready, calculates the standard deviation of its values. The estimate is annualized by multiplying by the square root of 252. The example attaches the model to daily SPY data and enters a fully invested position when the reported volatility becomes positive; it does not use volatility to scale position size or choose trade direction.
The code illustrates the platform’s required model interface and a straightforward way to estimate realized volatility from sampled returns. It sets a sample period and cash amount, but reports no backtest outcomes, comparison with another estimator, or evidence that the entry rule has merit. The model updates at most once per day and does not specify history requirements, so early estimates depend on live updates filling the rolling window. Its simple standard deviation estimate may not capture changing volatility well, and the example’s buy condition should not be mistaken for a validated volatility strategy.
Key ideas
- The model estimates realized volatility from a rolling window of daily price returns.
- It annualizes the return standard deviation using the square root of 252.
- The example applies the model to daily SPY data and buys when its estimate is positive.
- The example provides no performance results and does not use volatility for position sizing.
- Early estimates depend on accumulating enough updates because no history request is specified.
Tags
Full text
# CustomVolatilityModelAlgorithm
# CustomVolatilityModelAlgorithm
Example of custom volatility model
## Source (Apache-2.0)
```python
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from AlgorithmImports import *
### <summary>
### Example of custom volatility model
### </summary>
### <meta name="tag" content="using quantconnect" />
### <meta name="tag" content="indicators" />
### <meta name="tag" content="reality modelling" />
class CustomVolatilityModelAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2013,10,7) #Set Start Date
self.set_end_date(2015,7,15) #Set End Date
self.set_cash(100000) #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.equity = self.add_equity("SPY", Resolution.DAILY)
self.equity.set_volatility_model(CustomVolatilityModel(10))
def on_data(self, data):
if not self.portfolio.invested and self.equity.volatility_model.volatility > 0:
self.set_holdings("SPY", 1)
# Python implementation of StandardDeviationOfReturnsVolatilityModel
# Computes the annualized sample standard deviation of daily returns as the volatility of the security
# https://github.com/QuantConnect/Lean/blob/master/Common/Securities/Volatility/StandardDeviationOfReturnsVolatilityModel.cs
class CustomVolatilityModel():
def __init__(self, periods):
self.last_update = datetime.min
self.last_price = 0
self.needs_update = False
self.period_span = timedelta(1)
self.window = RollingWindow(periods)
# Volatility is a mandatory attribute
self.volatility = 0
# Updates this model using the new price information in the specified security instance
# Update is a mandatory method
def update(self, security, data):
time_since_last_update = data.end_time - self.last_update
if time_since_last_update >= self.period_span and data.price > 0:
if self.last_price > 0:
self.window.add(float(data.price / self.last_price) - 1.0)
self.needs_update = self.window.is_ready
self.last_update = data.end_time
self.last_price = data.price
if self.window.count < 2:
self.volatility = 0
return
if self.needs_update:
self.needs_update = False
std = np.std([ x for x in self.window ])
self.volatility = std * np.sqrt(252.0)
# Returns history requirements for the volatility model expressed in the form of history request
# GetHistoryRequirements is a mandatory method
def get_history_requirements(self, security, utc_time):
# For simplicity's sake, we will not set a history requirement
return None
```Shown in full with attribution under the source's licence. Licence: Apache-2.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.