Lean  $LEAN_TAG$
RateLimitEnumerator.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15 */
16 
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 
22 {
23  /// <summary>
24  /// Provides augmentation of how often an enumerator can be called. Time is measured using
25  /// an <see cref="ITimeProvider"/> instance and calls to the underlying enumerator are limited
26  /// to a minimum time between each call.
27  /// </summary>
28  public class RateLimitEnumerator<T> : IEnumerator<T>
29  {
30  private T _current;
31  private DateTime _lastCallTime;
32 
33  private readonly ITimeProvider _timeProvider;
34  private readonly IEnumerator<T> _enumerator;
35  private readonly TimeSpan _minimumTimeBetweenCalls;
36 
37  /// <summary>
38  /// Initializes a new instance of the <see cref="RateLimitEnumerator{T}"/> class
39  /// </summary>
40  /// <param name="enumerator">The underlying enumerator to place rate limits on</param>
41  /// <param name="timeProvider">Time provider used for determing the time between calls</param>
42  /// <param name="minimumTimeBetweenCalls">The minimum time allowed between calls to the underlying enumerator</param>
43  public RateLimitEnumerator(IEnumerator<T> enumerator, ITimeProvider timeProvider, TimeSpan minimumTimeBetweenCalls)
44  {
45  _enumerator = enumerator;
46  _timeProvider = timeProvider;
47  _minimumTimeBetweenCalls = minimumTimeBetweenCalls;
48  }
49 
50  /// <summary>
51  /// Advances the enumerator to the next element of the collection.
52  /// </summary>
53  /// <returns>
54  /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
55  /// </returns>
56  /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
57  public bool MoveNext()
58  {
59  // determine time since last successful call, do this on units of the minimum time
60  // this will give us nice round emit times
61  var currentTime = _timeProvider.GetUtcNow().RoundDown(_minimumTimeBetweenCalls);
62  var timeBetweenCalls = currentTime - _lastCallTime;
63 
64  // if within limits, patch it through to move next
65  if (timeBetweenCalls >= _minimumTimeBetweenCalls)
66  {
67  if (!_enumerator.MoveNext())
68  {
69  // our underlying is finished
70  _current = default(T);
71  return false;
72  }
73 
74  // only update last call time on non rate limited requests
75  _lastCallTime = currentTime;
76  _current = _enumerator.Current;
77  }
78  else
79  {
80  // we've been rate limitted
81  _current = default(T);
82  }
83 
84  return true;
85  }
86 
87  /// <summary>
88  /// Sets the enumerator to its initial position, which is before the first element in the collection.
89  /// </summary>
90  /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
91  public void Reset()
92  {
93  _enumerator.Reset();
94  }
95 
96  /// <summary>
97  /// Gets the element in the collection at the current position of the enumerator.
98  /// </summary>
99  /// <returns>
100  /// The element in the collection at the current position of the enumerator.
101  /// </returns>
102  public T Current
103  {
104  get { return _current; }
105  }
106 
107  /// <summary>
108  /// Gets the current element in the collection.
109  /// </summary>
110  /// <returns>
111  /// The current element in the collection.
112  /// </returns>
113  /// <filterpriority>2</filterpriority>
114  object IEnumerator.Current
115  {
116  get { return _current; }
117  }
118 
119  /// <summary>
120  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
121  /// </summary>
122  /// <filterpriority>2</filterpriority>
123  public void Dispose()
124  {
125  _enumerator.Dispose();
126  }
127  }
128 }