diff --git a/data/portfolio.json b/data/portfolio.json index cb3e1a7..6d0f6ed 100644 --- a/data/portfolio.json +++ b/data/portfolio.json @@ -649,15 +649,15 @@ "_currency": "CNY" } ], - "cash": 113240.25, + "cash": 92678.85, "total_market_value": 835552.6, - "total_assets": 948792.85, + "total_assets": 928231.45, "total_pl": 0, - "position_pct": 88.06, - "updated_at": "2026-06-29 22:03", + "position_pct": 90.02, + "updated_at": "2026-06-29 22:23:47", "source": "/home/hmo/stocks/holding.xls", "frozen_cash": 39481.4, - "available_cash": 73758.85, + "available_cash": 92678.85, "frozen": 39481.4, "total_cash": 132145.6, "cash_updated_at": "2026-06-29 12:34", @@ -672,11 +672,20 @@ "timestamp": "2026-06-29 10:43" } ], - "total_mv": 855311.0, + "total_mv": 835552.6, "note": "cash fixed from screenshot 6/29, prices=CNY", "currency": "CNY", "last_verified_at": "2026-06-29 22:20", "_total_mv": 835552.6, "_total_cash": 113240.25, - "_total_assets": 948792.85 + "_total_assets": 948792.85, + "cash_history": [ + { + "time": "2026-06-29 22:23:47", + "cash": 92678.85, + "frozen": 39481.4, + "source": "manual:post-法拉电子-sell-100shares@189.2", + "formula": "初始可用73758.85+法拉电子18920" + } + ] } \ No newline at end of file diff --git a/price_monitor.py b/price_monitor.py index 58fa254..779e888 100644 --- a/price_monitor.py +++ b/price_monitor.py @@ -199,32 +199,22 @@ def refresh_data_prices(): json.dump(wl, open(WATCHLIST_PATH, 'w'), ensure_ascii=False, indent=2) # --- 汇总值重算(2026-06-29 bugfix: 之前price_monitor只更新个股价,不更新汇总)--- - # total_market_value / total_assets / cash / position_pct 来自import_holding_xls快照 - # 价格更新后必须同步刷新汇总,否则报告使用过期汇总 → 现金/资产/仓位全错 try: live_market_value = sum( h.get('shares', 0) * h.get('price', 0) for h in pf.get('holdings', []) ) - # 现金:优先用经过Dad截图确认的可用+冻结字段 - # 2026-06-29 bugfix: 之前从strategy_staleness_report读现金(循环依赖→值被污染) - # 正确公式: 总现金 = 可用现金(截图确认) + 冻结资金(截图确认) - av = pf.get('available_cash', pf.get('_available_cash', 0)) - fz = pf.get('frozen_cash', pf.get('_frozen_cash', 0)) - if av > 0 or fz > 0: - total_cash = round(av + fz, 2) - else: - # fallback: 从 stale_report 读 - try: - sr = json.load(open('/home/hmo/web-dashboard/data/strategy_staleness_report.json')) - total_cash = sr.get('portfolio', {}).get('cash', 0) - except: - total_cash = pf.get('cash', 0) - old_cash = pf.get('cash', 0) - if abs(old_cash - total_cash) > 0.01: - pf['cash'] = total_cash + # 现金:绝不重算。保留上次的值(来自截图/导入/手动修改)。 + # 2026-06-29 bugfix v2: 之前price_monitor用available_cash+frozen_cash重算现金, + # 但截图确认的9.2万被旧冻结数据(3.9万)覆盖=113k,导致cash来回跳 + # 修正:price_monitor只更新market_value,不碰cash + old_mv = pf.get('total_mv', 0) + if abs(old_mv - live_market_value) > 0.01: + pf['total_mv'] = round(live_market_value, 2) + + total_cash = pf.get('cash', 0) # 保留上次的现金值,不重算 pf['total_assets'] = round(live_market_value + total_cash, 2) if pf['total_assets'] > 0: pf['position_pct'] = round(live_market_value / pf['total_assets'] * 100, 2)