25
25
using System . Linq ;
26
26
using QuantConnect . Securities ;
27
27
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 ;
28
36
29
37
namespace QuantConnect . Tests . Engine . RealTime
30
38
{
@@ -81,14 +89,65 @@ public void RefreshesMarketHoursCorrectly(SecurityExchangeHours securityExchange
81
89
null ,
82
90
new TestTimeLimitManager ( ) ) ;
83
91
84
- var time = new DateTime ( 2023 , 5 , 28 ) . Date ;
92
+ var time = new DateTime ( 2023 , 5 , 30 ) . Date ;
85
93
var entry = new MarketHoursDatabase . Entry ( TimeZones . NewYork , securityExchangeHours ) ;
86
94
var key = new SecurityDatabaseKey ( Market . USA , null , SecurityType . Equity ) ;
87
95
var mhdb = new MarketHoursDatabase ( new Dictionary < SecurityDatabaseKey , MarketHoursDatabase . Entry > ( ) { { key , entry } } ) ;
88
96
realTimeHandler . SetMarketHoursDatabase ( mhdb ) ;
89
97
realTimeHandler . TestRefreshMarketHoursToday ( security , time , expectedSegment ) ;
90
98
}
91
99
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
+
92
151
private class TestTimeLimitManager : IIsolatorLimitResultProvider
93
152
{
94
153
public IsolatorLimitResult IsWithinLimit ( )
@@ -153,6 +212,39 @@ public void AssertMarketHours(Security security, DateTime time, MarketHoursSegme
153
212
}
154
213
}
155
214
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
+
156
248
public class ExchangeHoursDataClass
157
249
{
158
250
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
176
268
177
269
private static SecurityExchangeHours CreateExchangeHoursWithEarlyCloseAndLateOpen ( )
178
270
{
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 ) } } ;
181
273
var exchangeHours = new SecurityExchangeHours ( TimeZones . NewYork , new List < DateTime > ( ) , new [ ]
182
274
{
183
275
_sunday , _monday , _tuesday , _wednesday , _thursday , _friday , _saturday
@@ -187,7 +279,7 @@ private static SecurityExchangeHours CreateExchangeHoursWithEarlyCloseAndLateOpe
187
279
188
280
private static SecurityExchangeHours CreateExchangeHoursWithEarlyClose ( )
189
281
{
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 ) } } ;
191
283
var lateOpens = new Dictionary < DateTime , TimeSpan > ( ) ;
192
284
var exchangeHours = new SecurityExchangeHours ( TimeZones . NewYork , new List < DateTime > ( ) , new [ ]
193
285
{
@@ -199,19 +291,19 @@ private static SecurityExchangeHours CreateExchangeHoursWithEarlyClose()
199
291
private static SecurityExchangeHours CreateExchangeHoursWithLateOpen ( )
200
292
{
201
293
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 ) } } ;
203
295
var exchangeHours = new SecurityExchangeHours ( TimeZones . NewYork , new List < DateTime > ( ) , new [ ]
204
296
{
205
297
_sunday , _monday , _tuesday , _wednesday , _thursday , _friday , _saturday
206
298
} . ToDictionary ( x => x . DayOfWeek ) , earlyCloses , lateOpens ) ;
207
299
return exchangeHours ;
208
300
}
209
301
210
- private static SecurityExchangeHours CreateExchangeHoursWithHolidays ( )
302
+ public static SecurityExchangeHours CreateExchangeHoursWithHolidays ( )
211
303
{
212
304
var earlyCloses = new Dictionary < DateTime , TimeSpan > ( ) ;
213
305
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 } ;
215
307
var exchangeHours = new SecurityExchangeHours ( TimeZones . NewYork , holidays , new [ ]
216
308
{
217
309
_sunday , _monday , _tuesday , _wednesday , _thursday , _friday , _saturday
0 commit comments