/*
* 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