mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-14 00:06:58 +08:00
support parallel HF trading
This commit is contained in:
@@ -242,6 +242,7 @@ class Exchange:
|
|||||||
raise ValueError("trade_account and position can only choose one")
|
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)
|
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(
|
trade_val, trade_cost = self._calc_trade_info_by_order(
|
||||||
order, trade_account.current if trade_account else position
|
order, trade_account.current if trade_account else position
|
||||||
)
|
)
|
||||||
@@ -256,16 +257,6 @@ class Exchange:
|
|||||||
|
|
||||||
return trade_val, trade_cost, trade_price
|
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):
|
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]
|
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
|
Calculation of trade info
|
||||||
|
|
||||||
|
**NOTE**: Order will be changed in this function
|
||||||
|
|
||||||
:param order:
|
:param order:
|
||||||
:param position: Position
|
:param position: Position
|
||||||
:return: trade_val, trade_cost
|
:return: trade_val, trade_cost
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import copy
|
import copy
|
||||||
import warnings
|
import warnings
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from typing import Union
|
from typing import List, Union
|
||||||
|
|
||||||
from qlib.backtest.report import Indicator
|
from qlib.backtest.report import Indicator
|
||||||
|
|
||||||
@@ -317,6 +317,15 @@ class NestedExecutor(BaseExecutor):
|
|||||||
class SimulatorExecutor(BaseExecutor):
|
class SimulatorExecutor(BaseExecutor):
|
||||||
"""Executor that simulate the true market"""
|
"""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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
time_per_step: str,
|
time_per_step: str,
|
||||||
@@ -328,6 +337,7 @@ class SimulatorExecutor(BaseExecutor):
|
|||||||
track_data: bool = False,
|
track_data: bool = False,
|
||||||
trade_exchange: Exchange = None,
|
trade_exchange: Exchange = None,
|
||||||
common_infra: CommonInfrastructure = None,
|
common_infra: CommonInfrastructure = None,
|
||||||
|
trade_type: str = TT_PARAL,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -336,6 +346,8 @@ class SimulatorExecutor(BaseExecutor):
|
|||||||
trade_exchange : Exchange
|
trade_exchange : Exchange
|
||||||
exchange that provides market info, used to deal order and generate report
|
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
|
- 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__(
|
super(SimulatorExecutor, self).__init__(
|
||||||
time_per_step=time_per_step,
|
time_per_step=time_per_step,
|
||||||
@@ -351,6 +363,8 @@ class SimulatorExecutor(BaseExecutor):
|
|||||||
if trade_exchange is not None:
|
if trade_exchange is not None:
|
||||||
self.trade_exchange = trade_exchange
|
self.trade_exchange = trade_exchange
|
||||||
|
|
||||||
|
self.trade_type = trade_type
|
||||||
|
|
||||||
def reset_common_infra(self, common_infra):
|
def reset_common_infra(self, common_infra):
|
||||||
"""
|
"""
|
||||||
reset infrastructure for trading
|
reset infrastructure for trading
|
||||||
@@ -360,14 +374,45 @@ class SimulatorExecutor(BaseExecutor):
|
|||||||
if common_infra.has("trade_exchange"):
|
if common_infra.has("trade_exchange"):
|
||||||
self.trade_exchange = common_infra.get("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):
|
def execute(self, trade_decision: BaseTradeDecision):
|
||||||
|
|
||||||
trade_step = self.trade_calendar.get_trade_step()
|
trade_step = self.trade_calendar.get_trade_step()
|
||||||
trade_start_time, trade_end_time = self.trade_calendar.get_step_time(trade_step)
|
trade_start_time, trade_end_time = self.trade_calendar.get_step_time(trade_step)
|
||||||
execute_result = []
|
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:
|
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(
|
trade_val, trade_cost, trade_price = self.trade_exchange.deal_order(
|
||||||
order, trade_account=self.trade_account
|
order, trade_account=self.trade_account
|
||||||
)
|
)
|
||||||
@@ -404,6 +449,7 @@ class SimulatorExecutor(BaseExecutor):
|
|||||||
# do nothing
|
# do nothing
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Account will not be changed in this function
|
||||||
self.trade_account.update_bar_end(
|
self.trade_account.update_bar_end(
|
||||||
trade_start_time,
|
trade_start_time,
|
||||||
trade_end_time,
|
trade_end_time,
|
||||||
|
|||||||
@@ -718,8 +718,11 @@ class FileOrderStrategy(BaseStrategy):
|
|||||||
----------
|
----------
|
||||||
file : Union[IO, str, Path]
|
file : Union[IO, str, Path]
|
||||||
this parameters will specify the info of expected orders
|
this parameters will specify the info of expected orders
|
||||||
|
|
||||||
Here is an example of the content
|
Here is an example of the content
|
||||||
|
|
||||||
|
1) Amount (**adjusted**) based strategy
|
||||||
|
|
||||||
datetime,instrument,amount,direction
|
datetime,instrument,amount,direction
|
||||||
20200102, SH600519, 1000, sell
|
20200102, SH600519, 1000, sell
|
||||||
20200103, SH600519, 1000, buy
|
20200103, SH600519, 1000, buy
|
||||||
|
|||||||
Reference in New Issue
Block a user