ChanPivotMonitor: 实时中枢特征跟踪 + Telegram推送

- ChanPivotClassifier: 提取 calc_duration/contraction/shift 为 @staticmethod,新增 compute_features()
- ChanPivotMonitor: 实时追踪当前中枢,bi_count 增长时重新计算 shift/contraction/duration
- bsp_monitor/fetcher: 改用 data_provider HTTP API 替代直连 CCXT
- bsp_monitor/notify: 新增 send_telegram_message() 通用推送
- bsp_monitor/main: 集成 ChanPivotMonitor,有新笔或 BSP 时推送到 Telegram

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jackyu66git
2026-05-26 11:35:09 +08:00
co-authored by Claude Opus 4.7
parent 5ad761fad4
commit b1cbdca707
5 changed files with 300 additions and 40 deletions
+57 -1
View File
@@ -19,7 +19,12 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from fetcher import fetch_ohlcv
from engine import ChanEngine
from notify import send_bsp_alert, BOT_TOKEN, CHAT_ID
from notify import send_bsp_alert, send_telegram_message, BOT_TOKEN, CHAT_ID
_PARENT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _PARENT not in sys.path:
sys.path.insert(0, _PARENT)
from ChanPivotMonitor import ChanPivotMonitor
logging.basicConfig(
level=logging.INFO,
@@ -38,6 +43,7 @@ class BSPMonitor:
self._first_run = True
self._last_df_ts = None
self._known_bsp_keys: set = set() # 已见过的 BSP 键(含已推送和历史的)
self.pivot_monitor = ChanPivotMonitor(window_size=10)
async def tick(self):
"""单次 tick。"""
@@ -68,6 +74,56 @@ class BSPMonitor:
logger.error(f"缠论计算失败: {e}", exc_info=True)
return
# 2.5 更新中枢特征监控 + 推送
pivot_state = self.pivot_monitor.update(engine.bi_zs_list)
if pivot_state:
logger.info(
f"中枢特征更新: bi_count={pivot_state['bi_count']} "
f"is_sure={pivot_state['is_sure']} "
f"contraction={pivot_state['contraction']:.4f} "
f"shift_norm={pivot_state['shift_norm']:+.4f} "
f"duration_norm={pivot_state['duration_norm']:.4f}"
)
# Telegram 推送
if pivot_state["is_sure"]:
phase = "✅ 已确认"
elif pivot_state["bi_count"] > 3:
phase = "🔄 延伸中"
else:
phase = "🆕 刚形成"
zs_dir = pivot_state["zs_dir"]
dir_label = "⬆️ 向上" if "UP" in zs_dir else "⬇️ 向下"
# 白话解释
c = pivot_state["contraction"]
if c < 0.85:
contraction_note = "收敛(振幅缩小,可能快出方向)"
elif c > 1.15:
contraction_note = "扩张(振幅放大,波动加剧)"
else:
contraction_note = "稳定"
s = pivot_state["shift_norm"]
if s > 0.3:
shift_note = "重心上移(偏多)"
elif s < -0.3:
shift_note = "重心下移(偏空)"
else:
shift_note = "重心居中"
msg = (
f"🏠 <b>中枢更新</b> — BTC/USDT 1m\n"
f"\n"
f"📐 笔数: <b>{pivot_state['bi_count']}</b> {dir_label} {phase}\n"
f"📏 收敛率: <b>{pivot_state['contraction']:.4f}</b> → {contraction_note}\n"
f"⚖️ 重心漂移: <b>{pivot_state['shift_norm']:+.4f}</b> → {shift_note}\n"
f"⏱️ 持续: {pivot_state['duration_raw']}K "
f"(norm: {pivot_state['duration_norm']:.2f})\n"
f"📦 区间: {pivot_state['zd']:.2f} {pivot_state['zg']:.2f} "
f"(gg/dd: {pivot_state['gg']:.2f}/{pivot_state['dd']:.2f})"
)
send_telegram_message(msg)
# 3. 检测新 BSP(用 stable key 去重)
current_bsps = engine.bsp_list
current_keys = {_bsp_stable_key(b) for b in current_bsps}