fix(portfolio): all_weather 小盘池码 + fq 口径 + stop_loss 日志

- all_weather:
  - s_stocks 399101.XSHE → 000852.XSHG(中证1000)。旧码在 constituent_unified
    无数据,分支C(小盘轮动)完全 dead(S_mean 恒 0)= 业绩差主因。
  - stop_loss -8% logger.debug → info(原 INFO 不可见,无法验收该分支)。
  - big/bm/small 阈值验证用放宽(适配年报口径+中证1000,最终业务决策再说):
    small roe>0.15&roa>0.10 → roe>0.05&roa>0.02(原 roa>0.10 命中仅~5%)。
- runner_backtest: build_broker_facade_inner 注入 set_option 委托 bullet_trade
  settings + initialize 顺序改(先注入 broker 再 initialize)。修 fq 口径不一致
  (engine fq_mode=none raw vs get_current_data fq=pre)致大盘市价保护价<当前价不成交。

修后 all_weather 2022-2024 全量验证(726交易日,max-pool 50):
总收益 0.82%→15.48%,夏普 -0.16→+0.04,回撤 -27%→-23%。
全分支跑通:月度调仓36 / 分支A无敌行情2月 / 分支C小盘活了(末日全仓小盘) /
stop_loss -8% 触发111次。
This commit is contained in:
2026-07-24 11:27:25 +08:00
parent 0ef0cadaff
commit e807bed09c
2 changed files with 33 additions and 18 deletions
+7 -1
View File
@@ -172,9 +172,11 @@ def run_backtest(args: argparse.Namespace) -> Dict[str, Any]:
except Exception as exc:
logger.warning("注册定时任务失败(回测可能不触达): %s", exc)
strategy.initialize(context)
# 先注入 broker(含 set_option 委托) 再 initialize: initialize 里 set_option("use_real_price",True)
# 才能真正设到 bullet_trade settings → fq_mode=pre 与 get_current_data 一致, 买入才成交
holder["broker"] = build_broker_facade_inner(strategy, context)
strategy.broker = holder["broker"]
strategy.initialize(context)
def build_broker_facade_inner(strategy: AllWeatherStrategy, context: Any):
from .strategies.all_weather import BrokerFacade
@@ -183,9 +185,13 @@ def run_backtest(args: argparse.Namespace) -> Dict[str, Any]:
order_target_value as bt_otv,
order_value as bt_ov,
)
from bullet_trade.core.settings import set_option as bt_set_option # type: ignore
return BrokerFacade(
order_target_value=lambda c, v: bt_otv(c, v),
order_value=lambda c, v: bt_ov(c, v),
# 注入 set_option 委托 bullet_trade settings: 让策略 set_option("use_real_price",True)
# 真正生效 → engine fq_mode=pre 与 get_current_data(fq=pre) 一致, 避免保护价<当前价不成交
set_option=lambda k, v: bt_set_option(k, v),
)
print("[runner] ENGINE_BUILD_PRE", flush=True)