mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-03 19:10:58 +08:00
fix comments & add VAStrategy & add trade indicator
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Nested Decision Execution
|
||||
|
||||
This worflow is an example for nested decision execution in backtesting. Qlib supports nested decision execution in backtesting. It means that users can use different strategies to make trade decision in different frequencies.
|
||||
This workflow is an example for nested decision execution in backtesting. Qlib supports nested decision execution in backtesting. It means that users can use different strategies to make trade decision in different frequencies.
|
||||
|
||||
## Weekly Portfolio Generation and Daily Order Execution
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ class NestedDecisonExecutionWorkflow:
|
||||
benchmark = "SH000300"
|
||||
|
||||
data_handler_config = {
|
||||
"start_time": "2008-01-01",
|
||||
"end_time": "2021-01-20",
|
||||
"fit_start_time": "2008-01-01",
|
||||
"fit_end_time": "2014-12-31",
|
||||
"start_time": "2010-01-01",
|
||||
"end_time": "2021-05-28",
|
||||
"fit_start_time": "2010-01-01",
|
||||
"fit_end_time": "2017-12-31",
|
||||
"instruments": market,
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ class NestedDecisonExecutionWorkflow:
|
||||
"kwargs": data_handler_config,
|
||||
},
|
||||
"segments": {
|
||||
"train": ("2008-01-01", "2014-12-31"),
|
||||
"valid": ("2015-01-01", "2016-12-31"),
|
||||
"test": ("2017-01-01", "2021-01-20"),
|
||||
"train": ("2010-01-01", "2017-12-31"),
|
||||
"valid": ("2018-01-01", "2019-12-31"),
|
||||
"test": ("2020-01-01", "2021-05-28"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -67,33 +67,45 @@ class NestedDecisonExecutionWorkflow:
|
||||
"kwargs": {
|
||||
"time_per_step": "week",
|
||||
"inner_executor": {
|
||||
"class": "SimulatorExecutor",
|
||||
"class": "NestedExecutor",
|
||||
"module_path": "qlib.backtest.executor",
|
||||
"kwargs": {
|
||||
"time_per_step": "day",
|
||||
"verbose": True,
|
||||
"generate_report": True,
|
||||
"inner_executor": {
|
||||
"class": "SimulatorExecutor",
|
||||
"module_path": "qlib.backtest.executor",
|
||||
"kwargs": {
|
||||
"time_per_step": "15min",
|
||||
"generate_report": True,
|
||||
"verbose": True,
|
||||
},
|
||||
},
|
||||
"inner_strategy": {
|
||||
"class": "TWAPStrategy",
|
||||
"module_path": "qlib.contrib.strategy.rule_strategy",
|
||||
},
|
||||
"show_indicator": True,
|
||||
},
|
||||
},
|
||||
"inner_strategy": {
|
||||
"class": "SBBStrategyEMA",
|
||||
"class": "VAStrategy",
|
||||
"module_path": "qlib.contrib.strategy.rule_strategy",
|
||||
"kwargs": {
|
||||
"freq": "day",
|
||||
"instruments": market,
|
||||
},
|
||||
},
|
||||
"generate_report": True,
|
||||
"track_data": True,
|
||||
"show_indicator": True,
|
||||
},
|
||||
},
|
||||
"backtest": {
|
||||
"start_time": "2017-01-01",
|
||||
"end_time": "2020-08-01",
|
||||
"start_time": "2020-09-20",
|
||||
"end_time": "2021-05-28",
|
||||
"account": 100000000,
|
||||
"benchmark": benchmark,
|
||||
"exchange_kwargs": {
|
||||
"freq": "day",
|
||||
"freq": "1min",
|
||||
"limit_threshold": 0.095,
|
||||
"deal_price": "close",
|
||||
"open_cost": 0.0005,
|
||||
@@ -105,11 +117,40 @@ class NestedDecisonExecutionWorkflow:
|
||||
|
||||
def _init_qlib(self):
|
||||
"""initialize qlib"""
|
||||
provider_uri = "~/.qlib/qlib_data/cn_data" # target_dir
|
||||
if not exists_qlib_data(provider_uri):
|
||||
print(f"Qlib data is not found in {provider_uri}")
|
||||
GetData().qlib_data(target_dir=provider_uri, region=REG_CN)
|
||||
qlib.init(provider_uri=provider_uri, region=REG_CN)
|
||||
provider_uri_day = "/data1/v-xiabi/qlib/qlib_data/cn_data" # target_dir
|
||||
GetData().qlib_data(target_dir=provider_uri_day, region=REG_CN, version="v2", exists_skip=True)
|
||||
# provider_uri_1min = HIGH_FREQ_CONFIG.get("provider_uri")
|
||||
provider_uri_1min = "/data1/v-xiabi/qlib/qlib_data/cn_data_highfreq"
|
||||
GetData().qlib_data(
|
||||
target_dir=provider_uri_1min, interval="1min", region=REG_CN, version="v2", exists_skip=True
|
||||
)
|
||||
|
||||
provider_uri_map = {"1min": provider_uri_1min, "day": provider_uri_day}
|
||||
client_config = {
|
||||
"calendar_provider": {
|
||||
"class": "LocalCalendarProvider",
|
||||
"module_path": "qlib.data.data",
|
||||
"kwargs": {
|
||||
"backend": {
|
||||
"class": "FileCalendarStorage",
|
||||
"module_path": "qlib.data.storage.file_storage",
|
||||
"kwargs": {"provider_uri_map": provider_uri_map},
|
||||
}
|
||||
},
|
||||
},
|
||||
"feature_provider": {
|
||||
"class": "LocalFeatureProvider",
|
||||
"module_path": "qlib.data.data",
|
||||
"kwargs": {
|
||||
"backend": {
|
||||
"class": "FileFeatureStorage",
|
||||
"module_path": "qlib.data.storage.file_storage",
|
||||
"kwargs": {"provider_uri_map": provider_uri_map},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
qlib.init(provider_uri=provider_uri_day, **client_config)
|
||||
|
||||
def _train_model(self, model, dataset):
|
||||
with R.start(experiment_name="train"):
|
||||
@@ -141,7 +182,7 @@ class NestedDecisonExecutionWorkflow:
|
||||
with R.start(experiment_name="backtest"):
|
||||
|
||||
recorder = R.get_recorder()
|
||||
par = PortAnaRecord(recorder, self.port_analysis_config, "day")
|
||||
par = PortAnaRecord(recorder, self.port_analysis_config, "15minute")
|
||||
par.generate()
|
||||
|
||||
def collect_data(self):
|
||||
@@ -165,98 +206,6 @@ class NestedDecisonExecutionWorkflow:
|
||||
for trade_decision in data_generator:
|
||||
print(trade_decision)
|
||||
|
||||
def _init_qlib_with_backend(self):
|
||||
provider_uri_1min = HIGH_FREQ_CONFIG.get("provider_uri")
|
||||
if not exists_qlib_data(provider_uri_1min):
|
||||
print(f"Qlib data is not found in {provider_uri_1min}")
|
||||
GetData().qlib_data(target_dir=provider_uri_1min, interval="1min", region=REG_CN)
|
||||
|
||||
# TODO: update latest data
|
||||
provider_uri_day = "~/.qlib/qlib_data/cn_data" # target_dir
|
||||
if not exists_qlib_data(provider_uri_day):
|
||||
print(f"Qlib data is not found in {provider_uri_day}")
|
||||
GetData().qlib_data(target_dir=provider_uri_day, region=REG_CN)
|
||||
|
||||
provider_uri_map = {"1min": provider_uri_1min, "day": provider_uri_day}
|
||||
client_config = {
|
||||
"calendar_provider": {
|
||||
"class": "LocalCalendarProvider",
|
||||
"module_path": "qlib.data.data",
|
||||
"kwargs": {
|
||||
"backend": {
|
||||
"class": "FileCalendarStorage",
|
||||
"module_path": "qlib.data.storage.file_storage",
|
||||
"kwargs": {"provider_uri_map": provider_uri_map},
|
||||
}
|
||||
},
|
||||
},
|
||||
"feature_provider": {
|
||||
"class": "LocalFeatureProvider",
|
||||
"module_path": "qlib.data.data",
|
||||
"kwargs": {
|
||||
"backend": {
|
||||
"class": "FileFeatureStorage",
|
||||
"module_path": "qlib.data.storage.file_storage",
|
||||
"kwargs": {"provider_uri_map": provider_uri_map},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
qlib.init(provider_uri=provider_uri_day, **client_config)
|
||||
|
||||
def _get_highfreq_config(self, model, dataset):
|
||||
|
||||
executor_config = self.port_analysis_config["executor"]
|
||||
# update executor with hierarchical decison freq ["day", "1min"]
|
||||
executor_config["kwargs"]["time_per_step"] = "day"
|
||||
executor_config["kwargs"]["inner_executor"]["kwargs"]["time_per_step"] = "15min"
|
||||
backtest_config = self.port_analysis_config["backtest"]
|
||||
|
||||
# yahoo highfreq data time
|
||||
backtest_config["start_time"] = "2020-09-20"
|
||||
backtest_config["end_time"] = "2021-01-20"
|
||||
|
||||
# update benchmark, yahoo data don't have SH000300
|
||||
instruments = D.instruments(market="csi300")
|
||||
instrument_list = D.list_instruments(instruments=instruments, as_list=True)
|
||||
backtest_config["benchmark"] = instrument_list
|
||||
|
||||
# update exchange config
|
||||
backtest_config["exchange_kwargs"]["freq"] = "1min"
|
||||
|
||||
# set strategy
|
||||
strategy_config = {
|
||||
"class": "TopkDropoutStrategy",
|
||||
"module_path": "qlib.contrib.strategy.model_strategy",
|
||||
"kwargs": {
|
||||
"model": model,
|
||||
"dataset": dataset,
|
||||
"topk": 50,
|
||||
"n_drop": 5,
|
||||
},
|
||||
}
|
||||
|
||||
return executor_config, strategy_config, backtest_config
|
||||
|
||||
def backtest_highfreq(self):
|
||||
self._init_qlib_with_backend()
|
||||
model = init_instance_by_config(self.task["model"])
|
||||
dataset = init_instance_by_config(self.task["dataset"])
|
||||
self._train_model(model, dataset)
|
||||
executor_config, strategy_config, backtest_config = self._get_highfreq_config(model, dataset)
|
||||
|
||||
highfreq_port_analysis_config = {
|
||||
"executor": executor_config,
|
||||
"strategy": strategy_config,
|
||||
"backtest": backtest_config,
|
||||
}
|
||||
|
||||
with R.start(experiment_name="backtest_highfreq"):
|
||||
|
||||
recorder = R.get_recorder()
|
||||
par = PortAnaRecord(recorder, highfreq_port_analysis_config, "day")
|
||||
par.generate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(NestedDecisonExecutionWorkflow)
|
||||
|
||||
Reference in New Issue
Block a user