1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-11 14:56:55 +08:00

successful run random order gen in day script

This commit is contained in:
Young
2021-06-25 20:12:39 +00:00
committed by you-n-g
parent b68294da93
commit b41267fa59
17 changed files with 505 additions and 354 deletions

View File

@@ -11,7 +11,7 @@ import warnings
from ..log import get_module_logger
from ..backtest import get_exchange, backtest as backtest_func
from ..utils import get_date_range
from ..utils.resam import parse_freq, NORM_FREQ_MONTH, NORM_FREQ_WEEK, NORM_FREQ_DAY, NORM_FREQ_MINUTE
from ..utils.resam import Freq
from ..data import D
from ..config import C
@@ -35,12 +35,12 @@ def risk_analysis(r, N: int = None, freq: str = "day"):
"""
def cal_risk_analysis_scaler(freq):
_count, _freq = parse_freq(freq)
_count, _freq = Freq.parse(freq)
_freq_scaler = {
NORM_FREQ_MINUTE: 240 * 252,
NORM_FREQ_DAY: 252,
NORM_FREQ_WEEK: 50,
NORM_FREQ_MONTH: 12,
Freq.NORM_FREQ_MINUTE: 240 * 252,
Freq.NORM_FREQ_DAY: 252,
Freq.NORM_FREQ_WEEK: 50,
Freq.NORM_FREQ_MONTH: 12,
}
return _freq_scaler[_freq] / _count

View File

@@ -6,8 +6,7 @@ import pandas as pd
from ...utils.resam import resam_ts_data
from ...strategy.base import ModelStrategy
from ...backtest.order import Order
from ...backtest.utils import TradeDecison
from ...backtest.order import Order, BaseTradeDecision
from .order_generator import OrderGenWInteract
@@ -247,7 +246,7 @@ class TopkDropoutStrategy(ModelStrategy):
factor=factor,
)
buy_order_list.append(buy_order)
return TradeDecison(order_list=sell_order_list + buy_order_list, ori_strategy=self)
return TradeDecision(order_list=sell_order_list + buy_order_list, ori_strategy=self)
class WeightStrategyBase(ModelStrategy):
@@ -344,4 +343,4 @@ class WeightStrategyBase(ModelStrategy):
trade_start_time=trade_start_time,
trade_end_time=trade_end_time,
)
return TradeDecison(order_list=order_list, ori_strategy=self)
return TradeDecision(order_list=order_list, ori_strategy=self)

View File

@@ -6,7 +6,7 @@ This order generator is for strategies based on WeightStrategyBase
"""
from ...backtest.position import Position
from ...backtest.exchange import Exchange
from ...backtest.utils import TradeDecison
from ...backtest.order import BaseTradeDecision
import pandas as pd
import copy
@@ -127,7 +127,7 @@ class OrderGenWInteract(OrderGenerator):
trade_start_time=trade_start_time,
trade_end_time=trade_end_time,
)
return TradeDecison(order_list=order_list, ori_strategy=self)
return TradeDecision(order_list=order_list, ori_strategy=self)
class OrderGenWOInteract(OrderGenerator):
@@ -191,4 +191,4 @@ class OrderGenWOInteract(OrderGenerator):
trade_start_time=trade_start_time,
trade_end_time=trade_end_time,
)
return TradeDecison(order_list=order_list, ori_strategy=self)
return TradeDecision(order_list=order_list, ori_strategy=self)

View File

@@ -7,9 +7,9 @@ from ...utils.resam import resam_ts_data
from ...data.data import D
from ...data.dataset.utils import convert_index_format
from ...strategy.base import BaseStrategy
from ...backtest.order import Order
from ...backtest.order import BaseTradeDecision, Order, TradeDecisionWO
from ...backtest.exchange import Exchange
from ...backtest.utils import CommonInfrastructure, LevelInfrastructure, TradeDecison
from ...backtest.utils import CommonInfrastructure, LevelInfrastructure
class TWAPStrategy(BaseStrategy):
@@ -17,7 +17,7 @@ class TWAPStrategy(BaseStrategy):
def __init__(
self,
outer_trade_decision: TradeDecison = None,
outer_trade_decision: BaseTradeDecision = None,
trade_exchange: Exchange = None,
level_infra: LevelInfrastructure = None,
common_infra: CommonInfrastructure = None,
@@ -25,8 +25,8 @@ class TWAPStrategy(BaseStrategy):
"""
Parameters
----------
outer_trade_decision : TradeDecison
the trade decison of outer strategy which this startegy relies
outer_trade_decision : BaseTradeDecision
the trade decision of outer strategy which this startegy relies
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
@@ -57,25 +57,35 @@ class TWAPStrategy(BaseStrategy):
if common_infra.has("trade_exchange"):
self.trade_exchange = common_infra.get("trade_exchange")
def reset(self, outer_trade_decision: TradeDecison = None, **kwargs):
def reset(self, outer_trade_decision: BaseTradeDecision = None, **kwargs):
"""
Parameters
----------
outer_trade_decision : TradeDecison, optional
outer_trade_decision : BaseTradeDecision, optional
"""
super(TWAPStrategy, self).reset(outer_trade_decision=outer_trade_decision, **kwargs)
if outer_trade_decision is not None:
self.trade_amount = {}
outer_order_generator = outer_trade_decision.generator()
for order in outer_order_generator:
for order in outer_trade_decision.get_decision():
self.trade_amount[order.stock_id] = order.amount
def generate_trade_decision(self, execute_result=None):
# strategy is not available. Give an empty decision
if len(self.outer_trade_decision.get_decision()) == 0:
return TradeDecisionWO(order_list=[], strategy=self)
# get the number of trading step finished, trade_step can be [0, 1, 2, ..., trade_len - 1]
trade_step = self.trade_calendar.get_trade_step()
# get the total count of trading step
trade_len = self.trade_calendar.get_trade_len()
start_idx, end_idx = self.outer_trade_decision.get_range_limit()
trade_len = end_idx - start_idx + 1
if trade_step < start_idx:
# It is not time to start trading
return TradeDecisionWO(order_list=[], strategy=self)
rel_trade_step = trade_step - start_idx # trade_step relative to start_idx
# update the order amount
if execute_result is not None:
@@ -84,8 +94,7 @@ class TWAPStrategy(BaseStrategy):
trade_start_time, trade_end_time = self.trade_calendar.get_step_time(trade_step)
order_list = []
outer_order_generator = self.outer_trade_decision.generator(only_enable=True)
for order in outer_order_generator:
for order in self.outer_trade_decision.get_decision():
# if not tradable, continue
if not self.trade_exchange.is_stock_tradable(
stock_id=order.stock_id, start_time=trade_start_time, end_time=trade_end_time
@@ -96,21 +105,21 @@ class TWAPStrategy(BaseStrategy):
# considering trade unit
if _amount_trade_unit is None:
# divide the order into equal parts, and trade one part
_order_amount = self.trade_amount[order.stock_id] / (trade_len - trade_step)
_order_amount = self.trade_amount[order.stock_id] / (trade_len - rel_trade_step)
# without considering trade unit
else:
# divide the order into equal parts, and trade one part
# calculate the total count of trade units to trade
trade_unit_cnt = int(self.trade_amount[order.stock_id] // _amount_trade_unit)
# calculate the amount of one part, ceil the amount
# floor((trade_unit_cnt + trade_len - trade_step) / (trade_len - trade_step + 1)) == ceil(trade_unit_cnt / (trade_len - trade_step + 1))
# floor((trade_unit_cnt + trade_len - rel_trade_step) / (trade_len - rel_trade_step + 1)) == ceil(trade_unit_cnt / (trade_len - rel_trade_step + 1))
_order_amount = (
(trade_unit_cnt + trade_len - trade_step - 1) // (trade_len - trade_step) * _amount_trade_unit
(trade_unit_cnt + trade_len - rel_trade_step - 1) // (trade_len - rel_trade_step) * _amount_trade_unit
)
if order.direction == order.SELL:
# sell all amount at last
if self.trade_amount[order.stock_id] > 1e-5 and (_order_amount < 1e-5 or trade_step == trade_len - 1):
if self.trade_amount[order.stock_id] > 1e-5 and (_order_amount < 1e-5 or rel_trade_step == trade_len - 1):
_order_amount = self.trade_amount[order.stock_id]
_order_amount = min(_order_amount, self.trade_amount[order.stock_id])
@@ -126,7 +135,7 @@ class TWAPStrategy(BaseStrategy):
factor=order.factor,
)
order_list.append(_order)
return TradeDecison(order_list=order_list, ori_strategy=self)
return TradeDecisionWO(order_list=order_list, strategy=self)
class SBBStrategyBase(BaseStrategy):
@@ -140,7 +149,7 @@ class SBBStrategyBase(BaseStrategy):
def __init__(
self,
outer_trade_decision: TradeDecison = None,
outer_trade_decision: BaseTradeDecision = None,
trade_exchange: Exchange = None,
level_infra: LevelInfrastructure = None,
common_infra: CommonInfrastructure = None,
@@ -148,8 +157,8 @@ class SBBStrategyBase(BaseStrategy):
"""
Parameters
----------
outer_trade_decision : TradeDecison
the trade decison of outer strategy which this startegy relies
outer_trade_decision : BaseTradeDecision
the trade decision of outer strategy which this startegy relies
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
@@ -178,11 +187,11 @@ class SBBStrategyBase(BaseStrategy):
if common_infra.has("trade_exchange"):
self.trade_exchange = common_infra.get("trade_exchange")
def reset(self, outer_trade_decision: TradeDecison = None, **kwargs):
def reset(self, outer_trade_decision: BaseTradeDecision = None, **kwargs):
"""
Parameters
----------
outer_trade_decision : TradeDecison, optional
outer_trade_decision : BaseTradeDecision, optional
"""
super(SBBStrategyBase, self).reset(outer_trade_decision=outer_trade_decision, **kwargs)
if outer_trade_decision is not None:
@@ -336,7 +345,7 @@ class SBBStrategyBase(BaseStrategy):
# in the first one of two adjacent bars, store the trend for the second one to use
self.trade_trend[order.stock_id] = _pred_trend
return TradeDecison(order_list=order_list, ori_strategy=self)
return TradeDecision(order_list=order_list, ori_strategy=self)
class SBBStrategyEMA(SBBStrategyBase):
@@ -346,7 +355,7 @@ class SBBStrategyEMA(SBBStrategyBase):
def __init__(
self,
outer_trade_decision: TradeDecison = None,
outer_trade_decision: BaseTradeDecision = None,
instruments: Union[List, str] = "csi300",
freq: str = "day",
trade_exchange: Exchange = None,
@@ -426,7 +435,7 @@ class ACStrategy(BaseStrategy):
lamb: float = 1e-6,
eta: float = 2.5e-6,
window_size: int = 20,
outer_trade_decision: TradeDecison = None,
outer_trade_decision: BaseTradeDecision = None,
instruments: Union[List, str] = "csi300",
freq: str = "day",
trade_exchange: Exchange = None,
@@ -503,11 +512,11 @@ class ACStrategy(BaseStrategy):
self.trade_calendar = level_infra.get("trade_calendar")
self._reset_signal()
def reset(self, outer_trade_decision: TradeDecison = None, **kwargs):
def reset(self, outer_trade_decision: BaseTradeDecision = None, **kwargs):
"""
Parameters
----------
outer_trade_decision : TradeDecison, optional
outer_trade_decision : BaseTradeDecision, optional
"""
super(ACStrategy, self).reset(outer_trade_decision=outer_trade_decision, **kwargs)
if outer_trade_decision is not None:
@@ -592,13 +601,13 @@ class ACStrategy(BaseStrategy):
factor=order.factor,
)
order_list.append(_order)
return TradeDecison(order_list=order_list, ori_strategy=self)
return TradeDecision(order_list=order_list, ori_strategy=self)
class RandomOrderStrategy(BaseStrategy):
def __init__(self,
time_range: Tuple = ("9:30", "15:00"), # The range is closed on both left and right.
index_range: Tuple[int, int], # The range is closed on both left and right.
sample_ratio: float = 1.,
volume_ratio: float = 0.01,
market: str = "all",
@@ -607,10 +616,10 @@ class RandomOrderStrategy(BaseStrategy):
"""
Parameters
----------
time_range : Tuple
the intra day time range of the orders
index_range : Tuple
the intra day time index range of the orders
the left and right is closed.
# TODO: this is a time_range level limitation. We'll implement a more detailed limitation later.
# TODO: this is a index_range level limitation. We'll implement a more detailed limitation later.
sample_ratio : float
the ratio of all orders are sampled
volume_ratio : float
@@ -621,12 +630,27 @@ class RandomOrderStrategy(BaseStrategy):
"""
super().__init__(*args, **kwargs)
self.time_range = time_range
self.index_range = index_range
self.sample_ratio = sample_ratio
self.volume_ratio = volume_ratio
self.market = market
exch: Exchange = self.common_infra.get("exchange")
self.volume = D.features(D.instruments("market"), ["Mean($volume, 10)"], start_time=exch.start_time, end_time=exch.end_time)
exch: Exchange = self.common_infra.get("trade_exchange")
self.volume = D.features(D.instruments(market), ["Mean(Ref($volume, 1), 10)"], start_time=exch.start_time, end_time=exch.end_time)
self.volume_df = self.volume.iloc[:, 0].unstack()
def generate_trade_decision(self, execute_result=None):
return super().generate_trade_decision(execute_result=execute_result)
trade_step = self.trade_calendar.get_trade_step()
step_time_start, step_time_end = self.trade_calendar.get_step_time(trade_step)
order_list = []
for direction in Order.SELL, Order.BUY:
for stock_id, volume in self.volume_df[step_time_start].dropna().sample(frac=self.sample_ratio).items():
order_list.append(
self.common_infra.get("trade_exchange").create_order(
code=stock_id,
amount=volume * self.volume_ratio,
start_time=step_time_start,
end_time=step_time_end,
direction=direction, # 1 for buy
))
return TradeDecisionWO(order_list, self)