feat: strategy_lifecycle + stale_detector + server — DB-first price reads, Tencent API as fallback only

This commit is contained in:
知微
2026-07-01 22:48:48 +08:00
parent 849495c4ba
commit 8ed755bff9
3 changed files with 227 additions and 32 deletions
+40 -22
View File
@@ -889,31 +889,49 @@ def upload_confirm():
try:
codes = [s["code"] for s in stocks if s.get("code")]
if codes:
qs = " ".join(
f"hk{c}" if len(c) == 5 # 港股5位代码
else f"sz{c}" if c.startswith("0") or c.startswith("3")
else f"sh{c}" if c.startswith("6")
else f"hk{c}"
for c in codes
)
url = f"https://qt.gtimg.cn/q={qs}"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
resp = urllib.request.urlopen(req, timeout=10)
qt_text = resp.read().decode("gbk", errors="replace")
# map realtime prices
# DB 优先(price_monitor 维护的实时价)
db_prices = {}
try:
import sqlite3
db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db')
db.row_factory = sqlite3.Row
for code in codes:
row = db.execute("SELECT price, change_pct FROM holdings WHERE code=? AND is_active=1", (code,)).fetchone()
if row and row['price']:
db_prices[code] = (row['price'], row['change_pct'] or 0)
db.close()
except Exception:
pass
# Fallback: 腾讯 API
need_tencent = [c for c in codes if c not in db_prices]
if need_tencent:
qs = " ".join(
f"hk{c}" if len(c) == 5
else f"sz{c}" if c.startswith("0") or c.startswith("3")
else f"sh{c}" if c.startswith("6")
else f"hk{c}"
for c in need_tencent
)
url = f"https://qt.gtimg.cn/q={qs}"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
resp = urllib.request.urlopen(req, timeout=10)
qt_text = resp.read().decode("gbk", errors="replace")
# 优先 DB 价格,再补腾讯
for stock in stocks:
code = stock.get("code", "")
prefix = "hk" if len(code) == 5 else "sz" if code.startswith(("0","3")) else "sh" if code.startswith("6") else "hk"
# 腾讯 API 格式: prefix+code="市场~名称~代码~当前价~昨收~今开~成交量~..."
m = re.search(rf'{prefix}{code}="([^"]+)"', qt_text)
if m:
fields = m.group(1).split('~')
name = fields[1]
price = fields[3] # 当前价
if code in db_prices:
if not stock.get("price"):
stock["price"] = price
if not stock.get("name"):
stock["name"] = name
stock["price"] = db_prices[code][0]
elif need_tencent and code in need_tencent:
prefix = "hk" if len(code) == 5 else "sz" if code.startswith(("0","3")) else "sh" if code.startswith("6") else "hk"
m = re.search(rf'{prefix}{code}="([^"]+)"', qt_text)
if m:
fields = m.group(1).split('~')
if not stock.get("name"):
stock["name"] = fields[1]
if not stock.get("price"):
stock["price"] = fields[3]
except:
pass # 行情获取失败不影响主流程