Files
MoFin/deploy/profile-scripts/health_monitor_daily.py
T

88 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""health_monitor_daily.py — 策略健康度每日监控(数据驱动:跟随 strategy_weights.json 激活集合)
背景(2026-08-12 事项四:健康监控注册 p_oversold):
evolution/health_monitor.py 能算策略健康度(实盘近7天浮盈 vs 回测基线5y 偏差 + 写 strategy_health 表 + 告警),
但**不在 cron**——策略健康没有自动写。本脚本每天定时跑,对当前策略(v_weak 实盘 + v_oversold 新策略)
分别做健康检查,写 strategy_health 表(供进化模块 dashboard 展示健康度趋势)。
输出:strategy_health 表(strategy_version/date/live_trades/live_wins/live_return_pct/backtest_wr/backtest_avg_ret/deviation/health_score
调度:每日收盘后(45 16 * * 1-5,实盘当日浮盈定型后)
规范:单例守卫(5.3) + 各策略独立健康分(backtest 基线用各自回测 5y
"""
import sys, os, sqlite3, fcntl
from pathlib import Path
from datetime import datetime
sys.path.insert(0, "/home/hmo/MoFin")
sys.path.insert(0, "/home/hmo/MoFin/evolution")
sys.path.insert(0, "/home/hmo/MoFin/deploy/profile-scripts")
def _singleton_guard(tag="health_monitor_daily.py"):
lock_dir = Path("/tmp/mofin_locks")
lock_dir.mkdir(exist_ok=True)
try:
fd = os.open(str(lock_dir / f"{tag}.lock"), os.O_CREAT | os.O_RDWR)
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
return fd
except OSError:
print(f"[{tag}] 已有实例在运行,退出", flush=True)
sys.exit(0)
def _load_active_strategies():
"""从 strategy_weights.json 读当前激活策略(A股 active + 港股 markets.hk.active)。
2026-08-15 数据驱动改造:原硬编码 (v_weak, v_oversold),温区切换后激活策略变化
但监控集合不跟随,导致激活策略无健康度数据。改为读路由输出,兜底旧二元组。
"""
import json as _json
try:
d = _json.loads(Path("/home/hmo/MoFin/data/strategy_weights.json").read_text(encoding="utf-8"))
active = list(d.get("active") or [])
active += list(((d.get("markets") or {}).get("hk") or {}).get("active") or [])
seen, out = set(), []
for v in active:
if v and v not in seen:
seen.add(v)
out.append(v)
if out:
return out
except Exception as e:
print(f" [warn] 读 strategy_weights.json 失败({e}),兜底 v_weak/v_oversold", flush=True)
return ["v_weak", "v_oversold"]
def main():
_fd = _singleton_guard()
print(f"[health_monitor_daily] {datetime.now().strftime('%H:%M:%S')} 策略健康度监控开始", flush=True)
try:
from evolution.health_monitor import run_health_check
except Exception:
# evolution 包导入兜底(直接按路径加载)
import importlib.util as _ilu
_spec = _ilu.spec_from_file_location("health_monitor", "/home/hmo/MoFin/evolution/health_monitor.py")
_m = _ilu.module_from_spec(_spec)
_spec.loader.exec_module(_m)
run_health_check = _m.run_health_check
# 数据驱动:监控集合 = 路由激活策略(A股+港股),随温区切换自动跟随
versions = _load_active_strategies()
print(f" 监控策略集合: {versions}", flush=True)
results = {}
for version in versions:
try:
r = run_health_check(strategy_version=version)
results[version] = r
if r and r.get("alert"):
print(f" ⚠️ {version}: {r['alert']}", flush=True)
except Exception as e:
print(f" ❌ {version} 健康检查失败: {e}", flush=True)
ok = sum(1 for r in results.values() if r)
print(f"[health_monitor_daily] 完成: {ok}/{len(results)} 策略健康分已写入 strategy_health", flush=True)
if __name__ == "__main__":
main()