Lean  $LEAN_TAG$
RealTimeSynchronizedTimer.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 using System;
17 using System.Diagnostics;
18 using System.Threading;
19 
20 namespace QuantConnect
21 {
22  /// <summary>
23  /// Real time timer class for precise callbacks on a millisecond resolution in a self managed thread.
24  /// </summary>
25  /// <remarks>Due to the way Window's system clock works the clock is only accurate to the nearest 16ms. In linux it is accurate to the millisecond.</remarks>
27  {
28  private bool _stopped;
29  private Thread _thread;
30  private TimeSpan _period;
31  private Action<DateTime> _callback = null;
32  private Stopwatch _timer = new Stopwatch();
33  private DateTime _triggerTime;
34  private bool _paused;
35 
36  /// <summary>
37  /// Constructor for Real Time Event Driver:
38  /// </summary>
40  {
41  _period = TimeSpan.FromSeconds(0);
42  _thread = new Thread(Scanner) { IsBackground = true };
43  }
44 
45  /// <summary>
46  /// Trigger an event callback after precisely milliseconds-lapsed.
47  /// This is expensive, it creates a new thread and closely monitors the loop.
48  /// </summary>
49  /// <param name="period">delay period between event callbacks</param>
50  /// <param name="callback">Callback event passed the UTC time the event is intended to be triggered</param>
51  public RealTimeSynchronizedTimer(TimeSpan period, Action<DateTime> callback)
52  {
53  _period = period;
54  _callback = callback;
55  _timer = new Stopwatch();
56  _thread = new Thread(Scanner) { IsBackground = true };
57  _stopped = false;
58  _triggerTime = DateTime.UtcNow.RoundUp(period);
59  }
60 
61  /// <summary>
62  /// Start the synchronized real time timer - fire events at start of each second or minute
63  /// </summary>
64  public void Start()
65  {
66  _timer.Start();
67  _thread.Start();
68  _triggerTime = DateTime.UtcNow.RoundDown(_period).Add(_period);
69  }
70 
71  /// <summary>
72  /// Scan the stopwatch for the desired millisecond delay:
73  /// </summary>
74  public void Scanner()
75  {
76  while (!_stopped)
77  {
78  if (_callback != null && DateTime.UtcNow >= _triggerTime)
79  {
80  _timer.Restart();
81  var triggeredAt = _triggerTime;
82  _triggerTime = DateTime.UtcNow.RoundDown(_period).Add(_period);
83  _callback(triggeredAt);
84  }
85 
86  while (_paused && !_stopped) Thread.Sleep(10);
87  Thread.Sleep(1);
88  }
89  }
90 
91  /// <summary>
92  /// Hang the real time event:
93  /// </summary>
94  public void Pause()
95  {
96  _paused = true;
97  }
98 
99  /// <summary>
100  /// Resume clock
101  /// </summary>
102  public void Resume()
103  {
104  _paused = false;
105  }
106 
107  /// <summary>
108  /// Stop the real time timer:
109  /// </summary>
110  public void Stop()
111  {
112  _stopped = true;
113  }
114 
115  } // End Time Class
116 
117 } // End QC Namespace