fix: system_audit/stale_push_wlin/refresh_mtf → DB, remove final JSON refs
This commit is contained in:
@@ -50,13 +50,9 @@ def main():
|
|||||||
|
|
||||||
log(f"Pre-populating multi-timeframe cache for {len(codes)} stocks...")
|
log(f"Pre-populating multi-timeframe cache for {len(codes)} stocks...")
|
||||||
|
|
||||||
# 检查当前缓存,只更新需要更新的
|
# 从 DB 读取现有缓存(替代 multi_tf_cache.json)
|
||||||
mtf_cache_path = "/home/hmo/web-dashboard/data/multi_tf_cache.json"
|
from multi_timeframe import _load_mtf_cache, _save_mtf_cache
|
||||||
try:
|
existing = _load_mtf_cache()
|
||||||
with open(mtf_cache_path) as f:
|
|
||||||
existing = json.load(f)
|
|
||||||
except (FileNotFoundError, json.JSONDecodeError):
|
|
||||||
existing = {}
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from multi_timeframe import full_multi_tf_analysis
|
from multi_timeframe import full_multi_tf_analysis
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import re
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
from mo_data import read_portfolio, read_decisions
|
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from mo_data import read_portfolio, read_decisions
|
||||||
|
|
||||||
# ── MoFin unified model ──────────────────────────────────────────────
|
# ── MoFin unified model ──────────────────────────────────────────────
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
@@ -225,11 +225,14 @@ def trigger_regen_sync(stock_codes=None):
|
|||||||
|
|
||||||
|
|
||||||
def load_cash():
|
def load_cash():
|
||||||
"""从 mo_data 实时读可用现金"""
|
"""从 portfolio.json 实时读可用现金(可用 ≈ 实时买力),不硬编码"""
|
||||||
try:
|
try:
|
||||||
pf = read_portfolio()
|
data = read_portfolio()
|
||||||
if isinstance(pf, dict):
|
if isinstance(data, dict):
|
||||||
return pf.get("cash_available", pf.get("cash", 0))
|
# 先读 cash_available(拆分了可用/冻结),fallback 到 cash
|
||||||
|
return data.get("cash_available", data.get("cash", 0))
|
||||||
|
if isinstance(data, list) and len(data) > 1 and isinstance(data[1], dict):
|
||||||
|
return data[1].get("cash_available", data[1].get("cash", 0))
|
||||||
return 0
|
return 0
|
||||||
except Exception:
|
except Exception:
|
||||||
return 0
|
return 0
|
||||||
@@ -332,7 +335,7 @@ def main():
|
|||||||
cooldown = load_cooldown()
|
cooldown = load_cooldown()
|
||||||
now_ts = datetime.now().timestamp()
|
now_ts = datetime.now().timestamp()
|
||||||
|
|
||||||
# 读 decisions 获取完整策略数据
|
# 读 decisions.json 获取完整策略数据
|
||||||
code_data = {}
|
code_data = {}
|
||||||
try:
|
try:
|
||||||
dec = read_decisions()
|
dec = read_decisions()
|
||||||
@@ -388,7 +391,7 @@ def main():
|
|||||||
to_reassess = list(set(s[1] for s in stocks) | set(s[1] for s in stale_list))
|
to_reassess = list(set(s[1] for s in stocks) | set(s[1] for s in stale_list))
|
||||||
if to_reassess:
|
if to_reassess:
|
||||||
trigger_regen_sync(to_reassess)
|
trigger_regen_sync(to_reassess)
|
||||||
# 重评完成,re-read decisions 获取最新策略
|
# 重评完成,re-read decisions.json 获取最新策略
|
||||||
code_data = {}
|
code_data = {}
|
||||||
try:
|
try:
|
||||||
dec = read_decisions()
|
dec = read_decisions()
|
||||||
@@ -474,8 +477,8 @@ def main():
|
|||||||
# 加载基本面缓存(PE等)
|
# 加载基本面缓存(PE等)
|
||||||
fund_cache = {}
|
fund_cache = {}
|
||||||
try:
|
try:
|
||||||
with open("/home/hmo/web-dashboard/data/multi_tf_cache.json") as f:
|
import multi_timeframe as mtf_mod
|
||||||
mtf = json.load(f)
|
mtf = mtf_mod._load_mtf_cache()
|
||||||
for code, v in mtf.items():
|
for code, v in mtf.items():
|
||||||
fund_cache[code] = v.get("fundamentals", {})
|
fund_cache[code] = v.get("fundamentals", {})
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|||||||
+5
-13
@@ -18,6 +18,7 @@
|
|||||||
import json, sqlite3, subprocess, sys, time
|
import json, sqlite3, subprocess, sys, time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from mo_data import read_portfolio, read_decisions, read_watchlist
|
||||||
|
|
||||||
DATA_DIR = Path("/home/hmo/MoFin/data")
|
DATA_DIR = Path("/home/hmo/MoFin/data")
|
||||||
WEB_DATA = Path("/home/hmo/web-dashboard/data")
|
WEB_DATA = Path("/home/hmo/web-dashboard/data")
|
||||||
@@ -53,7 +54,7 @@ def audit_signals(conn):
|
|||||||
def audit_stocks(conn):
|
def audit_stocks(conn):
|
||||||
# 关注列表
|
# 关注列表
|
||||||
try:
|
try:
|
||||||
wl = json.loads((WEB_DATA / "watchlist.json").read_text())
|
wl = read_watchlist()
|
||||||
watching = [s for s in wl.get("stocks", []) if s.get("status") == "watching"]
|
watching = [s for s in wl.get("stocks", []) if s.get("status") == "watching"]
|
||||||
formal = [s for s in wl.get("stocks", []) if s.get("status") != "watching"]
|
formal = [s for s in wl.get("stocks", []) if s.get("status") != "watching"]
|
||||||
log_ok("股票池", f"正式自选{len(formal)}只, 关注列表{len(watching)}只")
|
log_ok("股票池", f"正式自选{len(formal)}只, 关注列表{len(watching)}只")
|
||||||
@@ -70,7 +71,7 @@ def audit_stocks(conn):
|
|||||||
# ── 3. 策略状态审计 ──
|
# ── 3. 策略状态审计 ──
|
||||||
def audit_strategies(conn):
|
def audit_strategies(conn):
|
||||||
try:
|
try:
|
||||||
dec = json.loads((WEB_DATA / "decisions.json").read_text())
|
dec = read_decisions()
|
||||||
active = [d for d in dec.get("decisions", []) if d.get("status") in ("active", "updated")]
|
active = [d for d in dec.get("decisions", []) if d.get("status") in ("active", "updated")]
|
||||||
stale_count = 0
|
stale_count = 0
|
||||||
no_stop = 0
|
no_stop = 0
|
||||||
@@ -99,7 +100,7 @@ def audit_strategies(conn):
|
|||||||
# ── 4. 建议闭环审计 ──
|
# ── 4. 建议闭环审计 ──
|
||||||
def audit_advice(conn):
|
def audit_advice(conn):
|
||||||
try:
|
try:
|
||||||
dec = json.loads((WEB_DATA / "decisions.json").read_text())
|
dec = read_decisions()
|
||||||
pending = 0
|
pending = 0
|
||||||
for d in dec.get("decisions", []):
|
for d in dec.get("decisions", []):
|
||||||
for a in d.get("advice_timeline", []):
|
for a in d.get("advice_timeline", []):
|
||||||
@@ -116,19 +117,10 @@ def audit_advice(conn):
|
|||||||
# ── 5. 组合健康 ──
|
# ── 5. 组合健康 ──
|
||||||
def audit_portfolio(conn):
|
def audit_portfolio(conn):
|
||||||
try:
|
try:
|
||||||
# 优先从 portfolio.json 读总仓位(更准确,基于实际市值/总资产)
|
pj = read_portfolio()
|
||||||
pj_path = WEB_DATA / "portfolio.json"
|
|
||||||
if not pj_path.exists():
|
|
||||||
pj_path = DATA_DIR / "portfolio.json"
|
|
||||||
if pj_path.exists():
|
|
||||||
pj = json.loads(pj_path.read_text())
|
|
||||||
pos = pj.get("position_pct", 0)
|
pos = pj.get("position_pct", 0)
|
||||||
cash = pj.get("cash", 0)
|
cash = pj.get("cash", 0)
|
||||||
available = pj.get("available_cash", cash)
|
available = pj.get("available_cash", cash)
|
||||||
else:
|
|
||||||
# 兜底:SQLite position_pct 之和
|
|
||||||
pos = conn.execute("SELECT SUM(position_pct) FROM holdings WHERE is_active=1").fetchone()[0] or 0
|
|
||||||
available = 0
|
|
||||||
|
|
||||||
log_ok("组合", f"总仓位{pos:.1f}%")
|
log_ok("组合", f"总仓位{pos:.1f}%")
|
||||||
if pos > 90:
|
if pos > 90:
|
||||||
|
|||||||
Reference in New Issue
Block a user