#!/usr/bin/env python3 # -*- coding: utf-8 -*- """regime_tracker.py — 温区平滑跟踪 + 周期记录(2026-08-13) 设计(老莫确认方向 + 数据选参): - 实时温区判定:滞回确认 K=5(连续5天同温区才确认,滞后约5天,宁慢勿错) 数据依据:K=5 → 112周期/平均20.7天/无1天噪音(vs 原始457周期/151个1天) - 温区周期记录:regime_cycles 表(start/end/regime/days),供策略评估归因 - 温度(rsi):不滞后,实时反映恐慌/亢奋(与温区互补:温区滞后、温度实时) 写表: regime_cycles(date_start, date_end, regime, days) 输出: market_regime_smoothed.json(当前平滑温区 + 温度) """ import sys import json import sqlite3 from pathlib import Path from datetime import datetime _SCRIPT_DIR = Path(__file__).resolve().parent sys.path.insert(0, str(_SCRIPT_DIR)) sys.path.insert(0, "/home/hmo/MoFin") DB = "/home/hmo/MoFin/data/mofin.db" OUT = "/home/hmo/MoFin/data/market_regime_smoothed.json" # 滞回确认天数(数据选参:K=5 甜区) CONFIRM_DAYS = 5 def load_daily_regime(): """读取 market_regime 逐日数据(时间正序)""" conn = sqlite3.connect(DB, timeout=5) rows = conn.execute( "SELECT date, above_ma20, adx, regime FROM market_regime ORDER BY date ASC" ).fetchall() conn.close() return rows def classify_day(above, adx): """单日温区(与 market_regime 同逻辑)""" if above == 1 and adx is not None and adx >= 20: return "trend_up" if adx is not None and adx < 20: return "choppy" return "trend_down" def smooth_states(rows, k=CONFIRM_DAYS): """滞回确认:连续 K 天同温区才确认切换。返回 (states, cycles)""" dates = [r[0] for r in rows] raw = [classify_day(r[1], r[2]) for r in rows] n = len(dates) # 状态机:current 确认态;每 K 天窗口看是否一致 states = [None] * n current = None for i in range(n): if i < k - 1: continue window = raw[i - k + 1:i + 1] if len(set(window)) == 1: # 连续 K 天同温区 → 确认(切换) current = window[0] states[i] = current if current is not None else raw[i] # 开头填补(前 K-1 天用原始值) for i in range(min(k - 1, n)): states[i] = raw[i] # 聚合周期 cycles = [] cur = None for i in range(n): s = states[i] if cur is None or s != cur["regime"]: if cur: cycles.append(cur) cur = {"regime": s, "start": dates[i], "end": dates[i], "days": 1} else: cur["end"] = dates[i] cur["days"] += 1 if cur: cycles.append(cur) return states, cycles, dates def save_cycles(cycles): """写入 regime_cycles 表""" conn = sqlite3.connect(DB, timeout=30) conn.execute("PRAGMA busy_timeout=30000") conn.execute(""" CREATE TABLE IF NOT EXISTS regime_cycles ( id INTEGER PRIMARY KEY AUTOINCREMENT, regime TEXT, start_date TEXT, end_date TEXT, days INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """) # 清空重建(保持与 market_regime 同步) conn.execute("DELETE FROM regime_cycles") for cy in cycles: conn.execute( "INSERT INTO regime_cycles (regime, start_date, end_date, days) VALUES (?,?,?,?)", (cy["regime"], cy["start"], cy["end"], cy["days"]) ) conn.commit() conn.close() return len(cycles) def get_temp(): """实时温度(rsi 档位,不滞后)""" try: from temp_band import get_market_temp return get_market_temp() except Exception: return {"band": "unknown", "rsi": None} def main(): rows = load_daily_regime() if len(rows) < CONFIRM_DAYS + 1: print(f"数据不足: {len(rows)} 条") return states, cycles, dates = smooth_states(rows) n_cycles = save_cycles(cycles) # 当前平滑温区(最新确认态) current_regime = states[-1] current_date = dates[-1] temp = get_temp() # 最近周期列表 recent = cycles[-8:] out = { "current_regime": current_regime, "current_date": current_date, "confirm_days": CONFIRM_DAYS, "temp": temp, "total_cycles": n_cycles, "recent_cycles": recent, "updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } Path(OUT).write_text(json.dumps(out, ensure_ascii=False, indent=1), encoding="utf-8") print(f"平滑温区: {current_regime} (确认期{CONFIRM_DAYS}天, 至{current_date})") print(f"温度: {temp.get('band')} (rsi={temp.get('rsi')})") print(f"周期总数: {n_cycles}") print("最近周期:") for cy in recent: print(f" {cy['regime']:<12} {cy['start']} ~ {cy['end']} ({cy['days']}天)") if __name__ == "__main__": main()