/* * 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. */ using System; using System.Collections.Generic; using MathNet.Numerics.Statistics; using QuantConnect.Data; using QuantConnect.Indicators; using QuantConnect.Securities.Volatility; namespace QuantConnect.Securities { /// /// Provides an implementation of that computes the /// annualized sample standard deviation of daily returns as the volatility of the security /// public class StandardDeviationOfReturnsVolatilityModel : BaseVolatilityModel { private bool _needsUpdate; private decimal _volatility; private DateTime _lastUpdate = DateTime.MinValue; private decimal _lastPrice; private Resolution? _resolution; private TimeSpan _periodSpan; private readonly object _sync = new object(); private RollingWindow _window; /// /// Gets the volatility of the security as a percentage /// public override decimal Volatility { get { lock (_sync) { if (_window.Count < 2) { return 0m; } if (_needsUpdate) { _needsUpdate = false; var std = _window.StandardDeviation().SafeDecimalCast(); _volatility = std * (decimal)Math.Sqrt(252.0); } } return _volatility; } } /// /// Initializes a new instance of the class /// /// The max number of samples in the rolling window to be considered for calculating the standard deviation of returns /// /// Resolution of the price data inserted into the rolling window series to calculate standard deviation. /// Will be used as the default value for update frequency if a value is not provided for . /// This only has a material effect in live mode. For backtesting, this value does not cause any behavioral changes. /// /// Frequency at which we insert new values into the rolling window for the standard deviation calculation /// /// The volatility model will be updated with the most granular/highest resolution data that was added to your algorithm. /// That means that if I added data for my Futures strategy, that this model will be /// updated using data as the algorithm progresses in time. /// /// Keep this in mind when setting the period and update frequency. The Resolution parameter is only used for live mode, or for /// the default value of the if no value is provided. /// public StandardDeviationOfReturnsVolatilityModel( int periods, Resolution? resolution = null, TimeSpan? updateFrequency = null ) { if (periods < 2) { throw new ArgumentOutOfRangeException(nameof(periods), "'periods' must be greater than or equal to 2."); } _window = new RollingWindow(periods); _resolution = resolution; _periodSpan = updateFrequency ?? resolution?.ToTimeSpan() ?? TimeSpan.FromDays(1); } /// /// Initializes a new instance of the class /// /// /// Resolution of the price data inserted into the rolling window series to calculate standard deviation. /// Will be used as the default value for update frequency if a value is not provided for . /// This only has a material effect in live mode. For backtesting, this value does not cause any behavioral changes. /// /// Frequency at which we insert new values into the rolling window for the standard deviation calculation /// /// The volatility model will be updated with the most granular/highest resolution data that was added to your algorithm. /// That means that if I added data for my Futures strategy, that this model will be /// updated using data as the algorithm progresses in time. /// /// Keep this in mind when setting the period and update frequency. The Resolution parameter is only used for live mode, or for /// the default value of the if no value is provided. /// public StandardDeviationOfReturnsVolatilityModel( Resolution resolution, TimeSpan? updateFrequency = null ) : this(PeriodsInResolution(resolution), resolution, updateFrequency) { } /// /// Updates this model using the new price information in /// the specified security instance /// /// The security to calculate volatility for /// Data to update the volatility model with public override void Update(Security security, BaseData data) { var timeSinceLastUpdate = data.EndTime - _lastUpdate; if (timeSinceLastUpdate >= _periodSpan && data.Price > 0) { lock (_sync) { if (_lastPrice > 0.0m) { _needsUpdate = true; _window.Add((double)(data.Price / _lastPrice) - 1.0); } } _lastUpdate = data.EndTime; _lastPrice = data.Price; } } /// /// Returns history requirements for the volatility model expressed in the form of history request /// /// The security of the request /// The date of the request /// History request object list, or empty if no requirements public override IEnumerable GetHistoryRequirements(Security security, DateTime utcTime) { // Let's reset the model since it will get warmed up again using these history requirements Reset(); return GetHistoryRequirements( security, utcTime, _resolution, _window.Size + 1); } /// /// Resets the model to its initial state /// private void Reset() { _needsUpdate = false; _volatility = 0m; _lastUpdate = DateTime.MinValue; _lastPrice = 0m; _window.Reset(); } private static int PeriodsInResolution(Resolution resolution) { int periods; switch (resolution) { case Resolution.Tick: case Resolution.Second: periods = 600; break; case Resolution.Minute: periods = 60 * 24; break; case Resolution.Hour: periods = 24 * 30; break; default: periods = 30; break; } return periods; } } }