chore: deployed cleanup + hygiene system

This commit is contained in:
知微
2026-07-20 19:05:03 +08:00
parent 7f3ff66be4
commit 54c48dc5d7
926 changed files with 897917 additions and 7169 deletions
+89 -60
View File
@@ -12,8 +12,19 @@
"""
import json
import os
import urllib.request
from datetime import datetime, date
from mo_data import get_price
# 腾讯API字段索引
F = {
"name": 1, "code": 2, "price": 3, "close_yest": 4, "open": 5,
"volume": 6, "timestamp": 30, "change": 31, "change_pct": 32,
"high": 33, "low": 34, "amplitude": 43,
"turnover": 38, "pe": 39, "pb": 46,
"limit_up": 47, "limit_down": 48,
"avg_price": 51, "inner_vol": 52, "outer_vol": 53,
}
HISTORY_PATH = "/home/hmo/web-dashboard/data/price_history.json"
HISTORY_DAYS = 60 # 使用最近 N 天的 HLC 数据
@@ -44,7 +55,7 @@ def _market_prefix(code):
def get_quote(code):
"""获取行情数据。使用 mo_data.get_price 统一入口,缓存+格式转换"""
"""获取行情数据。先拿DB的价格和涨跌幅,再调腾讯API拿HLC全量数据"""
import time
_cache = get_quote.__dict__.get("_cache", {})
now = time.time()
@@ -52,51 +63,88 @@ def get_quote(code):
if cached and (now - cached["ts"]) < 60:
return cached["data"]
price, change_pct = get_price(code)
if price is None:
return {"code": code, "error": "价格获取失败"}
# 先从DB拿基础价格(快速,不阻塞)
db_price = None
db_chg = None
try:
from mofin_db import get_price_from_db
p, chg = get_price_from_db(code)
if p:
db_price, db_chg = p, chg
except:
pass
# 腾讯API获取全量HLC数据
raw = str(code).split("_")[0]
prefix = _market_prefix(code)
today_str = date.today().isoformat()
url = f"http://qt.gtimg.cn/q={prefix}{raw}"
try:
r = urllib.request.urlopen(url, timeout=5)
fields = r.read().decode("gbk").split('"')[1].split("~")
except Exception as e:
if db_price:
return {"code": code, "price": db_price, "change_pct": db_chg or 0}
return {"code": code, "error": str(e)}
def get(i):
try:
return float(fields[i]) if fields[i].strip() else None
except (IndexError, ValueError):
return None
today_str = date.today().isoformat()
q = {
"code": raw,
"market": prefix,
"name": code,
"price": price,
"close_yest": None,
"open": None,
"high": None,
"low": None,
"volume": None,
"amount": None,
"change": None,
"change_pct": change_pct or 0,
"amplitude": None,
"turnover_rate": None,
"pe": None,
"pb": None,
"limit_up": None,
"limit_down": None,
"avg_price": None,
"inner_vol": None,
"outer_vol": None,
"timestamp": "",
"name": fields[F["name"]] if len(fields) > F["name"] else code,
"price": get(3),
"close_yest": get(4),
"open": get(5),
"high": get(33),
"low": get(34),
"volume": get(6),
"amount": get(37),
"change": get(31),
"change_pct": get(32),
"amplitude": get(43),
"turnover_rate": get(38),
"pe": get(39),
"pb": get(46),
"limit_up": get(47),
"limit_down": get(48),
"avg_price": get(51),
"inner_vol": get(52),
"outer_vol": get(53),
"timestamp": fields[F["timestamp"]] if len(fields) > F["timestamp"] else "",
"_date": today_str,
}
# 写入价格历史缓存(每日一次,只存价格
history = _load_history()
if raw not in history:
history[raw] = []
days = history[raw]
if days and len(days) > 0 and days[-1].get("date") == today_str:
days[-1]["close"] = price
else:
days.append({"date": today_str, "close": price})
history[raw] = days[-HISTORY_DAYS:]
_save_history(history)
# 写入价格历史缓存(每日一次)
h = get(33) # high
l = get(34) # low
c = get(3) # price / close
v = get(6) # volume(手)
amt = get(37) # 成交额
if h and l and c:
history = _load_history()
if raw not in history:
history[raw] = []
days = history[raw]
# 如果今天已有记录,更新(盘中数据更精确)
if days and len(days) > 0 and days[-1].get("date") == today_str:
days[-1]["high"] = max(days[-1]["high"], h)
days[-1]["low"] = min(days[-1]["low"], l)
days[-1]["close"] = c # 盘中用最新价,收盘后是收盘价
if v: days[-1]["volume"] = v
if amt: days[-1]["amount"] = amt
else:
entry = {"date": today_str, "high": h, "low": l, "close": c}
if v: entry["volume"] = v
if amt: entry["amount"] = amt
days.append(entry)
# 只保留最近 HISTORY_DAYS 天
history[raw] = days[-HISTORY_DAYS:]
_save_history(history)
# 写入60秒缓存
get_quote.__dict__["_cache"] = {**get_quote.__dict__.get("_cache", {}), code: {"ts": now, "data": q}}
@@ -424,7 +472,9 @@ def analyze_volume_deep(code):
import sqlite3
from pathlib import Path
DATA_DIR = Path(__file__).parent.parent / "data"
DATA_DIR = Path(__file__).parent / "scripts" / "data"
if not (DATA_DIR / "mofin.db").exists():
DATA_DIR = Path(__file__).parent / "data"
try:
conn = sqlite3.connect(str(DATA_DIR / "mofin.db"))
row = conn.execute("SELECT cache_json FROM mtf_cache WHERE code=?", (code,)).fetchone()
@@ -587,30 +637,9 @@ def full_analysis(code):
if 'weekly' in mtf_raw:
w = mtf_raw['weekly']
ws = w.get('support_resistance', {})
wt = w.get('trend', {})
wm = w.get('mas', {})
mtf['weekly'] = {
mtf['weekly_sr'] = {
'weak_resist': ws.get('weak_resist'),
'weak_support': ws.get('weak_support'),
'strong_resist': ws.get('strong_resist'),
'strong_support': ws.get('strong_support'),
'trend': wt.get('direction', ''),
'ma5': wm.get('ma5'),
'ma10': wm.get('ma10'),
}
# 月线作为长期参考
if 'monthly' in mtf_raw:
m = mtf_raw['monthly']
ms = m.get('support_resistance', {})
mt = m.get('trend', {})
mm = m.get('mas', {})
mtf['monthly'] = {
'weak_resist': ms.get('weak_resist'),
'weak_support': ms.get('weak_support'),
'strong_resist': ms.get('strong_resist'),
'strong_support': ms.get('strong_support'),
'trend': mt.get('direction', ''),
'ma5': mm.get('ma5'),
}
except Exception:
pass # non-critical, graceful degradation