/* * 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 QuantConnect.Brokerages.Backtesting; using QuantConnect.Data.Market; using QuantConnect.Interfaces; using QuantConnect.Lean.Engine.Results; using QuantConnect.Logging; using QuantConnect.Orders; using QuantConnect.Util; namespace QuantConnect.Lean.Engine.TransactionHandlers { /// /// This transaction handler is used for processing transactions during backtests /// public class BacktestingTransactionHandler : BrokerageTransactionHandler { // save off a strongly typed version of the brokerage private BacktestingBrokerage _brokerage; private IAlgorithm _algorithm; private Delistings _lastestDelistings; /// /// Gets current time UTC. This is here to facilitate testing /// protected override DateTime CurrentTimeUtc => _algorithm.UtcTime; /// /// Creates a new BacktestingTransactionHandler using the BacktestingBrokerage /// /// The algorithm instance /// The BacktestingBrokerage /// public override void Initialize(IAlgorithm algorithm, IBrokerage brokerage, IResultHandler resultHandler) { if (!(brokerage is BacktestingBrokerage)) { throw new ArgumentException("Brokerage must be of type BacktestingBrokerage for use wth the BacktestingTransactionHandler"); } _brokerage = (BacktestingBrokerage)brokerage; _algorithm = algorithm; base.Initialize(algorithm, brokerage, resultHandler); } /// /// For backtesting order requests are processed synchronously by the algorithm thread, only live /// deployments with a concurrency enabled brokerage use background transaction threads /// protected override bool SynchronousProcessing => !(ConcurrencyEnabled && _algorithm.LiveMode); /// /// Processes all synchronous events that must take place before the next time loop for the algorithm /// public override void ProcessSynchronousEvents() { if (SynchronousProcessing) { // we process pending order requests our selves ProcessPendingRequests(); } base.ProcessSynchronousEvents(); _brokerage.Scan(); // Run our delistings processing, only do this once a slice if (_algorithm.CurrentSlice != null && _algorithm.CurrentSlice.Delistings != _lastestDelistings) { _lastestDelistings = _algorithm.CurrentSlice.Delistings; _brokerage.ProcessDelistings(_algorithm.CurrentSlice.Delistings); } } /// /// Processes asynchronous events on the transaction handler's thread /// public override void ProcessAsynchronousEvents() { base.ProcessAsynchronousEvents(); _brokerage.Scan(); } /// /// For backtesting we will submit the order ourselves /// /// The expecting to be submitted protected override void WaitForOrderSubmission(OrderTicket ticket) { if (!SynchronousProcessing) { // let the base class handle this base.WaitForOrderSubmission(ticket); return; } // we submit the order request our selves ProcessPendingRequests(); if (!ticket.OrderSet.WaitOne(0)) { // this could happen if there was some error handling the order // and it was not set Log.Error("BacktestingTransactionHandler.WaitForOrderSubmission(): " + $"The order request (Id={ticket.OrderId}) was not submitted. " + "See the OrderRequest.Response for more information"); } } } }