2626 build_batch_provider ,
2727 parse_bond_codes ,
2828)
29+ from ...backtest_disk_cache import DiskCacheProvider
2930from ...cb_events import CBEventStore , project_events_path
3031from ...data_providers import WindDataProvider
3132from ...historical_terms import (
3233 HistoricalBondDataProvider ,
3334 TermsPatchStore ,
3435 project_terms_patches_path ,
3536)
37+ from ...paths import data_dir
3638from ...strategy_backtest import (
3739 ScoreStrategyConfig ,
3840 _funding_legacy_alias ,
@@ -690,20 +692,26 @@ def _update():
690692 self .strategy_bt_progress .set (pct )
691693 self .after (0 , _update )
692694
693- result = backtest_score_strategy (
694- provider ,
695- codes ,
696- start_date = start ,
697- end_date = end ,
698- config = config ,
699- terms_cache = None ,
700- admission_config = admission_config ,
701- pricing_snapshot_cache = getattr (self , "_strategy_pricing_cache" , None ),
702- progress_cb = progress ,
703- stage_cb = stage_progress ,
704- cancel_cb = cancel_check ,
705- ** params ,
706- )
695+ try :
696+ result = backtest_score_strategy (
697+ provider ,
698+ codes ,
699+ start_date = start ,
700+ end_date = end ,
701+ config = config ,
702+ terms_cache = None ,
703+ admission_config = admission_config ,
704+ pricing_snapshot_cache = getattr (self , "_strategy_pricing_cache" , None ),
705+ progress_cb = progress ,
706+ stage_cb = stage_progress ,
707+ cancel_cb = cancel_check ,
708+ ** params ,
709+ )
710+ finally :
711+ # 跨运行磁盘缓存: 中途取消/异常也落盘已拉取的昂贵数据 (与 CLI 同口径)
712+ flush = getattr (provider , "flush" , None )
713+ if callable (flush ):
714+ flush ()
707715 result_config = dict (result .get ("config" ) or {})
708716 result_config ["history_mode" ] = history_mode
709717 result ["config" ] = result_config
@@ -766,7 +774,7 @@ def _build_strategy_provider(self, source):
766774 # 而是 strip 掉 Wind 泄漏的当前状态、改由 cb_events 按 event_date 重建。
767775 # 这些状态本就是离散公告事件 (cb_events 已覆盖 18 类), 事件重建既防未来
768776 # 函数又把每债 Wind 调用压到 ~2 次 (条款批量 wss + close wsd)。
769- return HistoricalBondDataProvider (
777+ provider = HistoricalBondDataProvider (
770778 WindDataProvider (),
771779 history_store = None ,
772780 patch_store = TermsPatchStore (project_terms_patches_path ()),
@@ -775,6 +783,9 @@ def _build_strategy_provider(self, source):
775783 merge_admission_status = False ,
776784 provider_history_terms = True ,
777785 )
786+ # 跨运行磁盘缓存 (与 CLI --cache-dir 同机制): 高保真逐债拉取的 point-in-time
787+ # 条款/历史价落盘复用, 复跑从数小时降到定价时间; 补丁/事件文件一变自动失效。
788+ return DiskCacheProvider (provider , data_dir ("strategy_backtest_cache" ))
778789
779790 base_provider = build_batch_provider (
780791 source ,
@@ -1354,6 +1365,17 @@ def _render_strategy_insight(self, result):
13541365 verdict = "暂无足够收益数据"
13551366 quality = "高" if fallback_ratio <= 0 else ("中" if fallback_ratio <= 0.2 else "低" )
13561367
1368+ hints = {
1369+ "结论" : "解读铁律: 一切对照「等权基准」——跑不赢基准 = 这套规则没有超额,\n "
1370+ "哪怕绝对收益为正。机会分是复核标记、不是收益预测;\n "
1371+ "单一市场周期的回测不构成策略承诺 (详见 USAGE 4.2 与 README 模型边界)。" ,
1372+ "最大回撤" : "净值从峰值到谷底的最大跌幅 = 历史上最深要忍受的亏损。\n "
1373+ "对照基准回撤判断风险是否换来了收益; 与持仓集中度、现金缓冲相关。" ,
1374+ "主要贡献" : "收益贡献最大的单券。若总收益高度依赖个别券 (尤其强赎/退市收敛券),\n "
1375+ "说明结果偏尾部运气而非系统性能力, 复现性存疑——去「归因」页核对。" ,
1376+ "数据质量" : "条款回退占比 = 用当前条款顶替历史条款的样本比例, >0 有未来信息渗入风险。\n "
1377+ "下结论前先看「数据」子页的补丁覆盖率与缺价跳过数。" ,
1378+ }
13571379 items = [
13581380 ("结论" , verdict ),
13591381 ("最大回撤" , (
@@ -1380,6 +1402,10 @@ def _render_strategy_insight(self, result):
13801402 font = (FONT_FAMILY , 13 , "bold" ), wraplength = 260 ,
13811403 justify = "left" )
13821404 value_label .pack (anchor = "w" )
1405+ hint = hints .get (title )
1406+ if hint :
1407+ Tooltip (cell , hint )
1408+ Tooltip (value_label , hint )
13831409
13841410 def _update_wrap (event , label = value_label ):
13851411 label .configure (wraplength = max (180 , event .width - 24 ))
0 commit comments