feat: data-layering 消费层读live_prices替换直连qt.gtimg.cn(5脚本)

This commit is contained in:
xxm
2026-08-26 19:55:38 +08:00
parent ad5adbee4a
commit bd1ef0c9a4
5 changed files with 181 additions and 219 deletions
+47 -88
View File
@@ -742,7 +742,7 @@ def load_macro_context():
def batch_fetch_prices(codes):
"""获取实时价格。优先从 DB 读取(price_monitor 每 2 分钟更新),失败才拉腾讯 API"""
"""获取实时价格。优先从 holdings DB 读取(price_monitor 维护),兜底读 live_prices 表(2026-08-26 分层铁律)"""
if not codes:
return {}
@@ -777,74 +777,42 @@ def batch_fetch_prices(codes):
except Exception:
pass
# Fallback: 腾讯 API(仅当 DB 无数据时
batch_size = 15
for batch_start in range(0, len(codes), batch_size):
batch = codes[batch_start:batch_start + batch_size]
symbols = []
code_map = {}
for raw_code in batch:
raw_code = str(raw_code).split('_')[0]
if not raw_code:
continue
if len(raw_code) == 5 and raw_code.isdigit():
prefix = "hk"
elif raw_code.startswith(("6", "5")):
prefix = "sh"
else:
prefix = "sz"
sym = f"{prefix}{raw_code}"
symbols.append(sym)
code_map[sym] = raw_code
if not symbols:
continue
url = f"http://qt.gtimg.cn/q={','.join(symbols)}"
max_retries = 2
for attempt in range(max_retries + 1):
try:
r = urllib.request.urlopen(url, timeout=10)
text = r.read().decode("gbk")
except Exception as e:
if attempt < max_retries:
# Fallback: live_prices 表(price_monitor 2分钟级实时价;2026-08-26 分层铁律:消费层不直连腾讯API
try:
import sqlite3 as _sq
_db = _sq.connect('/home/hmo/MoFin/data/mofin.db', timeout=5)
_codes = []
_seen = set()
for _rc in codes:
_rc = str(_rc).split('_')[0]
if _rc and _rc not in _seen:
_seen.add(_rc)
_codes.append(_rc)
if _codes:
_ph = ",".join("?" * len(_codes))
_rows = _db.execute(
f"SELECT code, price, change_pct FROM live_prices WHERE code IN ({_ph})", _codes
).fetchall()
for _c, _p, _cg in _rows:
if not _p:
continue
print(f" batch_fetch_prices error: {e}", file=sys.stderr)
continue
for line in text.strip().split("\n"):
line = line.strip()
if not line or "=" not in line:
continue
try:
sym = line.split("=", 1)[0].strip().lstrip("v_")
raw_value = line.split("=", 1)[1].strip().strip('"').strip(";")
fields = raw_value.split("~")
if len(fields) < 35:
continue
orig_code = code_map.get(sym)
if not orig_code:
continue
def f(i):
try:
return float(fields[i]) if fields[i].strip() else 0.0
except:
return 0.0
price_raw = f(3)
# 港股:腾讯 API 返回 HKD 原值,价格比较/止损止盈直接用原值
# (仅市值/总资产汇总时由 mo_models.calc_total_assets 折算 CNY
all_results[orig_code] = {
"price": price_raw, "close": f(4), "high": f(33), "low": f(34),
"code": orig_code,
}
except Exception:
continue
break # Success - break retry loop
_chg = _cg or 0.0
# 港股 live_prices 价格为 HKD 原值,价格比较/止损止盈直接用原值
# (仅市值/总资产汇总时由 mo_models.calc_total_assets 折算 CNY
_cl = _p / (1 + _chg / 100) if _chg else _p
all_results[_c] = {
"price": _p, "close": _cl, "high": _p, "low": _p,
"code": _c,
}
_db.close()
except Exception as e:
print(f" batch_fetch_prices live_prices error: {e}", file=sys.stderr)
return all_results
def get_price_tencent(code):
"""获取实时价格。优先 DBprice_monitor 维护),失败才拉腾讯。港股价格存 HKD 原值。"""
"""获取实时价格。优先 DBholdings),兜底 live_prices 表(price_monitor 维护)。港股价格存 HKD 原值。"""
raw_code = str(code).split('_')[0]
if not raw_code:
return None
@@ -864,33 +832,24 @@ def get_price_tencent(code):
except Exception:
pass
# Fallback: 腾讯 API
# Fallback: live_prices 表(price_monitor 2分钟级实时价;2026-08-26 分层铁律:消费层不直连腾讯API
try:
from mo_models import is_hk_stock
except ImportError:
is_hk_stock = lambda c: len(str(c).strip()) == 5 and str(c).strip().isdigit()
try:
if is_hk_stock(raw_code):
prefix = "hk"
elif raw_code.startswith("6") or raw_code.startswith("5"):
prefix = "sh"
else:
prefix = "sz"
url = f"http://qt.gtimg.cn/q={prefix}{raw_code}"
r = urllib.request.urlopen(url, timeout=5)
fields = r.read().decode("gbk").split('"')[1].split("~")
def f(i):
try:
return float(fields[i]) if fields[i].strip() else 0.0
except:
return 0.0
price = f(3)
return {
"price": price, "close": f(4), "high": f(33), "low": f(34),
"code": raw_code,
}
import sqlite3 as _sq
_db = _sq.connect('/home/hmo/MoFin/data/mofin.db', timeout=5)
_row = _db.execute("SELECT price, change_pct FROM live_prices WHERE code=?", (raw_code,)).fetchone()
_db.close()
if _row and _row[0]:
_chg = _row[1] or 0.0
# 港股 live_prices 价格为 HKD 原值
_cl = _row[0] / (1 + _chg / 100) if _chg else _row[0]
return {
"price": _row[0], "close": _cl, "high": _row[0], "low": _row[0],
"code": raw_code,
}
print(f" get_price live_prices 无数据 {code}", file=sys.stderr)
return None
except Exception as e:
print(f" get_price error {code}: {e}", file=sys.stderr)
print(f" get_price live_prices error {code}: {e}", file=sys.stderr)
return None