1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-04 03:21:00 +08:00

support parallel HF trading

This commit is contained in:
Young
2021-07-03 08:46:09 +00:00
parent a401f1eafe
commit ef7fe8aa75
3 changed files with 55 additions and 13 deletions

View File

@@ -242,6 +242,7 @@ class Exchange:
raise ValueError("trade_account and position can only choose one")
trade_price = self.get_deal_price(order.stock_id, order.start_time, order.end_time)
# NOTE: order will be changed in this function
trade_val, trade_cost = self._calc_trade_info_by_order(
order, trade_account.current if trade_account else position
)
@@ -256,16 +257,6 @@ class Exchange:
return trade_val, trade_cost, trade_price
def create_order(self, code, amount, start_time, end_time, direction) -> Order:
return Order(
stock_id=code,
amount=amount,
start_time=start_time,
end_time=end_time,
direction=direction,
factor=self.get_factor(code, start_time, end_time),
)
def get_quote_info(self, stock_id, start_time, end_time):
return resam_ts_data(self.quote[stock_id], start_time, end_time, method="last").iloc[0]
@@ -471,6 +462,8 @@ class Exchange:
"""
Calculation of trade info
**NOTE**: Order will be changed in this function
:param order:
:param position: Position
:return: trade_val, trade_cost

View File

@@ -1,7 +1,7 @@
import copy
import warnings
import pandas as pd
from typing import Union
from typing import List, Union
from qlib.backtest.report import Indicator
@@ -317,6 +317,15 @@ class NestedExecutor(BaseExecutor):
class SimulatorExecutor(BaseExecutor):
"""Executor that simulate the true market"""
# available trade_types
TT_SERIAL = "serial"
## The orders will be executed serially in a sequence
# In each trading step, it is possible that users sell instruments first and use the money to buy new instruments
TT_PARAL = "parallel"
## The orders will be executed parallelly
# In each trading step, if users try to sell instruments first and buy new instruments with money, failure will
# occur
def __init__(
self,
time_per_step: str,
@@ -328,6 +337,7 @@ class SimulatorExecutor(BaseExecutor):
track_data: bool = False,
trade_exchange: Exchange = None,
common_infra: CommonInfrastructure = None,
trade_type: str = TT_PARAL,
**kwargs,
):
"""
@@ -336,6 +346,8 @@ class SimulatorExecutor(BaseExecutor):
trade_exchange : Exchange
exchange that provides market info, used to deal order and generate report
- If `trade_exchange` is None, self.trade_exchange will be set with common_infra
trade_type: str
please refer to the doc of `TT_SERIAL` & `TT_PARAL`
"""
super(SimulatorExecutor, self).__init__(
time_per_step=time_per_step,
@@ -351,6 +363,8 @@ class SimulatorExecutor(BaseExecutor):
if trade_exchange is not None:
self.trade_exchange = trade_exchange
self.trade_type = trade_type
def reset_common_infra(self, common_infra):
"""
reset infrastructure for trading
@@ -360,14 +374,45 @@ class SimulatorExecutor(BaseExecutor):
if common_infra.has("trade_exchange"):
self.trade_exchange = common_infra.get("trade_exchange")
def _get_order_iterator(self, trade_decision: BaseTradeDecision) -> List[Order]:
"""
Parameters
----------
trade_decision : BaseTradeDecision
the trade decision given by the strategy
Returns
-------
List[Order]:
get a list orders according to `self.trade_type`
"""
orders = trade_decision.get_decision()
if self.trade_type == self.TT_SERIAL:
# Orders will be traded in a parallel way
order_it = orders
elif self.trade_type == self.TT_PARAL:
# NOTE: !!!!!!!
# Assumption: there will not be orders in different trading direction in a single step of a strategy !!!!
# The parallel trading failure will be caused only by the confliction of money
# Therefore, make the buying go first will make sure the confliction happen.
# It equals to parallel trading after sorting the order by direction
order_it = sorted(orders, key=lambda order: -order.direction)
else:
raise NotImplementedError(f"This type of input is not supported")
return order_it
def execute(self, trade_decision: BaseTradeDecision):
trade_step = self.trade_calendar.get_trade_step()
trade_start_time, trade_end_time = self.trade_calendar.get_step_time(trade_step)
execute_result = []
for order in trade_decision.get_decision():
for order in self._get_order_iterator(trade_decision):
if self.trade_exchange.check_order(order) is True:
# execute the order
# execute the order.
# NOTE: The trade_account will be changed in this function
trade_val, trade_cost, trade_price = self.trade_exchange.deal_order(
order, trade_account=self.trade_account
)
@@ -404,6 +449,7 @@ class SimulatorExecutor(BaseExecutor):
# do nothing
pass
# Account will not be changed in this function
self.trade_account.update_bar_end(
trade_start_time,
trade_end_time,

View File

@@ -718,8 +718,11 @@ class FileOrderStrategy(BaseStrategy):
----------
file : Union[IO, str, Path]
this parameters will specify the info of expected orders
Here is an example of the content
1) Amount (**adjusted**) based strategy
datetime,instrument,amount,direction
20200102, SH600519, 1000, sell
20200103, SH600519, 1000, buy