mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-07 21:11:50 +08:00
Qlib simulator refinement (redo of PR 1244) (#1262)
* Use dict-like configuration * Rename from_neutrader to integration * SAOE strategy * Optimize file structure * Optimize code * Format code * create_state_maintainer_recursive * Remove explicit time_per_step * CI test passed * Resolve PR comments * Pass all CI * Minor test issue * Refine SAOE adapter logic * Minor bugfix * Cherry pick updates * Resolve PR comments * CI issues * Refine adapter & saoe_data logic * Resolve PR comments * Resolve PR comments * Rename ONE_SEC to EPS_T; complete backtest loop * CI issue * Resolve Yuge's PR comments
This commit is contained in:
@@ -345,4 +345,4 @@ def format_decisions(
|
||||
return res
|
||||
|
||||
|
||||
__all__ = ["Order", "backtest"]
|
||||
__all__ = ["Order", "backtest", "get_strategy_executor"]
|
||||
|
||||
@@ -83,7 +83,9 @@ def collect_data_loop(
|
||||
while not trade_executor.finished():
|
||||
_trade_decision: BaseTradeDecision = trade_strategy.generate_trade_decision(_execute_result)
|
||||
_execute_result = yield from trade_executor.collect_data(_trade_decision, level=0)
|
||||
trade_strategy.post_exe_step(_execute_result)
|
||||
bar.update(1)
|
||||
trade_strategy.post_upper_level_exe_step()
|
||||
|
||||
if return_value is not None:
|
||||
all_executors = trade_executor.get_all_executors()
|
||||
|
||||
@@ -135,6 +135,21 @@ class Order:
|
||||
else:
|
||||
raise NotImplementedError(f"This type of input is not supported")
|
||||
|
||||
@property
|
||||
def key_by_day(self) -> tuple:
|
||||
"""A hashable & unique key to identify this order, under the granularity in day."""
|
||||
return self.stock_id, self.date, self.direction
|
||||
|
||||
@property
|
||||
def key(self) -> tuple:
|
||||
"""A hashable & unique key to identify this order."""
|
||||
return self.stock_id, self.start_time, self.end_time, self.direction
|
||||
|
||||
@property
|
||||
def date(self) -> pd.Timestamp:
|
||||
"""Date of the order."""
|
||||
return pd.Timestamp(self.start_time.replace(hour=0, minute=0, second=0))
|
||||
|
||||
|
||||
class OrderHelper:
|
||||
"""
|
||||
|
||||
@@ -114,7 +114,7 @@ class BaseExecutor:
|
||||
self.track_data = track_data
|
||||
self._trade_exchange = trade_exchange
|
||||
self.level_infra = LevelInfrastructure()
|
||||
self.level_infra.reset_infra(common_infra=common_infra)
|
||||
self.level_infra.reset_infra(common_infra=common_infra, executor=self)
|
||||
self._settle_type = settle_type
|
||||
self.reset(start_time=start_time, end_time=end_time, common_infra=common_infra)
|
||||
if common_infra is None:
|
||||
@@ -134,6 +134,8 @@ class BaseExecutor:
|
||||
else:
|
||||
self.common_infra.update(common_infra)
|
||||
|
||||
self.level_infra.reset_infra(common_infra=self.common_infra)
|
||||
|
||||
if common_infra.has("trade_account"):
|
||||
# NOTE: there is a trick in the code.
|
||||
# shallow copy is used instead of deepcopy.
|
||||
@@ -256,6 +258,7 @@ class BaseExecutor:
|
||||
object
|
||||
trade decision
|
||||
"""
|
||||
|
||||
if self.track_data:
|
||||
yield trade_decision
|
||||
|
||||
@@ -296,6 +299,7 @@ class BaseExecutor:
|
||||
|
||||
if return_value is not None:
|
||||
return_value.update({"execute_result": res})
|
||||
|
||||
return res
|
||||
|
||||
def get_all_executors(self) -> List[BaseExecutor]:
|
||||
@@ -396,7 +400,7 @@ class NestedExecutor(BaseExecutor):
|
||||
trade_decision = updated_trade_decision
|
||||
# NEW UPDATE
|
||||
# create a hook for inner strategy to update outer decision
|
||||
self.inner_strategy.alter_outer_trade_decision(trade_decision)
|
||||
trade_decision = self.inner_strategy.alter_outer_trade_decision(trade_decision)
|
||||
return trade_decision
|
||||
|
||||
def _collect_data(
|
||||
@@ -473,6 +477,9 @@ class NestedExecutor(BaseExecutor):
|
||||
# do nothing and just step forward
|
||||
sub_cal.step()
|
||||
|
||||
# Let inner strategy know that the outer level execution is done.
|
||||
self.inner_strategy.post_upper_level_exe_step()
|
||||
|
||||
return execute_result, {"inner_order_indicators": inner_order_indicators, "decision_list": decision_list}
|
||||
|
||||
def post_inner_exe_step(self, inner_exe_res: List[object]) -> None:
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import bisect
|
||||
from abc import abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, Set, Tuple, Union
|
||||
from typing import Any, Set, Tuple, TYPE_CHECKING, Union
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -184,8 +183,8 @@ class TradeCalendarManager:
|
||||
Tuple[int, int]:
|
||||
the index of the range. **the left and right are closed**
|
||||
"""
|
||||
left = bisect.bisect_right(list(self._calendar), start_time) - 1
|
||||
right = bisect.bisect_right(list(self._calendar), end_time) - 1
|
||||
left = np.searchsorted(self._calendar, start_time, side="right") - 1
|
||||
right = np.searchsorted(self._calendar, end_time, side="right") - 1
|
||||
left -= self.start_index
|
||||
right -= self.start_index
|
||||
|
||||
@@ -248,7 +247,7 @@ class LevelInfrastructure(BaseInfrastructure):
|
||||
sub_level_infra:
|
||||
- **NOTE**: this will only work after _init_sub_trading !!!
|
||||
"""
|
||||
return {"trade_calendar", "sub_level_infra", "common_infra"}
|
||||
return {"trade_calendar", "sub_level_infra", "common_infra", "executor"}
|
||||
|
||||
def reset_cal(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user