全数据路径审计修复:price_monitor HK股价不再转CNY

审计发现(2026-07-03 15:00 systematic audit):
1. price_monitor 港股仍转 CNY (line 255, 306) → 改为存 HKD 原值, currency=HKD
2. strategy_lifecycle 质量门禁检查 currency=CNY (line 88-91) → 改为接受 HKD/CNY
3. strategy_lifecycle 新建策略写 currency='CNY' (line 2299) → 改为按代码判断 HKD/CNY
4. stale_push_wlin 两处直接 json.load(open(decisions.json)) → 改为 read_decisions()
5. stale_push_wlin 直接 json.load(open(portfolio.json)) → 改为 read_portfolio()
6. DB holdings/holding_strategies: 8只HK股currency从CNY改为HKD
7. calc_total_mv 增加港股HKD→CNY汇兑计算

验证:
- 建滔 84.45 HKD 浮亏-4.3%(不是-24%)
- 现金 132,121.93 总资产 953,295
- 所有8只HK股DB正确标记HKD
- price_monitor已重启,下个tick用新逻辑写HKD原值
- stale_push_wlin已换用mo_data读DB
This commit is contained in:
知微
2026-07-03 17:13:19 +08:00
parent 0bfb819110
commit 908dc6a897
12 changed files with 1542 additions and 1668 deletions
+10 -10
View File
@@ -84,11 +84,11 @@ STRATEGY_QUALITY_GATES = [
"fix": "tech_snapshot 包含强撑/弱撑/弱压/强压至少3个数值"
},
{
"id": "GATE_CURRENCY_SET",
"desc": "港股决策金额应为人民币标价(currency=CNY)",
"check": lambda d: not is_hk_stock(d.get("code","")) or d.get("currency") in ("CNY", None),
"severity": "MEDIUM",
"fix": "设置 d['currency']='CNY'(系统统一存CNY"
"id": "GATE_CURRENCY",
"severity": "CRITICAL",
"desc": "港股决策金额应为港币标价(currency=HKD)A股为CNY",
"check": lambda d: d.get("currency") in ("HKD", "CNY") or not d.get("code"),
"fix": "设置 d['currency']='HKD' for HK stocks"
},
# --- 第4条 CRITICAL 红线:9维交叉验证 (2026-07-02 Dad要求) ---
# 策略不能只有价格数字,必须有证据经过了多维分析:
@@ -2293,10 +2293,10 @@ def regenerate_all(stdout=True):
sector_ctx_str = f"大盘上涨比{market_breadth}%"
new_entry = {
"code": code, "name": name, "price": price,
"cost": old_entry.get("cost", cost) if old_entry else cost, # 优先保留旧成本(holding.xls权威)
"shares": shares, # 当前实际持仓股数(不继承旧决策的可能为0的值)
"avg_price": old_entry.get("avg_price", 0), # 保留持仓均价
"currency": "CNY", # 系统统一存人民币标价(mo_models规范)
"cost": old_entry.get("cost", cost) if old_entry else cost,
"shares": shares,
"avg_price": old_entry.get("avg_price", 0),
"currency": "HKD" if is_hk_stock(code) else "CNY",
"action": result["action"],
"stop_loss": result.get("stop_loss"),
"entry_low": result["entry_low"],
@@ -2526,7 +2526,7 @@ def regenerate_all(stdout=True):
write_holdings_batch(conn, existing_pf.get('holdings', []))
write_portfolio_summary(conn, existing_pf)
for s in wl.get('stocks', []):
s.setdefault('currency', 'CNY')
s.setdefault('currency', 'HKD') if is_hk_stock(str(s.get('code',''))) else s.setdefault('currency', 'CNY')
write_watchlist_stock(conn, s)
for d in decisions:
# ── 策略质量门禁 ──