|
5 | 5 | """ |
6 | 6 | from __future__ import annotations |
7 | 7 |
|
| 8 | +import logging |
8 | 9 | import threading |
9 | 10 | import tkinter as tk |
10 | 11 | from datetime import date |
|
32 | 33 | write_batch_results_csv, |
33 | 34 | ) |
34 | 35 | from ...pricing_api import batch_price_from_provider_threaded |
35 | | -from ...market_valuation import load_history, valuation_banner |
| 36 | +from ...market_valuation import ( |
| 37 | + append_history, |
| 38 | + compute_snapshot, |
| 39 | + load_history, |
| 40 | + valuation_banner, |
| 41 | +) |
36 | 42 | from ...paths import data_path |
37 | 43 | from ...watchlist import load_watchlist |
38 | 44 | from ..widgets import Tooltip |
|
60 | 66 | if TYPE_CHECKING: |
61 | 67 | from ..app import CBPricerApp |
62 | 68 |
|
| 69 | +logger = logging.getLogger(__name__) |
| 70 | + |
63 | 71 | # 列预设: 简洁视图只保留投资决策最常看的字段, 完整视图沿用所有字段 |
64 | 72 | # 状态列: 成功 → ✓ (单字符即可), 失败行保留错误文本, 故宽度大幅收窄 |
65 | 73 | _BATCH_COLS_FULL = ( |
@@ -413,6 +421,9 @@ def on_progress(done, total): |
413 | 421 | params=params, |
414 | 422 | upcoming_results=watchlist_pricing, |
415 | 423 | ) |
| 424 | + # 样本外纪律: 全市场重算成功即自动记录当期估值快照 (同估值日幂等覆盖)。 |
| 425 | + # 仅主池重算触发; 缓存加载/关注池局部重算不记, 避免污染基线。 |
| 426 | + _record_valuation_history(results) |
416 | 427 | app._batch_results = results |
417 | 428 | app._batch_upcoming_results = watchlist_pricing |
418 | 429 | app._last_batch_source = provider.name |
@@ -528,6 +539,21 @@ def _render_batch_views( |
528 | 539 | _render_watchlist_table(app) |
529 | 540 |
|
530 | 541 |
|
| 542 | +def _record_valuation_history(results, history_path=None) -> bool: |
| 543 | + """全市场重算成功后把当期估值快照并入历史基线 (样本外纪律的自动化形态)。 |
| 544 | +
|
| 545 | + 同估值日幂等覆盖; 失败静默 (记录是副产品, 不能影响主流程)。返回是否成功记录。 |
| 546 | + """ |
| 547 | + try: |
| 548 | + snapshot = compute_snapshot(results or []) |
| 549 | + path = history_path or data_path("cb_valuation_history.json", seed=True) |
| 550 | + append_history(path, snapshot) |
| 551 | + return True |
| 552 | + except Exception: |
| 553 | + logger.debug("估值历史自动记录失败 (忽略)", exc_info=True) |
| 554 | + return False |
| 555 | + |
| 556 | + |
531 | 557 | def _update_valuation_banner(app, base_results) -> None: |
532 | 558 | """用全量定价池更新标题栏的转债大类估值/择时信号 (静默失败不影响主流程)。""" |
533 | 559 | if not hasattr(app, "v_batch_valuation"): |
|
0 commit comments