From c1c4ba4a81699bbfb3bd4445157dcde760bb2be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E5=BE=AE?= Date: Fri, 3 Jul 2026 13:24:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20price=5Fmonitor=20HKD=E2=86=92CNY=20+=20?= =?UTF-8?q?Eastmoney=202s=20timeout=20+=20None-safe=20+=20summary=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- price_monitor.py | 30 +++++++++++++++++++++--------- scripts/fix_summary.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 scripts/fix_summary.py diff --git a/price_monitor.py b/price_monitor.py index 979645e..b6d24e5 100644 --- a/price_monitor.py +++ b/price_monitor.py @@ -131,21 +131,26 @@ def fetch_hk_eastmoney(codes): results = {} - # 主通道:东方财富实时行情(逐股查询,港股仅~10只,<1秒完成。该API不支持批量) + # 主通道:东方财富实时行情(逐股查询,2秒超时。连续失败则立即切腾讯兜底) + consecutive_fail = 0 for code in hk_codes: try: + if consecutive_fail >= 3: + break # 前3只都失败,东财不可用,直接切腾讯 url = (f"https://push2.eastmoney.com/api/qt/stock/get" f"?secid=116.{code}" f"&fields=f43,f170,f60,f57,f58" f"&fltt=2") req = urllib.request.Request(url, headers={"User-Agent": UA}) - with urllib.request.urlopen(req, timeout=5) as r: + with urllib.request.urlopen(req, timeout=2) as r: resp = json.loads(r.read().decode("utf-8")) if resp.get("rc") != 0: + consecutive_fail += 1 continue item = resp.get("data", {}) if not item: + consecutive_fail += 1 continue price = float(item.get("f43", 0)) if item.get("f43") else 0 prev_close = float(item.get("f60", 0)) if item.get("f60") else 0 @@ -153,10 +158,12 @@ def fetch_hk_eastmoney(codes): change_pct = str(item.get("f170", "0")) if price > 0: results[code] = (price, change, change_pct) - time.sleep(0.1) # 防止触发东财反爬(逐股查询,不支持批量) + consecutive_fail = 0 # 成功后重置计数 + time.sleep(0.1) except Exception as e: - print(f"⚠️ 东方财富 {code} 拉取失败: {e}", file=sys.stderr) - continue + consecutive_fail += 1 + if consecutive_fail <= 2: + print(f"⚠️ 东方财富 {code} 拉取失败: {e}", file=sys.stderr) # Fallback: 腾讯 qt.gtimg.cn(15分钟延迟) missing = [c for c in hk_codes if c not in results] @@ -248,12 +255,14 @@ def refresh_data_prices(): if s['code'] in prices: price, _, change_pct = prices[s['code']] if price > 0: - # 港股API返回HKD,直接存HKD原值。calc_total_mv统一做CNY折算 - old = s.get('price', 0) + # 港股:API返回HKD,需转CNY。系统统一存CNY标价 + if is_hk_stock(s['code']): + price = round(price * HK_RATE, 2) + old = s.get('price') or 0 if abs(old - price) > 0.001: s['price'] = round(price, 2) s['change_pct'] = float(change_pct) if change_pct else 0 - s['currency'] = 'HKD' if is_hk_stock(s['code']) else 'CNY' + s['currency'] = 'CNY' updated += 1 changed = True if changed: @@ -297,7 +306,10 @@ def refresh_data_prices(): if s['code'] in prices: price, _, change_pct = prices[s['code']] if price > 0: - old = s.get('price', 0) + # 港股:API返回HKD,需转CNY + if is_hk_stock(s['code']): + price = round(price * HK_RATE, 2) + old = s.get('price') or 0 if abs(old - price) > 0.001: s['price'] = round(price, 2) s['change_pct'] = float(change_pct) if change_pct else 0 diff --git a/scripts/fix_summary.py b/scripts/fix_summary.py new file mode 100644 index 0000000..c41c652 --- /dev/null +++ b/scripts/fix_summary.py @@ -0,0 +1,30 @@ +"""Fix portfolio_summary directly from holdings table""" +import sqlite3, sys +sys.path.insert(0, '/home/hmo/MoFin') +from mo_models import calc_total_mv, calc_total_assets, calc_position_pct +from datetime import datetime + +db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') + +# Get holdings +rows = db.execute("SELECT code, name, shares, cost, price, market_value, change_pct, currency, position_pct FROM holdings WHERE is_active=1").fetchall() +holdings = [dict(zip(['code','name','shares','cost','price','market_value','change_pct','currency','position_pct'], r)) for r in rows] + +# Get cash/summary +sr = db.execute("SELECT cash, frozen_cash FROM portfolio_summary WHERE id=1").fetchone() +cash = sr[0] or 0 +frozen = sr[1] or 0 + +pf = {'holdings': holdings, 'cash': cash, 'frozen_cash': frozen} +mv = calc_total_mv(holdings) +ta = calc_total_assets(pf) +pp = calc_position_pct(pf) +pnl = sum((h['price'] or 0) * (h['shares'] or 0) - (h['cost'] or 0) * (h['shares'] or 0) for h in holdings) + +print(f"mv={mv} ta={ta} pnl={pnl} pp={pp}%") + +db.execute("UPDATE portfolio_summary SET total_mv=?, total_assets=?, total_pnl=?, position_pct=?, updated_at=? WHERE id=1", + (mv, ta, pnl, pp, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) +db.commit() +print("portfolio_summary updated") +db.close()