Skip to content

Commit e64d089

Browse files
committed
Add one more unit test
1 parent 992d4cb commit e64d089

File tree

2 files changed

+110
-8
lines changed

2 files changed

+110
-8
lines changed

Engine/RealTime/LiveTradingRealTimeHandler.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ private void Run()
119119
protected void RefreshMarketHoursToday(DateTime date)
120120
{
121121
date = date.Date;
122-
MarketHoursDatabase.Reset();
122+
ResetMarketHoursDatabase();
123123

124124
// update market hours for each security
125125
foreach (var kvp in Algorithm.Securities)
@@ -201,5 +201,15 @@ protected virtual IEnumerable<MarketHoursSegment> GetMarketHours(DateTime time,
201201
yield return segment;
202202
}
203203
}
204+
205+
/// <summary>
206+
/// Resets the market hours database, forcing a reload when reused.
207+
/// Called in tests where multiple algorithms are run sequentially,
208+
/// and we need to guarantee that every test starts with the same environment.
209+
/// </summary>
210+
protected virtual void ResetMarketHoursDatabase()
211+
{
212+
MarketHoursDatabase.Reset();
213+
}
204214
}
205215
}

Tests/Engine/RealTime/LiveTradingRealTimeHandlerTests.cs

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
using System.Linq;
2626
using QuantConnect.Securities;
2727
using System.Collections.Generic;
28+
using QuantConnect.Data.Market;
29+
using QuantConnect.Lean.Engine.TransactionHandlers;
30+
using Moq;
31+
using QuantConnect.Brokerages.Backtesting;
32+
using static QuantConnect.Tests.Engine.BrokerageTransactionHandlerTests.BrokerageTransactionHandlerTests;
33+
using QuantConnect.Orders;
34+
using System.Reflection;
35+
using QuantConnect.Lean.Engine.HistoricalData;
2836

2937
namespace QuantConnect.Tests.Engine.RealTime
3038
{
@@ -81,14 +89,65 @@ public void RefreshesMarketHoursCorrectly(SecurityExchangeHours securityExchange
8189
null,
8290
new TestTimeLimitManager());
8391

84-
var time = new DateTime(2023, 5, 28).Date;
92+
var time = new DateTime(2023, 5, 30).Date;
8593
var entry = new MarketHoursDatabase.Entry(TimeZones.NewYork, securityExchangeHours);
8694
var key = new SecurityDatabaseKey(Market.USA, null, SecurityType.Equity);
8795
var mhdb = new MarketHoursDatabase(new Dictionary<SecurityDatabaseKey, MarketHoursDatabase.Entry>() { { key, entry} });
8896
realTimeHandler.SetMarketHoursDatabase(mhdb);
8997
realTimeHandler.TestRefreshMarketHoursToday(security, time, expectedSegment);
9098
}
9199

100+
[Test]
101+
public void ResetMarketHoursCorrectly()
102+
{
103+
var algorithm = new TestAlgorithm { HistoryProvider = new FakeHistoryProvider() };
104+
algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm));
105+
algorithm.SetCash(100000);
106+
algorithm.SetStartDate(2023, 5, 30);
107+
algorithm.SetEndDate(2023, 5, 30);
108+
var security = algorithm.AddEquity("SPY");
109+
security.Exchange = new SecurityExchange(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork));
110+
var symbol = security.Symbol;
111+
algorithm.SetFinishedWarmingUp();
112+
113+
var handleOptionNotification = typeof(BrokerageTransactionHandler).GetMethod("HandleOptionNotification", BindingFlags.NonPublic | BindingFlags.Instance);
114+
115+
var transactionHandler = new TestBrokerageTransactionHandler();
116+
var broker = new BacktestingBrokerage(algorithm);
117+
transactionHandler.Initialize(algorithm, broker, new BacktestingResultHandler());
118+
119+
// Creates a market order
120+
security.SetMarketPrice(new TradeBar(new DateTime(2023, 5, 30), symbol, 280m, 280m, 280m, 280m, 100));
121+
122+
var orderRequest = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, 1, 0, 0, new DateTime(2023, 5, 30), "TestTag1");
123+
124+
var orderProcessorMock = new Mock<IOrderProcessor>();
125+
orderProcessorMock.Setup(m => m.GetOrderTicket(It.IsAny<int>())).Returns(new OrderTicket(algorithm.Transactions, orderRequest));
126+
algorithm.Transactions.SetOrderProcessor(orderProcessorMock.Object);
127+
var orderTicket = transactionHandler.Process(orderRequest);
128+
transactionHandler.HandleOrderRequest(orderRequest);
129+
Assert.IsTrue(orderTicket.Status == OrderStatus.Submitted);
130+
broker.Scan();
131+
Assert.IsTrue(orderTicket.Status == OrderStatus.Filled);
132+
133+
var realTimeHandler = new TestLiveTradingRealTimeHandlerReset();
134+
realTimeHandler.Setup(algorithm,
135+
new AlgorithmNodePacket(PacketType.AlgorithmNode),
136+
new BacktestingResultHandler(),
137+
null,
138+
new TestTimeLimitManager());
139+
realTimeHandler.AddRefreshHoursScheduledEvent();
140+
141+
orderRequest = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, 1, 0, 0, new DateTime(2023, 5, 30), "TestTag2");
142+
orderRequest.SetOrderId(2);
143+
orderTicket = transactionHandler.Process(orderRequest);
144+
transactionHandler.HandleOrderRequest(orderRequest);
145+
Assert.IsTrue(orderTicket.Status == OrderStatus.Submitted);
146+
broker.Scan();
147+
Assert.IsTrue(orderTicket.Status != OrderStatus.Filled);
148+
realTimeHandler.Exit();
149+
}
150+
92151
private class TestTimeLimitManager : IIsolatorLimitResultProvider
93152
{
94153
public IsolatorLimitResult IsWithinLimit()
@@ -153,6 +212,39 @@ public void AssertMarketHours(Security security, DateTime time, MarketHoursSegme
153212
}
154213
}
155214

215+
public class TestLiveTradingRealTimeHandlerReset : LiveTradingRealTimeHandler
216+
{
217+
private static AutoResetEvent OnSecurityUpdated = new AutoResetEvent(false);
218+
219+
public void AddRefreshHoursScheduledEvent()
220+
{
221+
Add(new ScheduledEvent("RefreshHours", new[] { new DateTime(2023, 6, 29) }, (name, triggerTime) =>
222+
{
223+
// refresh market hours from api every day
224+
RefreshMarketHoursToday((new DateTime(2023, 5, 30)).Date);
225+
}));
226+
OnSecurityUpdated.Reset();
227+
SetTime(DateTime.UtcNow);
228+
OnSecurityUpdated.WaitOne();
229+
Exit();
230+
}
231+
232+
protected override IEnumerable<MarketHoursSegment> GetMarketHours(DateTime time, Symbol symbol)
233+
{
234+
var results = base.GetMarketHours(time, symbol);
235+
OnSecurityUpdated.Set();
236+
return results;
237+
}
238+
239+
protected override void ResetMarketHoursDatabase()
240+
{
241+
var entry = new MarketHoursDatabase.Entry(TimeZones.NewYork, ExchangeHoursDataClass.CreateExchangeHoursWithHolidays());
242+
var key = new SecurityDatabaseKey(Market.USA, null, SecurityType.Equity);
243+
var mhdb = new MarketHoursDatabase(new Dictionary<SecurityDatabaseKey, MarketHoursDatabase.Entry>() { { key, entry } });
244+
MarketHoursDatabase = mhdb;
245+
}
246+
}
247+
156248
public class ExchangeHoursDataClass
157249
{
158250
private static LocalMarketHours _sunday = new LocalMarketHours(DayOfWeek.Sunday, new TimeSpan(9, 30, 0), new TimeSpan(16, 0, 0));
@@ -176,8 +268,8 @@ public static IEnumerable<TestCaseData> TestCases
176268

177269
private static SecurityExchangeHours CreateExchangeHoursWithEarlyCloseAndLateOpen()
178270
{
179-
var earlyCloses = new Dictionary<DateTime, TimeSpan> { { new DateTime(2023, 5, 28).Date, new TimeSpan(13, 0, 0) } };
180-
var lateOpens = new Dictionary<DateTime, TimeSpan>() { { new DateTime(2023, 5, 28).Date, new TimeSpan(10, 0, 0) } };
271+
var earlyCloses = new Dictionary<DateTime, TimeSpan> { { new DateTime(2023, 5, 30).Date, new TimeSpan(13, 0, 0) } };
272+
var lateOpens = new Dictionary<DateTime, TimeSpan>() { { new DateTime(2023, 5, 30).Date, new TimeSpan(10, 0, 0) } };
181273
var exchangeHours = new SecurityExchangeHours(TimeZones.NewYork, new List<DateTime>(), new[]
182274
{
183275
_sunday, _monday, _tuesday, _wednesday, _thursday, _friday, _saturday
@@ -187,7 +279,7 @@ private static SecurityExchangeHours CreateExchangeHoursWithEarlyCloseAndLateOpe
187279

188280
private static SecurityExchangeHours CreateExchangeHoursWithEarlyClose()
189281
{
190-
var earlyCloses = new Dictionary<DateTime, TimeSpan> { { new DateTime(2023, 5, 28).Date, new TimeSpan(13, 0, 0) } };
282+
var earlyCloses = new Dictionary<DateTime, TimeSpan> { { new DateTime(2023, 5, 30).Date, new TimeSpan(13, 0, 0) } };
191283
var lateOpens = new Dictionary<DateTime, TimeSpan>();
192284
var exchangeHours = new SecurityExchangeHours(TimeZones.NewYork, new List<DateTime>(), new[]
193285
{
@@ -199,19 +291,19 @@ private static SecurityExchangeHours CreateExchangeHoursWithEarlyClose()
199291
private static SecurityExchangeHours CreateExchangeHoursWithLateOpen()
200292
{
201293
var earlyCloses = new Dictionary<DateTime, TimeSpan>();
202-
var lateOpens = new Dictionary<DateTime, TimeSpan>() { { new DateTime(2023, 5, 28).Date, new TimeSpan(10, 0, 0) } };
294+
var lateOpens = new Dictionary<DateTime, TimeSpan>() { { new DateTime(2023, 5, 30).Date, new TimeSpan(10, 0, 0) } };
203295
var exchangeHours = new SecurityExchangeHours(TimeZones.NewYork, new List<DateTime>(), new[]
204296
{
205297
_sunday, _monday, _tuesday, _wednesday, _thursday, _friday, _saturday
206298
}.ToDictionary(x => x.DayOfWeek), earlyCloses, lateOpens);
207299
return exchangeHours;
208300
}
209301

210-
private static SecurityExchangeHours CreateExchangeHoursWithHolidays()
302+
public static SecurityExchangeHours CreateExchangeHoursWithHolidays()
211303
{
212304
var earlyCloses = new Dictionary<DateTime, TimeSpan>();
213305
var lateOpens = new Dictionary<DateTime, TimeSpan>();
214-
var holidays = new List<DateTime>() { new DateTime(2023, 5, 28).Date };
306+
var holidays = new List<DateTime>() { new DateTime(2023, 5, 30).Date };
215307
var exchangeHours = new SecurityExchangeHours(TimeZones.NewYork, holidays, new[]
216308
{
217309
_sunday, _monday, _tuesday, _wednesday, _thursday, _friday, _saturday

0 commit comments

Comments
 (0)