1
1
import copy
2
2
import warnings
3
3
import pandas as pd
4
- from typing import Union
4
+ from typing import List , Union
5
5
6
6
from qlib .backtest .report import Indicator
7
7
@@ -317,6 +317,15 @@ def get_all_executors(self):
317
317
class SimulatorExecutor (BaseExecutor ):
318
318
"""Executor that simulate the true market"""
319
319
320
+ # available trade_types
321
+ TT_SERIAL = "serial"
322
+ ## The orders will be executed serially in a sequence
323
+ # In each trading step, it is possible that users sell instruments first and use the money to buy new instruments
324
+ TT_PARAL = "parallel"
325
+ ## The orders will be executed parallelly
326
+ # In each trading step, if users try to sell instruments first and buy new instruments with money, failure will
327
+ # occure
328
+
320
329
def __init__ (
321
330
self ,
322
331
time_per_step : str ,
@@ -328,6 +337,7 @@ def __init__(
328
337
track_data : bool = False ,
329
338
trade_exchange : Exchange = None ,
330
339
common_infra : CommonInfrastructure = None ,
340
+ trade_type : str = TT_PARAL ,
331
341
** kwargs ,
332
342
):
333
343
"""
@@ -336,6 +346,8 @@ def __init__(
336
346
trade_exchange : Exchange
337
347
exchange that provides market info, used to deal order and generate report
338
348
- If `trade_exchange` is None, self.trade_exchange will be set with common_infra
349
+ trade_type: str
350
+ please refer to the doc of `TT_SERIAL` & `TT_PARAL`
339
351
"""
340
352
super (SimulatorExecutor , self ).__init__ (
341
353
time_per_step = time_per_step ,
@@ -351,6 +363,8 @@ def __init__(
351
363
if trade_exchange is not None :
352
364
self .trade_exchange = trade_exchange
353
365
366
+ self .trade_type = trade_type
367
+
354
368
def reset_common_infra (self , common_infra ):
355
369
"""
356
370
reset infrastructure for trading
@@ -360,14 +374,45 @@ def reset_common_infra(self, common_infra):
360
374
if common_infra .has ("trade_exchange" ):
361
375
self .trade_exchange = common_infra .get ("trade_exchange" )
362
376
377
+ def _get_order_iterator (self , trade_decision : BaseTradeDecision ) -> List [Order ]:
378
+ """
379
+
380
+ Parameters
381
+ ----------
382
+ trade_decision : BaseTradeDecision
383
+ the trade decision given by the strategy
384
+
385
+ Returns
386
+ -------
387
+ List[Order]:
388
+ get a list orders according to `self.trade_type`
389
+ """
390
+ orders = trade_decision .get_decision ()
391
+
392
+ if self .trade_type == self .TT_SERIAL :
393
+ # Orders will be traded in a parallel way
394
+ order_it = orders
395
+ elif self .trade_type == self .TT_PARAL :
396
+ # NOTE: !!!!!!!
397
+ # Assumption: there will not be orders in different trading direction in a single step of a strategy !!!!
398
+ # The parallel trading failure will be caused only by the confliction of money
399
+ # Therefore, make the buying go first will make sure the confliction happen.
400
+ # It equals to parallel trading after sorting the order by direction
401
+ order_it = sorted (orders , key = lambda order : - order .direction )
402
+ else :
403
+ raise NotImplementedError (f"This type of input is not supported" )
404
+ return order_it
405
+
363
406
def execute (self , trade_decision : BaseTradeDecision ):
364
407
365
408
trade_step = self .trade_calendar .get_trade_step ()
366
409
trade_start_time , trade_end_time = self .trade_calendar .get_step_time (trade_step )
367
410
execute_result = []
368
- for order in trade_decision .get_decision ():
411
+
412
+ for order in self ._get_order_iterator (trade_decision ):
369
413
if self .trade_exchange .check_order (order ) is True :
370
- # execute the order
414
+ # execute the order.
415
+ # NOTE: The trade_account will be changed in this function
371
416
trade_val , trade_cost , trade_price = self .trade_exchange .deal_order (
372
417
order , trade_account = self .trade_account
373
418
)
@@ -404,6 +449,7 @@ def execute(self, trade_decision: BaseTradeDecision):
404
449
# do nothing
405
450
pass
406
451
452
+ # Account will not be changed in this function
407
453
self .trade_account .update_bar_end (
408
454
trade_start_time ,
409
455
trade_end_time ,
0 commit comments