refactor: 统一价格入口 mo_data.get_price() - 22个脚本移除自拉腾讯API
所有价格获取统一走 mo_data.get_price() / get_prices_batch():
- 优先读 live_prices(DB) → 无/过期才调 stock_quote(API) → 自动写回DB
- 22个脚本全部替换:branch_scanner chip_factors divergence_detector
market_screener mo_provider mofin_collect monitor_300308 300308_monitor
multi_timeframe refresh_macro_context stale_detector stale_push_wlin
stock_profile strategy_evaluator strategy_lifecycle strategy_review
strategy-staleness-check technical_analysis xiaoguo_signal_consumer
collect_evaluation_data
This commit is contained in:
+23
-96
@@ -7,114 +7,41 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import urllib.request
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from mo_data import read_portfolio, read_decisions, read_watchlist
|
||||
from mo_data import read_portfolio, read_decisions, read_watchlist, get_price
|
||||
|
||||
DATA_DIR = "/home/hmo/web-dashboard/data"
|
||||
MTF_CACHE_PATH = os.path.join(DATA_DIR, "multi_tf_cache.json")
|
||||
MACRO_PATH = os.path.join(DATA_DIR, "macro_context.json")
|
||||
PORTFOLIO_PATH = os.path.join(DATA_DIR, "portfolio.json")
|
||||
|
||||
# 腾讯API字段索引(quote批量接口)
|
||||
F = {
|
||||
"name": 1, "code": 2, "price": 3, "close_yest": 4, "open": 5,
|
||||
"volume": 6, "outer_vol": 7, "inner_vol": 8,
|
||||
"timestamp": 30, "change": 31, "change_pct": 32,
|
||||
"high": 33, "low": 34,
|
||||
"turnover": 37, "turnover_rate": 38, "pe": 39,
|
||||
"high_limit": 41, "low_limit": 42, "amplitude": 43,
|
||||
"market_cap_流通": 44, "market_cap_总": 45, "pb": 46,
|
||||
"ep": 47, "es": 48, "eps": 49,
|
||||
"avg_price": 51,
|
||||
"sector_tag": 60, "sector": 61,
|
||||
"high_52w": 67, "low_52w": 68,
|
||||
}
|
||||
|
||||
# 港股字段偏移不同
|
||||
F_HK = {
|
||||
"name": 1, "code": 2, "price": 3, "close_yest": 4,
|
||||
"change": 31, "change_pct": 32,
|
||||
"high": 33, "low": 34, "high_limit": 48, "low_limit": 49,
|
||||
"pe": 57, "pb": 58, "eps": 72, "market_cap_总": 45,
|
||||
"turnover": 37,
|
||||
}
|
||||
|
||||
|
||||
def get_quote(code: str) -> dict:
|
||||
"""获取腾讯API实时行情+基本面"""
|
||||
raw = str(code).split("_")[0]
|
||||
if len(raw) == 5 and raw.isdigit():
|
||||
prefix = "hk"
|
||||
fields = F_HK
|
||||
elif raw.startswith("6") or raw.startswith("5"):
|
||||
prefix = "sh"
|
||||
fields = F
|
||||
else:
|
||||
prefix = "sz"
|
||||
fields = F
|
||||
|
||||
# DB 优先
|
||||
try:
|
||||
from mofin_db import get_price_from_db
|
||||
p, chg = get_price_from_db(raw)
|
||||
if p: return {"price": p, "name": name, "code": raw, "change_pct": chg or 0}
|
||||
except: pass
|
||||
# Fallback: 腾讯
|
||||
url = f"http://qt.gtimg.cn/q={prefix}{raw}"
|
||||
try:
|
||||
req = urllib.request.Request(url, headers={
|
||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
|
||||
})
|
||||
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||
raw_text = resp.read().decode("gbk")
|
||||
fields_raw = raw_text.split('"')[1].split("~")
|
||||
except Exception as e:
|
||||
return {"code": code, "error": str(e)}
|
||||
|
||||
def get(idx):
|
||||
try:
|
||||
v = fields_raw[idx].strip()
|
||||
return float(v) if v else None
|
||||
except (IndexError, ValueError):
|
||||
return None
|
||||
|
||||
def get_str(idx):
|
||||
try:
|
||||
return fields_raw[idx].strip()
|
||||
except IndexError:
|
||||
return ""
|
||||
|
||||
is_hk = prefix == "hk"
|
||||
"""获取实时行情。使用 mo_data.get_price 统一入口,保持dict格式兼容"""
|
||||
price, change_pct = get_price(code)
|
||||
if price is None:
|
||||
return {"code": code, "error": "价格获取失败"}
|
||||
|
||||
result = {
|
||||
"code": raw,
|
||||
"name": get_str(fields["name"]),
|
||||
"price": get(fields["price"]),
|
||||
"change_pct": get(fields["change_pct"]),
|
||||
"high": get(fields["high"]),
|
||||
"low": get(fields["low"]),
|
||||
"pe": get(fields["pe"]),
|
||||
"pb": get(fields["pb"]),
|
||||
"eps": get(fields["eps"]),
|
||||
"code": code,
|
||||
"name": "",
|
||||
"price": price,
|
||||
"change_pct": change_pct or 0,
|
||||
"high": None,
|
||||
"low": None,
|
||||
"pe": None,
|
||||
"pb": None,
|
||||
"eps": None,
|
||||
"market_cap": None,
|
||||
"market_cap_流通": None,
|
||||
"high_52w": None,
|
||||
"low_52w": None,
|
||||
"turnover_rate": None,
|
||||
"amplitude": None,
|
||||
"sector": None,
|
||||
"outer_vol": None,
|
||||
"inner_vol": None,
|
||||
}
|
||||
|
||||
if is_hk:
|
||||
result["market_cap"] = get(fields["market_cap_总"])
|
||||
result["high_52w"] = get(fields["high_limit"])
|
||||
result["low_52w"] = get(fields["low_limit"])
|
||||
else:
|
||||
result["market_cap"] = get(fields["market_cap_总"])
|
||||
result["market_cap_流通"] = get(fields["market_cap_流通"])
|
||||
result["high_52w"] = get(fields["high_52w"])
|
||||
result["low_52w"] = get(fields["low_52w"])
|
||||
result["turnover_rate"] = get(fields["turnover_rate"])
|
||||
result["amplitude"] = get(fields["amplitude"])
|
||||
result["sector"] = get_str(fields["sector"])
|
||||
result["outer_vol"] = get(fields["outer_vol"])
|
||||
result["inner_vol"] = get(fields["inner_vol"])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user