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
+36 -2
View File
@@ -20,9 +20,43 @@ PORTFOLIO_PATH = "/home/hmo/web-dashboard/data/portfolio.json"
def fetch_prices(codes):
import urllib.request
"""统一价格源:优先 stock_quote.py,腾讯API降级为兜底"""
if not codes:
return {}
# 尝试用 stock_quote.py 获取(脚本强制规范)
try:
import subprocess
script = None
for p in ["/home/hmo/MoFin/scripts/stock_quote.py", "/home/hmo/MoFin/stock_quote.py"]:
if os.path.exists(p):
script = p
break
if script:
result = subprocess.run(
[sys.executable, script] + [str(c) for c in codes],
capture_output=True, text=True, timeout=30
)
if result.returncode == 0 and result.stdout.strip():
results = {}
for line in result.stdout.strip().split("\n"):
if not line.strip():
continue
try:
item = json.loads(line)
code = str(item.get("code", ""))
price = item.get("price")
change = item.get("change_pct", 0)
if code and price is not None:
results[code] = (float(price), float(change))
except (json.JSONDecodeError, ValueError):
continue
if results:
return results
except Exception as e:
print(f"[STALE] stock_quote.py 回退: {e}", file=sys.stderr)
# 兜底:腾讯API(不应依赖,仅作为最后手段)
import urllib.request
symbols, code_map = [], {}
for c in codes:
c = str(c).strip()
@@ -38,7 +72,7 @@ def fetch_prices(codes):
with urllib.request.urlopen(req, timeout=10) as r:
text = r.read().decode("gbk")
except Exception as e:
print(f"FETCH_FAIL: {e}", file=sys.stderr)
print(f"FETCH_FAIL (fallback): {e}", file=sys.stderr)
return {}
results = {}