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:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user