chore: deployed cleanup + hygiene system
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user