feat: eliminate duplicate price fetches — stale_push_wlin + per_stock_reassess now read from DB instead of self-pulling Tencent API

This commit is contained in:
知微
2026-07-01 22:32:30 +08:00
parent 82024a6d7f
commit f50b93d427
2 changed files with 940 additions and 934 deletions
+20 -26
View File
@@ -41,41 +41,35 @@ def main():
# Always fetch live price for accurate reassessment # Always fetch live price for accurate reassessment
price = 0 price = 0
try: try:
import urllib.request # 价格从 DB 读取(price_monitor 每2分钟更新,唯一价格入口)
code_raw = entry.get("code", "") code_raw = entry.get("code", "")
# 港股5位代码(含0开头)→ 前缀hk price = 0
if len(code_raw) == 5 and code_raw[0] in '01': import sqlite3
prefix = "hk" db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db')
db.row_factory = sqlite3.Row
row = db.execute("SELECT price FROM holdings WHERE code=? AND is_active=1", (code_raw,)).fetchone()
if not row:
row = db.execute("SELECT price FROM watchlist_stocks WHERE code=? AND is_active=1", (code_raw,)).fetchone()
if not row:
row = db.execute("SELECT price FROM holding_strategies WHERE code=? AND status='active' ORDER BY updated_at DESC LIMIT 1", (code_raw,)).fetchone()
if row:
price = row['price'] or 0
db.close()
if price > 0:
print(f" 实时价: {price} (来自DB)")
else: else:
sym_map = {"6":"sh","5":"sh","0":"sz","3":"sz"} # fallback to portfolio.json
for k, v in sym_map.items():
if code_raw.startswith(k):
prefix = v
break
if not prefix:
prefix = "sz"
url = f"http://qt.gtimg.cn/q={prefix}{code_raw}"
resp = urllib.request.urlopen(url, timeout=5)
text = resp.read().decode("gbk")
fields = text.split('"')[1].split("~")
price = float(fields[3]) if fields[3] else 0
print(f" 实时价: {price} {'(港股HKD)' if len(code_raw) == 5 and code_raw[0] in '01' else ''}")
except Exception as e:
print(f" 实时价获取失败: {e}", file=sys.stderr)
# Try portfolio.json as fallback (price_monitor keeps live prices)
try:
with open("/home/hmo/web-dashboard/data/portfolio.json") as _pf: with open("/home/hmo/web-dashboard/data/portfolio.json") as _pf:
_pf_data = json.load(_pf) _pf_data = json.load(_pf)
for _h in _pf_data.get("holdings", []): for _h in _pf_data.get("holdings", []):
if _h["code"] == code_raw: if _h["code"] == code_raw:
price = float(_h.get("price", 0)) price = float(_h.get("price", 0))
print(f" 从portfolio.json取实时价: {price}")
break break
except Exception: if price <= 0:
pass
if price == 0:
price = entry.get("current_price") or entry.get("price") or 0 price = entry.get("current_price") or entry.get("price") or 0
print(f" fallback到存储价: {price}", file=sys.stderr) except Exception as e:
print(f" 价格获取失败: {e}", file=sys.stderr)
price = entry.get("current_price") or entry.get("price") or 0
# Price diff debounce: skip reassessment if price changed < 1% since last update # Price diff debounce: skip reassessment if price changed < 1% since last update
last_price = entry.get("last_reassessed_price", 0) last_price = entry.get("last_reassessed_price", 0)
+20 -8
View File
@@ -74,18 +74,30 @@ from stock_scorer import score_future_outlook, is_hk_stock, settlement_delay_not
# ── 趋势检查 ──────────────────────────────────────────────────── # ── 趋势检查 ────────────────────────────────────────────────────
def fetch_trend_data(code): def fetch_trend_data(code):
"""取均线数据判断趋势状态。返回 (current_price, ma5, trend_label) 或 None""" """取均线数据判断趋势状态。价格从 DB 读取(price_monitor 唯一入口)。返回 (current_price, ma5, trend_label) 或 None"""
# 价格从 DB 读取,不再自拉腾讯 API
current = 0
try: try:
prefix = "sh" if code.startswith(('60','68','51','56','50')) else "sz" if code.startswith(('00','30','15')) else "hk" import sqlite3
url = f"http://qt.gtimg.cn/q={prefix}{code}" db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db')
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) db.row_factory = sqlite3.Row
resp = urlopen(req, timeout=5).read().decode('gbk') row = db.execute("SELECT price FROM holdings WHERE code=? AND is_active=1", (code,)).fetchone()
fld = resp.split('=')[1].strip().strip('"').strip(';').split('~') if not row:
current = float(fld[3]) if len(fld) > 3 else 0 row = db.execute("SELECT price FROM watchlist_stocks WHERE code=? AND is_active=1", (code,)).fetchone()
except: if not row:
row = db.execute("SELECT price FROM holding_strategies WHERE code=? AND status='active' ORDER BY updated_at DESC LIMIT 1", (code,)).fetchone()
if row:
current = row['price'] or 0
db.close()
except Exception:
pass
if current <= 0:
return None return None
# K线数据仍从腾讯取(均线计算需要历史K线,DB 里 stock_daily 表有但不一定有最新数据)
try: try:
prefix = "sh" if code.startswith(('60','68','51','56','50')) else "sz" if code.startswith(('00','30','15')) else "hk"
url = f"http://ifzq.gtimg.cn/appstock/app/fqkline/get?param={prefix}{code},day,,,30,qfq" url = f"http://ifzq.gtimg.cn/appstock/app/fqkline/get?param={prefix}{code},day,,,30,qfq"
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
resp = urlopen(req, timeout=5).read().decode('utf-8') resp = urlopen(req, timeout=5).read().decode('utf-8')