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:
+49
-37
@@ -15,7 +15,7 @@ import sys
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
sys.path.insert(0, '/home/hmo/MoFin')
|
||||
from mo_data import read_portfolio, read_decisions, read_watchlist
|
||||
from mo_data import read_portfolio, read_decisions, read_watchlist, get_price, get_prices_batch
|
||||
|
||||
|
||||
def fetch_prices(codes):
|
||||
@@ -54,45 +54,14 @@ def fetch_prices(codes):
|
||||
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()
|
||||
p = "sh" if (len(c) == 6 and c[0] in "569") else "sz" if len(c) == 6 else "hk"
|
||||
sym = f"{p}{c}"
|
||||
symbols.append(sym)
|
||||
code_map[sym] = c
|
||||
# 兜底:mo_data.get_prices_batch
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
f"http://qt.gtimg.cn/q={','.join(symbols)}",
|
||||
headers={"User-Agent": "curl/7.81"},
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=10) as r:
|
||||
text = r.read().decode("gbk")
|
||||
raw = get_prices_batch(codes)
|
||||
if raw:
|
||||
return {code: (p, chg) for code, (p, chg) in raw.items()}
|
||||
except Exception as e:
|
||||
print(f"FETCH_FAIL (fallback): {e}", file=sys.stderr)
|
||||
return {}
|
||||
|
||||
results = {}
|
||||
for line in text.strip().split("\n"):
|
||||
if "=" not in line:
|
||||
continue
|
||||
try:
|
||||
raw = line.split("=", 1)[1].strip().strip('"').strip(";")
|
||||
fld = raw.split("~")
|
||||
if len(fld) < 6:
|
||||
continue
|
||||
sym = line.split("=", 1)[0].strip().lstrip("v_")
|
||||
oc = code_map.get(sym)
|
||||
if not oc:
|
||||
continue
|
||||
p = float(fld[3]) if fld[3] else 0
|
||||
c = fld[32] if len(fld) > 32 else "0"
|
||||
results[oc] = (p, c)
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
return results
|
||||
return {}
|
||||
|
||||
|
||||
def main():
|
||||
@@ -103,6 +72,49 @@ def main():
|
||||
# 只保留有买入区的条目,排除已关闭的(inactive/closed)
|
||||
EXCLUDED_STATUSES = ("closed", "inactive")
|
||||
to_check = [d for d in decisions_list if (d.get("entry_low") is not None or d.get("entry_high") is not None) and d.get("status") not in EXCLUDED_STATUSES]
|
||||
|
||||
# ----- 合并 DB watchlist_stocks 自选股 -----
|
||||
try:
|
||||
import sqlite3
|
||||
db = sqlite3.connect('/home/hmo/MoFin/data/mofin.db')
|
||||
db.row_factory = sqlite3.Row
|
||||
wl_rows = db.execute(
|
||||
"SELECT code, name, price, entry_low, entry_high, stop_loss, analysis_json "
|
||||
"FROM watchlist_stocks WHERE is_active=1 AND entry_low IS NOT NULL AND entry_high IS NOT NULL"
|
||||
).fetchall()
|
||||
db.close()
|
||||
existing_codes = {d["code"] for d in to_check}
|
||||
for row in wl_rows:
|
||||
code = str(row["code"])
|
||||
if code in existing_codes:
|
||||
continue
|
||||
entry_low = row["entry_low"]
|
||||
entry_high = row["entry_high"]
|
||||
if not entry_low or not entry_high or entry_low <= 0:
|
||||
continue
|
||||
analysis = {}
|
||||
aj = row["analysis_json"]
|
||||
if aj:
|
||||
try:
|
||||
analysis = json.loads(aj)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
action = analysis.get("action", "") if isinstance(analysis, dict) else ""
|
||||
timing_signal = analysis.get("timing_signal", "买入") if isinstance(analysis, dict) else "买入"
|
||||
wl_entry = {
|
||||
"code": code,
|
||||
"name": row["name"] or code,
|
||||
"entry_low": entry_low,
|
||||
"entry_high": entry_high,
|
||||
"stop_loss": row["stop_loss"],
|
||||
"type": "自选策略",
|
||||
"action": action,
|
||||
"timing_signal": timing_signal,
|
||||
}
|
||||
to_check.append(wl_entry)
|
||||
except Exception as e:
|
||||
print(f"[WATCHLIST_MERGE FAIL] {e}", file=sys.stderr)
|
||||
|
||||
if not to_check:
|
||||
print("[SILENT] 无需要检查的策略")
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user