Files
quantconnect--lean/Tests/Algorithm/AlgorithmLiveTradingTests.cs
2026-07-13 13:02:50 +08:00

116 lines
5.1 KiB
C#

/*
* 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.Linq;
using System.Threading;
using NUnit.Framework;
using QuantConnect.Algorithm;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Lean.Engine.Results;
using QuantConnect.Lean.Engine.TransactionHandlers;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Tests.Engine.DataFeeds;
namespace QuantConnect.Tests.Algorithm
{
[TestFixture, Parallelizable(ParallelScope.Fixtures)]
public class AlgorithmLiveTradingTests
{
[Test]
public void SetHoldingsTakesIntoAccountPendingMarketOrders()
{
var algorithm = new QCAlgorithm();
algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm));
algorithm.SetLiveMode(false);
var security = algorithm.AddEquity("SPY");
security.Exchange = new SecurityExchange(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork));
security.Exchange.SetLocalDateTimeFrontierProvider(algorithm.TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork));
security.SetMarketPrice(new Tick { Value = 270m });
algorithm.SetFinishedWarmingUp();
using var brokerage = new NullBrokerage();
var transactionHandler = new BrokerageTransactionHandler();
transactionHandler.Initialize(algorithm, brokerage, new LiveTradingResultHandler());
Thread.Sleep(250);
algorithm.Transactions.SetOrderProcessor(transactionHandler);
var symbol = security.Symbol;
// this order should timeout (no fills received within 5 seconds)
algorithm.SetHoldings(symbol, 1m);
Thread.Sleep(2000);
var openOrders = algorithm.Transactions.GetOpenOrders();
Assert.AreEqual(1, openOrders.Count);
// this order should never be submitted because of the pending order
algorithm.SetHoldings(symbol, 1m);
Thread.Sleep(2000);
openOrders = algorithm.Transactions.GetOpenOrders();
Assert.AreEqual(1, openOrders.Count);
transactionHandler.Exit();
}
}
public class NullBrokerage : IBrokerage
{
public virtual void Dispose() {}
#pragma warning disable 0067 // NullBrokerage doesn't use any of these so we will just ignore them
public event EventHandler<List<OrderEvent>> OrdersStatusChanged;
public event EventHandler<OrderEvent> OptionPositionAssigned;
public event EventHandler<OptionNotificationEventArgs> OptionNotification;
public event EventHandler<AccountEvent> AccountChanged;
public event EventHandler<BrokerageMessageEvent> Message;
public event EventHandler<DelistingNotificationEventArgs> DelistingNotification;
public event EventHandler<BrokerageOrderIdChangedEvent> OrderIdChanged;
public event EventHandler<NewBrokerageOrderNotificationEventArgs> NewBrokerageOrderNotification;
public event EventHandler<OrderUpdateEvent> OrderUpdated;
#pragma warning restore 0067
public string Name => "NullBrokerage";
public bool IsConnected { get; } = true;
public List<Order> GetOpenOrders() { return new List<Order>(); }
public List<Holding> GetAccountHoldings() { return new List<Holding>(); }
public List<CashAmount> GetCashBalance() { return new List<CashAmount>(); }
public bool PlaceOrder(Order order) { return true; }
public bool UpdateOrder(Order order) { return true; }
public bool CancelOrder(Order order) { return true; }
public void Connect() {}
public void Disconnect() {}
public bool AccountInstantlyUpdated { get; } = true;
public string AccountBaseCurrency => Currencies.USD;
public virtual IEnumerable<BaseData> GetHistory(HistoryRequest request) { return Enumerable.Empty<BaseData>(); }
public DateTime LastSyncDateTimeUtc { get; } = DateTime.UtcNow;
public bool ConcurrencyEnabled { get; set; }
public bool ShouldPerformCashSync(DateTime currentTimeUtc) { return false; }
public bool PerformCashSync(IAlgorithm algorithm, DateTime currentTimeUtc, Func<TimeSpan> getTimeSinceLastFill) { return true; }
public void OnOrderEvent(OrderEvent orderEvent)
{
OrdersStatusChanged?.Invoke(this, [orderEvent]);
}
}
}