软件工程师的量化交易之路(39)-Lean之BacktestingRealTimeHandler回测实时时间事件处理7

程序员的量化交易之路(39)--Lean之BacktestingRealTimeHandler回测实时时间事件处理7

</pre>转载需注明出处:<a target=_blank href="http://blog.csdn.net/minimicall?viewmode=contents">http://blog.csdn.net/minimicall?viewmode=contents</a>,<a target=_blank href="http://cloudtrade.top/">http://cloudtrade.top/</a></p><p></p><p>上一节已经说明了实时事件和处理接口。这一节需要说明回测里面的实时事件处理。主要是开启一个新的线程来处理定时事件。例如每天开市的时候的事件和每天闭市时候触发的事件。还有你可以定义任意一个给定时间的事件。</p><p>下面我们通过代码来说 明问题</p><p><pre name="code" class="csharp">/*
 * 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 System.Threading;
using QuantConnect.Interfaces;
using QuantConnect.Packets;
using QuantConnect.Logging;

namespace QuantConnect.Lean.Engine.RealTime
{
    /// <summary>
    /// Psuedo realtime event processing for backtesting to simulate realtime events in fast forward.
    /// 伪实时事件处理,为回归测试实时事件(快进)
    /// </summary>
    public class BacktestingRealTimeHandler : IRealTimeHandler
    {
        /******************************************************** 
        * PRIVATE VARIABLES
        *********************************************************/
        //Threading
        private DateTime _time = new DateTime();
        private bool _exitTriggered;
        private bool _isActive = true;
        private AlgorithmNodePacket _job;//相关任务

        //Events:
        private List<RealTimeEvent> _events;

        //Algorithm and Handlers:
        private IAlgorithm _algorithm;//相关算法
        private Dictionary<SecurityType, MarketToday> _today;//今日市场

        /******************************************************** 
        * PUBLIC PROPERTIES
        *********************************************************/
        /// <summary>
        /// Realtime Moment.
        /// </summary>
        public DateTime Time
        {
            get
            {
                return _time;
            }
        }

        /// <summary>
        /// Events array we scan to trigger realtime events.
        /// </summary>
        public List<RealTimeEvent> Events
        {
            get 
            {
                return _events;
            }
        }

        /// <summary>
        /// Flag indicating the hander thread is completely finished and ready to dispose.
        /// </summary>
        public bool IsActive
        {
            get
            {
                return _isActive;
            }
        }

        /// <summary>
        /// Market hours for today for each security type in the algorithm
        /// 为算法中每种证券类型的今日交易时间(例如股票和黄金的交易时间就不一样的,如果该算法涉及到这两种证券类型)
        /// </summary>
        public Dictionary<SecurityType, MarketToday> MarketToday
        {
            get
            {
                throw new NotImplementedException("MarketToday is not currently needed in backtesting mode");//回归测试不需要
                return _today;
            }
        }

        /******************************************************** 
        * PUBLIC CONSTRUCTOR
        *********************************************************/
        /// <summary>
        /// Setup the algorithm data, cash, job start end date etc.
        /// 设置算法数据、现金、任务开始和结束时间等信息,通过algorithm和job即可
        /// </summary>
        public BacktestingRealTimeHandler(IAlgorithm algorithm, AlgorithmNodePacket job) 
        {
            //Initialize:
            _algorithm = algorithm;
            _events = new List<RealTimeEvent>();
            _job = job;
            _today = new Dictionary<SecurityType, MarketToday>();
        }

        /******************************************************** 
        * PUBLIC METHODS
        *********************************************************/
        /// <summary>
        /// Setup the events for this date.
        /// 设置该日的事件
        /// </summary>
        /// <param name="date">Date for event</param>
        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.Debug("BacktestingRealTimeHandler.SetupEvents(): Adding End of Day: " + security.Exchange.MarketClose.Add(TimeSpan.FromMinutes(-10)));

                //1. Setup End of Day Events:
                //设置事件结束时间(23:50)
                var closingToday = date.Date + security.Exchange.MarketClose.Add(TimeSpan.FromMinutes(-10));
                var symbol = security.Symbol;//证券代号
                AddEvent(new RealTimeEvent( closingToday, () =>
                {//匿名方法
                    try
                    {
                        _algorithm.OnEndOfDay(symbol);//在一天闭市的时候会调用该函数
                    }
                    catch (Exception err)
                    {
                        Engine.ResultHandler.RuntimeError("Runtime error in OnEndOfDay event: " + err.Message, err.StackTrace);
                        Log.Error("BacktestingRealTimeHandler.SetupEvents(): EOD: " + err.Message);
                    }
                }));
            }

            // fire just before the day rolls over, 11:58pm在一天即将结束的时候调用。。。。(尼玛,和上面究竟啥子关系)
            AddEvent(new RealTimeEvent(date.AddHours(23.967), () =>
            {//匿名方法
                try
                {
                    _algorithm.OnEndOfDay();
                    Log.Trace(string.Format("BacktestingRealTimeHandler: Fired On End of Day Event() for Day({0})", _time.ToShortDateString()));
                }
                catch (Exception err)
                {
                    Engine.ResultHandler.RuntimeError("Runtime error in OnEndOfDay event: " + err.Message, err.StackTrace);
                    Log.Error("BacktestingRealTimeHandler.SetupEvents.Trigger OnEndOfDay(): " + err.Message);
                }
            }, true));
        }
        
        /// <summary>
        /// Normally this would run the realtime event monitoring. Backtesting is in fastforward so the realtime is linked to the backtest clock.
        /// This thread does nothing. Wait until the job is over.
        /// </summary>
        public void Run()
        {
            _isActive = false;
        }


        /// <summary>
        /// Add a new event to our list of events to scan.
        /// </summary>
        /// <param name="newEvent">Event object to montitor daily.</param>
        public void AddEvent(RealTimeEvent newEvent)
        {
            _events.Add(newEvent);
        }

        /// <summary>
        /// Scan the event list with the current market time and see if we need to trigger the callback.
        /// </summary>
        public void ScanEvents()
        {
            for (var i = 0; i < _events.Count; i++)
            {
                _events[i].Scan(_time);
            }
        }

        /// <summary>
        /// Clear any outstanding events.
        /// </summary>
        public void ClearEvents()
        {
            _events.Clear();
        }

        /// <summary>
        /// Reset the events for a new day.
        /// </summary>
        public void ResetEvents()
        {
            for (var i = 0; i < _events.Count; i++)
            {
                _events[i].Reset();
            }
        }


        /// <summary>
        /// Set the time for the realtime event handler.
        /// </summary>
        /// <param name="time">Current time.</param>
        public void SetTime(DateTime time)
        {
            //Check for day reset:
            if (_time.Date != time.Date)
            {
                // Backtest Mode Only: 
                // > Scan & trigger any remaining events which haven't been triggered (e.g. daily bar data with "daily event" at 4pm):
                ScanEvents();

                //Reset all the daily events with today's date:
                SetupEvents(time.Date);
            }

            //Set the time:
            _time = time;

            // Backtest Mode Only: 
            // > Scan the event every time we set the time. This allows "fast-forwarding" of the realtime events into sync with backtest.
            ScanEvents();
        }

        /// <summary>
        /// Stop the real time thread
        /// </summary>
        public void Exit()
        {
            _exitTriggered = true;
        }

    } // End Result Handler Thread:

} // End Namespace