Lean  $LEAN_TAG$
RelativeStandardDeviationVolatilityModel.cs
1 
2 /*
3  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
4  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15 */
16 
17 using System;
18 using MathNet.Numerics.Statistics;
19 using QuantConnect.Data;
21 using System.Collections.Generic;
22 using System.Linq;
24 using QuantConnect.Util;
25 
27 {
28  /// <summary>
29  /// Provides an implementation of <see cref="IVolatilityModel"/> that computes the
30  /// relative standard deviation as the volatility of the security
31  /// </summary>
33  {
34  private bool _needsUpdate;
35  private decimal _volatility;
36  private DateTime _lastUpdate;
37  private readonly TimeSpan _periodSpan;
38  private readonly object _sync = new object();
39  private readonly RollingWindow<double> _window;
40 
41  /// <summary>
42  /// Gets the volatility of the security as a percentage
43  /// </summary>
44  public override decimal Volatility
45  {
46  get
47  {
48  lock (_sync)
49  {
50  if (_window.Count < 2)
51  {
52  return 0m;
53  }
54 
55  if (_needsUpdate)
56  {
57  _needsUpdate = false;
58  var mean = Math.Abs(_window.Mean().SafeDecimalCast());
59  if (mean != 0m)
60  {
61  // volatility here is supposed to be a percentage
62  var std = _window.StandardDeviation().SafeDecimalCast();
63  _volatility = std / mean;
64  }
65  }
66  }
67  return _volatility;
68  }
69  }
70 
71  /// <summary>
72  /// Initializes a new instance of the <see cref="RelativeStandardDeviationVolatilityModel"/> class
73  /// </summary>
74  /// <param name="periodSpan">The time span representing one 'period' length</param>
75  /// <param name="periods">The number of 'period' lengths to wait until updating the value</param>
77  TimeSpan periodSpan,
78  int periods)
79  {
80  if (periods < 2) throw new ArgumentOutOfRangeException(nameof(periods), "'periods' must be greater than or equal to 2.");
81  _periodSpan = periodSpan;
82  _window = new RollingWindow<double>(periods);
83  _lastUpdate = GetLastUpdateInitialValue(periodSpan, periods);
84  }
85 
86  /// <summary>
87  /// Updates this model using the new price information in
88  /// the specified security instance
89  /// </summary>
90  /// <param name="security">The security to calculate volatility for</param>
91  /// <param name="data"></param>
92  public override void Update(Security security, BaseData data)
93  {
94  var timeSinceLastUpdate = data.EndTime - _lastUpdate;
95  if (timeSinceLastUpdate >= _periodSpan && data.Price > 0)
96  {
97  lock (_sync)
98  {
99  _needsUpdate = true;
100  _window.Add((double)data.Price);
101  }
102  _lastUpdate = data.EndTime;
103  }
104  }
105 
106  /// <summary>
107  /// Returns history requirements for the volatility model expressed in the form of history request
108  /// </summary>
109  /// <param name="security">The security of the request</param>
110  /// <param name="utcTime">The date/time of the request</param>
111  /// <returns>History request object list, or empty if no requirements</returns>
112  public override IEnumerable<HistoryRequest> GetHistoryRequirements(Security security, DateTime utcTime)
113  {
114  if (SubscriptionDataConfigProvider == null)
115  {
116  throw new InvalidOperationException(
117  "RelativeStandardDeviationVolatilityModel.GetHistoryRequirements(): " +
118  "SubscriptionDataConfigProvider was not set."
119  );
120  }
121 
122  // Let's reset the model since it will get warmed up again using these history requirements
123  Reset();
124 
125  var configurations = SubscriptionDataConfigProvider
126  .GetSubscriptionDataConfigs(security.Symbol)
127  .OrderBy(c => c.TickType)
128  .ToList();
129 
130  return GetHistoryRequirements(
131  security,
132  utcTime,
133  configurations.GetHighestResolution(),
134  _window.Size + 1);
135  }
136 
137  /// <summary>
138  /// Resets the model to its initial state
139  /// </summary>
140  private void Reset()
141  {
142  _needsUpdate = false;
143  _volatility = 0m;
144  _lastUpdate = GetLastUpdateInitialValue(_periodSpan, _window.Size);
145  _window.Reset();
146  }
147 
148  private static DateTime GetLastUpdateInitialValue(TimeSpan periodSpan, int periods)
149  {
150  return DateTime.MinValue + TimeSpan.FromMilliseconds(periodSpan.TotalMilliseconds * periods);
151  }
152  }
153 }