/* * 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 NAMESPACES **********************************************************/ using System; using System.Collections.Generic; using System.Threading; using QuantConnect.Interfaces; using QuantConnect.Packets; namespace QuantConnect.Lean.Engine.RealTime { /// /// Psuedo realtime event processing for backtesting to simulate realtime events in fast forward. /// public class BacktestingRealTimeHandler : IRealTimeHandler { /******************************************************** * PRIVATE VARIABLES *********************************************************/ //Threading private DateTime _time = new DateTime(); private bool _exitTriggered = false; private bool _isActive = true; private AlgorithmNodePacket _job; //Events: private List _events; //Algorithm and Handlers: private IAlgorithm _algorithm; /******************************************************** * PUBLIC PROPERTIES *********************************************************/ /// /// Realtime Moment. /// public DateTime Time { get { return _time; } } /// /// Events array we scan to trigger realtime events. /// public List Events { get { return _events; } } /// /// Flag indicating the hander thread is completely finished and ready to dispose. /// public bool IsActive { get { return _isActive; } } /******************************************************** * PUBLIC CONSTRUCTOR *********************************************************/ /// /// Setup the algorithm data, cash, job start end date etc. /// public BacktestingRealTimeHandler(IAlgorithm algorithm, AlgorithmNodePacket job) { //Initialize: _algorithm = algorithm; _events = new List(); _job = job; } /******************************************************** * PUBLIC METHODS *********************************************************/ /// /// Setup the events for this date. /// /// Date for event public void SetupEvents(DateTime date) { //Clear any existing events: ClearEvents(); //Set up the events: //1. Default End of Day Times: foreach (var security in _algorithm.Securities.Values) { //Register Events: //Log.Trace("BacktestingRealTimeHandler.SetupEvents(): Adding End of Day: " + security.Exchange.MarketClose.Add(TimeSpan.FromMinutes(-10))); //1. Setup End of Day Events: AddEvent(new RealTimeEvent(security.Exchange.MarketClose.Add(TimeSpan.FromMinutes(-10)), () => { _algorithm.OnEndOfDay(); _algorithm.OnEndOfDay(security.Symbol); //Log.Trace("BacktestingRealTimeHandler: Fired On End Of Day Event(" + security.Symbol + ") for Day( " + _time.ToShortDateString() + ")"); })); } } /// /// Normally this would run the realtime event monitoring, but since the backtesting is in fastforward he realtime is linked to the backtest clock. /// This thread does nothing. Wait until the job is over. /// public void Run() { _isActive = true; //Launch Thread: Continue looping until exit triggered: while (!_exitTriggered) { Thread.Sleep(500); } _isActive = false; } /// /// Add a new event to our list of events to scan. /// /// Event object to montitor daily. public void AddEvent(RealTimeEvent newEvent) { _events.Add(newEvent); } /// /// Scan the event list with the current market time and see if we need to trigger the callback. /// public void ScanEvents() { for (var i = 0; i < _events.Count; i++) { _events[i].Scan(_time); } } /// /// Clear any outstanding events. /// public void ClearEvents() { _events.Clear(); } /// /// Reset the events for a new day. /// public void ResetEvents() { for (var i = 0; i < _events.Count; i++) { _events[i].Reset(); } } /// /// Set the time for the realtime event handler. /// /// Current time. public void SetTime(DateTime time) { //Check for day reset: if (_time.Date != time.Date) { //Reset all the daily events SetupEvents(time.Date); ResetEvents(); } //Set the time: _time = time; //Refresh event processing when time manually set: ScanEvents(); } /// /// Stop the real time thread /// public void Exit() { _exitTriggered = true; } } // End Result Handler Thread: } // End Namespace