# binance_anomaly_detector **Repository Path**: chobit/binance_anomaly_detector ## Basic Information - **Project Name**: binance_anomaly_detector - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-15 - **Last Updated**: 2026-07-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Binance USDT-M 全量合约异动监控 实时检测币安 U 本位永续合约全市场异动信号,覆盖 250+ 交易对,支持多渠道告警推送。 --- ## 项目概述与目的 币安 U 本位合约市场拥有 250+ 个永续交易对,价格波动剧烈、异动频发。传统逐个盯盘的方式效率极低,且容易遗漏关键信号。本项目旨在: - **全量覆盖**:同时监控所有 U 本位永续合约,不遗漏任何交易对的异动 - **实时检测**:基于 WebSocket 推流 + REST 轮询,检测延迟控制在秒级 - **多维度异动**:六大检测维度(暴力拉升/砸盘、高低点反转、60日突破、持仓异动、成交放量、BTC 金叉/死叉),覆盖价格、成交、持仓、趋势四大层面 - **智能告警**:自带冷却去重机制,防止同一信号反复刷屏;支持企业微信、钉钉、Telegram 三种推送渠道 --- ## 功能模块说明 ### 六大异动检测 | # | 检测项 | 触发条件 | 数据源 | 检测频率 | |---|--------|----------|--------|----------| | 1 | 暴力拉升/砸盘 | 1H 涨跌幅 ≥ 5% | WS `@kline_1h` | 实时(每 1~2 秒推一次) | | 2 | 高低点反转 | 触及 24H 极值后反转 ≥ 2% | WS `!ticker@arr` | 实时(每秒全量推送) | | 3 | 60 日突破 | 价格创 60 日新高/新低 | WS `@kline_1h` + REST 历史 K 线 | 实时 | | 4 | 持仓异动 | 1H 持仓量变化 ≥ 5% | REST `/fapi/v1/openInterest` 轮询 | 每 10 分钟 | | 5 | 成交放量 | 1H 成交额占 24H 总量 ≥ 30% | WS `@kline_1h` + `!ticker@arr` | K 线收盘时 | | 6 | BTC 金叉/死叉 | EMA25 与 EMA99 交叉(日线 & 4H) | REST 历史 K 线 + WS `@kline_4h` | K 线收盘时 | ### 检测逻辑详解 #### 1. 暴力拉升/砸盘 (`check_surge_dump`) - **公式**:`change_pct = (当前价 - 开盘价) / 开盘价` - **阈值**:`|change_pct| ≥ 0.05`(5%) - **分类**:正数为暴力拉升(SURGE),负数为砸盘(DUMP) - **盘中 vs 收盘**:WebSocket 推送的 K 线有 `x` 字段标识是否收盘。盘中触发为"实时预警",收盘触发为"收盘确认"。两种都检测,用标记区分 - **冷却**:同一交易对的同一告警类型,5 分钟内不重复推送 #### 2. 高低点反转 (`check_reversal`) - **阶段一(触及极值)**:当价格在 24H 最高/最低价的 0.15% 范围内时,标记为"触及极值" - **阶段二(反转确认)**:触及后,从触及价反转幅度 ≥ 2% 时触发告警 - **重置**:告警后自动重置触及标记,等待下一轮触及→反转循环 - **高点**:`REVERSAL_HIGH`(触及高点后下跌 ≥ 2%) - **低点**:`REVERSAL_LOW`(触及低点后反弹 ≥ 2%) #### 3. 60 日突破 (`check_breakout`) - **启动预热**:从 REST API 加载 60 日日线 K 线,计算 `daily_high_60d` 和 `daily_low_60d` - **实时检测**:当前 1H K 线价格突破 60 日极值时触发 - **防重复**:突破后自动更新基准(`daily_high_60d = price`),避免同一突破反复告警 #### 4. 持仓异动 (`check_oi_change`) - **时间序列**:每 10 分钟记录一个 OI 快照,保留 6 个快照 ≈ 1 小时 - **对比**:当前持仓量 vs 1 小时前(最早快照)的变化幅度 - **阈值**:`|变化幅度| ≥ 5%` - **分类**:正数为持仓激增,负数为持仓骤减 #### 5. 成交放量 (`check_volume_surge`) - **公式**:`ratio = 1H成交额 / 24H总成交额` - **阈值**:`ratio ≥ 30%` - **触发时机**:仅在 1H K 线收盘时触发,避免盘中反复告警 - **防重复**:记录已告警的 K 线开盘时间,同一根 K 线只告警一次 #### 6. BTC 金叉/死叉 (`check_btc_ema_cross`) - **指标**:EMA(25)(快线)vs EMA(99)(慢线) - **时间维度**:日线(1d)和 4H 线双重检测 - **金叉**:上一根 EMA25 ≤ EMA99,当前根 EMA25 > EMA99 → 趋势转多 - **死叉**:上一根 EMA25 ≥ EMA99,当前根 EMA25 < EMA99 → 趋势转空 - **触发时机**: - 日线:BTC 1H K 线收盘时检测一次(频率足够,日线金叉不会在一根 K 线内反复切换) - 4H 线:BTC 4H K 纯收盘时检测(专用 WS 连接订阅 `btcusdt@kline_4h`) - **预热**:启动时加载 BTC 120 根 4H 历史收盘价和 65 根日线历史 --- ## 架构设计 项目采用三条数据通道并行架构: ``` ┌─────────────────────────────────────────────────────────┐ │ main.py (主程序) │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │ │ │ 通道 A │ │ 通道 B │ │ 通道 C │ │ BTC 4H 专用 │ │ │ │ kline_1h │ │ !ticker │ │ OI 轮询 │ │ @kline_4h │ │ │ │ WS 分片 │ │ @arr WS │ │ REST │ │ WS 连接 │ │ │ └─────────┘ └─────────┘ └─────────┘ └──────────────┘ │ │ │ │ │ │ │ │ └───────────┴───────────┴────────────┘ │ │ │ │ │ StateManager (内存状态) │ │ │ │ │ DetectorEngine (6大检测器) │ │ │ │ │ Notifier (告警推送 + 冷却去重) │ │ ┌───────┴───────┴───────┐ │ │ console wechat dingtalk telegram │ └─────────────────────────────────────────────────────────┘ ``` ### 数据通道说明 | 通道 | 协议 | 数据内容 | 连接数 | 覆盖范围 | |------|------|----------|--------|----------| | A | WebSocket | `@kline_1h` | 1(250+ stream,上限 1024) | 全量交易对 | | B | WebSocket | `!ticker@arr` | 1(单条推送覆盖全部) | 全量交易对 | | C | REST | `/fapi/v1/openInterest` | 10 并发/批 | 全量交易对 | | BTC 4H | WebSocket | `btcusdt@kline_4h` | 1 | 仅 BTCUSDT | ### 关键设计决策 1. **WebSocket 分流路径**:币安 WS 有分流路由,`@kline` 和 `@ticker` 属 Market 类数据,URL 必须加 `/market/` 前缀(`/market/stream`、`/market/ws`),否则静默无数据推送 2. **24 小时连接寿命**:币安 WS 连接最大存活 24 小时,到期服务端主动断开。项目在 23 小时处主动重连,留 1 小时余量 3. **代理环境兼容**: - 设置 `PROXY=127.0.0.1:11304` 使 REST 和 WS 连接统一走代理(自动补全 `http://` 前缀) - 代理环境下 `fstream.binance.com` WS 握手成功但可能静默无数据,设置 `WS_USE_DEMO=1` 切换到 `demo-fstream.binance.com` 4. **OI 时间序列**:持仓量无 WS 推送,用 REST 每 10 分钟轮询一次,记录快照到时间序列,6 个快照覆盖约 1 小时 --- ## 安装与配置步骤 ### 系统要求 - Python 3.10+(推荐 3.13) - 网络环境:能访问 `fapi.binance.com` 和 `fstream.binance.com`(或 `demo-fstream.binance.com`) - 无需币安 API Key(行情接口无需鉴权) ### 安装步骤 ```bash # 1. 克隆/下载项目 cd binance_anomaly_detector # 2. 创建虚拟环境(推荐) python -m venv venv # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 3. 安装依赖 pip install -r requirements.txt ``` ### 配置步骤 ```bash # 1. 复制环境配置模板 copy .env.example .env # Windows cp .env.example .env # Linux/Mac # 2. 编辑 .env 文件 ``` `.env` 配置项说明: | 配置项 | 默认值 | 说明 | |--------|--------|------| | `NOTIFY_CHANNEL` | `console` | 通知渠道:`console` / `wechat` / `dingtalk` / `telegram` | | `WEBHOOK_URL` | 空 | 企业微信/钉钉的 Webhook URL(对应渠道必填) | | `TG_BOT_TOKEN` | 空 | Telegram Bot Token(telegram 渠道必填) | | `TG_CHAT_ID` | 空 | Telegram Chat ID(telegram 渠道必填) | | `PROXY` | 空 | HTTP 代理地址,如 `127.0.0.1:11304`(不影响 WS 数据推送时无需设置) | | `WS_USE_DEMO` | `0` | 代理环境下 WS 静默无数据时设为 `1`,使用 demo-fstream.binance.com | | `LOG_LEVEL` | `INFO` | 日志级别:`DEBUG` / `INFO` / `WARNING` / `ERROR` | ### 通知渠道配置 #### 企业微信群机器人 1. 在企业微信群中添加机器人,获取 Webhook URL 2. `.env` 中设置 `NOTIFY_CHANNEL=wechat` 和 `WEBHOOK_URL=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx` #### 钉钉群机器人 1. 在钉钉群中添加自定义机器人,获取 Webhook URL 2. `.env` 中设置 `NOTIFY_CHANNEL=dingtalk` 和 `WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=xxx` #### Telegram Bot 1. 通过 [@BotFather](https://t.me/BotFather) 创建 Bot,获取 Token 2. 获取 Chat ID(可向 Bot 发消息后调用 `getUpdates` 接口查看) 3. `.env` 中设置 `NOTIFY_CHANNEL=telegram`、`TG_BOT_TOKEN=xxx`、`TG_CHAT_ID=xxx` --- ## 使用方法与操作指南 ### 启动监控 ```bash # 方式一:命令行启动 python main.py # 方式二:Windows 双击启动 run.bat ``` ### 启动流程 启动时程序会依次执行: 1. **获取交易对列表**:调用 `/fapi/v1/exchangeInfo`,过滤出所有 U 本位永续合约(约 250+) 2. **预热历史数据**: - 为每个交易对加载 60 日日线 K 线(并发限制 5,用于突破检测) - 加载 BTC 120 根 4H 历史收盘价(用于 EMA 4H 交叉检测) 3. **启动数据通道**: - WS 通道 A:连接 kline_1h 流 - WS 通道 B:连接 !ticker@arr 流 - WS BTC 4H 专用连接 - REST 通道 C:启动 OI 轮询循环 - 交易对刷新循环(每 6 小时检查新上线/下线合约) 4. **实时监控**:所有通道就绪后,检测引擎开始响应推送数据 ### 退出 ```bash # Ctrl+C 或 kill 信号触发优雅退出: # 1. 关闭所有 WS 连接 # 2. 关闭 HTTP Session # 3. 取消后台任务 # 4. 程序退出 ``` ### 告警输出格式 控制台输出示例: ``` 2026-07-15 10:30:00 | notifier | WARNING | 🔔 BTCUSDT | 暴力拉升 +6.00% [实时预警] 开盘 50000 -> 当前 53000 | 1H最高 53500 最低 49800 2026-07-15 10:35:00 | notifier | WARNING | 🔔 ETHUSDT | 高点反转 -2.04% 24H高点 3800 -> 触及价 3795 -> 当前 3715 ``` ### 告警类型一览 | 告警类型 | alert_type | 说明 | |----------|-----------|------| | 暴力拉升 | `SURGE` | 1H 涨幅 ≥ 5% | | 砸盘 | `DUMP` | 1H 跌幅 ≥ 5% | | 高点反转 | `REVERSAL_HIGH` | 触及 24H 高点后下跌 ≥ 2% | | 低点反弹 | `REVERSAL_LOW` | 触及 24H 低点后反弹 ≥ 2% | | 60日新高 | `BREAKOUT_HIGH` | 突破 60 日最高价 | | 60日新低 | `BREAKOUT_LOW` | 跌破 60 日最低价 | | 持仓激增 | `OI_CHANGE` (+) | 1H 持仓量增加 ≥ 5% | | 持仓骤减 | `OI_CHANGE` (-) | 1H 持仓量减少 ≥ 5% | | 成交放量 | `VOLUME_SURGE` | 1H 成交额占 24H ≥ 30% | | 金叉 | `GOLDEN_CROSS` | EMA25 上穿 EMA99 | | 死叉 | `DEATH_CROSS` | EMA25 下穿 EMA99 | --- ## 目录结构说明 ``` binance_anomaly_detector/ ├── main.py # 主程序入口 │ ├── 启动流程协调 │ ├── 预热加载(60d klines + BTC 4H history) │ ├── OI 轮询循环 │ ├── 交易对刷新循环 │ ├── BTC 4H 专用 WS 连接 │ └── 信号处理 & 优雅退出 │ ├── config.py # 配置常量 │ ├── API 端点 & WS URL(含代理环境切换) │ ├── 六大检测阈值 │ ├── 告警冷却时间 │ ├── 轮询间隔 & 批次大小 │ ├── 通知渠道 & 环境变量 │ ├── get_proxy() 统一代理格式化 │ └── .env 文件加载(python-dotenv) │ ├── binance_client.py # REST API 客户端 │ ├── fetch_usdt_perpetual_symbols() # 获取全部 U 本位永续交易对 │ ├── fetch_klines() # 拉取历史 K 线(1d/4h) │ └── fetch_open_interest() # 查询持仓量 │ ├── state.py # 内存状态管理 │ ├── SymbolState # 单个交易对的全部实时状态(dataclass) │ │ ├── kline_1h_* # 1H K 线字段(开盘/收盘/高低/成交额/是否收盘) │ │ ├── ticker_24h_* # 24H 统计字段(高低/成交额/涨跌幅/开盘价) │ │ ├── oi_* # 持仓量字段 │ │ ├── daily_* # 60 日历史字段 │ │ ├── touched_* # 反转追踪字段 │ │ └── kline_4h_* # BTC 4H K 线字段 │ ├── StateManager # 全局状态管理器 │ │ ├── init_symbols() │ │ ├── get() / get_all_symbols() │ │ └── remove_delisted() │ ├── ws_manager.py # WebSocket 连接管理器 │ ├── WsManager │ │ ├── start() # 启动 kline + ticker 两条 WS 通道 │ │ ├── stop() # 关闭所有连接 │ │ ├── _run_kline_connection() # 通道 A: kline_1h 流(24h 定时重连) │ │ └── _run_ticker_connection() # 通道 B: !ticker@arr 流(24h 定时重连) │ ├── detectors.py # 六大异动检测引擎 │ ├── DetectorEngine │ │ ├── check_surge_dump() # 1. 暴力拉升/砸盘 │ │ ├── check_reversal() # 2. 高低点反转 │ │ ├── check_breakout() # 3. 60 日突破 │ │ ├── check_oi_change() # 4. 持仓异动 │ │ ├── check_volume_surge() # 5. 成交放量 │ │ ├── check_btc_ema_cross() # 6. BTC 金叉/死叉(日线 & 4H) │ │ ├── record_oi_snapshot() # OI 时间序列管理 │ │ └── update_btc_4h_close() # BTC 4H 收盘价缓存 │ ├── indicators.py # EMA 计算与交叉检测 │ ├── calculate_ema() # EMA(period) 计算 │ ├── detect_ema_cross() # 金叉/死叉判定 │ ├── notifier.py # 统一告警通知器 │ ├── Notifier │ │ ├── send() # 统一发送入口(含冷却去重) │ │ ├── can_send() # 冷却检查 │ │ ├── _send_wechat() # 企业微信 Webhook │ │ ├── _send_dingtalk() # 钉钉 Webhook │ │ ├── _send_telegram() # Telegram Bot API │ │ └── close() # 关闭 HTTP Session │ ├── test_core.py # 核心逻辑单元测试 │ ├── test_ema() # EMA 计算正确性 │ ├── test_ema_cross() # 金叉/死叉检测 │ ├── test_surge_dump() # 暴力拉升/砸盘 │ ├── test_reversal() # 高低点反转 │ ├── test_oi_change() # 持仓异动 │ ├── test_volume_surge() # 成交放量 │ └── test_breakout() # 60 日突破 │ ├── requirements.txt # 依赖清单 ├── .env.example # 环境配置模板 ├── run.bat # Windows 启动脚本 └── README.md # 本文档 ``` --- ## 依赖项列表 | 包名 | 最低版本 | 用途 | |------|----------|------| | `websockets` | ≥ 12.0 | WebSocket 客户端,连接币安实时推送流 | | `aiohttp` | ≥ 3.9 | 异步 HTTP 客户端,调用币安 REST API + 发送 Webhook 通知 | | `python-dotenv` | ≥ 1.0.0 | 从 `.env` 文件加载环境变量 | ### Python 标准库依赖 - `asyncio` — 异步事件循环 - `json` — WebSocket 消息解析 - `time` — 冷却计时 & 时间戳 - `logging` — 日志输出 - `signal` — 优雅退出信号处理 - `dataclasses` — SymbolState 数据结构 - `typing` — 类型标注 --- ## 检测阈值配置 所有阈值在 `config.py` 的 `THRESHOLDS` 字典中集中定义,可按需调整: | 阈值键 | 默认值 | 说明 | |--------|--------|------| | `price_change_1h` | `0.05` | 暴力拉升/砸盘触发阈值(5%) | | `reversal_24h` | `0.02` | 高低点反转幅度阈值(2%) | | `touch_threshold` | `0.0015` | 触及极值判定距离(0.15%) | | `breakout_days` | `60` | 突破检测回溯天数 | | `oi_change_1h` | `0.05` | 持仓异动阈值(5%) | | `volume_ratio_1h` | `0.30` | 成交放量占比阈值(30%) | | `ema_fast` | `25` | EMA 快线周期 | | `ema_slow` | `99` | EMA 慢线周期 | 其他关键配置: | 配置项 | 默认值 | 说明 | |--------|--------|------| | `ALERT_COOLDOWN` | `300` | 告警冷却时间(秒),同一信号 5 分钟内不重复 | | `OI_POLL_INTERVAL` | `60` | 持仓量轮询间隔(秒) | | `OI_BATCH_SIZE` | `10` | 持仓量并发请求批次大小 | | `SYMBOL_REFRESH_INTERVAL` | `21600` | 交易对列表刷新间隔(6 小时) | | `WS_MAX_LIFETIME` | `82800` | WS 连接最大存活时间(23 小时) | | `WS_PING_INTERVAL` | `20` | WS 心跳间隔(秒) | | `WS_RECONNECT_DELAY` | `5` | WS 断线重连等待(秒) | --- ## 常见问题解答(FAQ) ### Q1: 启动后 WS 连接成功但没有数据推送? **A:** 这通常是因为代理/网络环境问题。币安文档附录 A 提到:代理环境下 `fstream.binance.com` 的 WS 握手可能成功但静默无数据。解决方案: ```bash # 在 .env 中设置: WS_USE_DEMO=1 ``` 这会切换到 `demo-fstream.binance.com`,该域名在代理环境下正常推送数据。 如果是因网络限制需要在代理后运行,可按以下步骤配置: ```bash # 1. 在 .env 中设置代理地址(REST 和 WS 共用) PROXY=127.0.0.1:11304 # 2. 如果 WS 仍无数据,再开启 demo 模式 WS_USE_DEMO=1 ``` `PROXY` 会自动补全 `http://` 前缀(支持 `127.0.0.1:11304` 或 `http://127.0.0.1:11304` 两种写法),REST API(aiohttp)和 WebSocket(websockets)连接均通过同一代理。 ### Q2: WS URL 为什么用 `/market/stream` 而不是 `/stream`? **A:** 币安 WS 有分流路由系统(文档 7.1 节)。`@kline` 和 `@ticker` 属于 **Market 类**数据,必须使用 `/market/` 前缀路径: | 类型 | URL 路径 | |------|----------| | 合并流(Market 类) | `/market/stream?streams=...` | | 单流(Market 类) | `/market/ws/` | | 合并流(Public 类) | `/stream?streams=...` | | 单流(Public 类) | `/ws/` | 如果用 `/stream` 订阅 `@kline`,连接正常但永远收不到数据。 ### Q3: 为什么单连接能承载 250+ 交易对?不需要分片吗? **A:** 币安文档 7.5 节规定:单连接最大流数为 **1024**(不是 200)。250+ 交易对 × `@kline_1h` = 250 条 stream,远低于 1024 上限,一条连接就够了。 ### Q4: 持仓量为什么用 REST 轮询而不是 WebSocket? **A:** 币安 U 本位合约的持仓量(Open Interest)没有 WebSocket 实时推送接口,只能通过 REST API `/fapi/v1/openInterest` 查询。项目每 10 分钟记录一个快照,6 个快照覆盖约 1 小时。 ### Q5: 成交放量为什么只在 K 线收盘时触发? **A:** 盘中 1H K 线还在形成,成交额在持续增长。如果在盘中就判断"占比 ≥ 30%",后半段回落时可能是假信号。仅在收盘时触发确保数据完整性。如果你希望盘中也能预警,可在 `detectors.py` 中移除 `if not st.kline_1h_closed: return` 这一行。 ### Q6: BTC 金叉/死叉为什么只检测 BTCUSDT? **A:** EMA 交叉是趋势级别信号,对 BTC(市场风向标)最有意义。其他币种的 EMA 交叉噪音太多、参考价值有限。如果需要扩展到更多币种,可在 `main.py` 中为其他交易对也订阅 `@kline_4h` 流并调用 `check_btc_ema_cross`。 ### Q7: 如何调整检测阈值? **A:** 修改 `config.py` 中的 `THRESHOLDS` 字典。例如把暴力拉升阈值从 5% 降到 3%: ```python THRESHOLDS = { "price_change_1h": 0.03, # 从 0.05 改为 0.03 ... } ``` ### Q8: 启动预热时间太长怎么办? **A:** 预热需要为 250+ 交易对各加载 65 根日线 K 线,并发限制为 5。如果网络慢,可以在 `main.py` 中调高并发限制: ```python sem = asyncio.Semaphore(10) # 从 5 提高到 10 ``` 但这会增加 API 权重消耗,注意不要超过币安的 2400 权重/分钟限制。 ### Q9: 如何只监控特定交易对而不是全量? **A:** 修改 `main.py` 中的兜底列表: ```python symbols = ["BTCUSDT", "ETHUSDT", "SOLUSDT"] # 只监控这三个 state.init_symbols(symbols) # 删除 fetch_usdt_perpetual_symbols() 调用 ``` ### Q10: Ctrl+C 退出时数据会丢失吗? **A:** 不会。项目使用纯内存状态,退出时只关闭连接和取消任务,没有任何持久化写入。所有状态会在下次启动时重新预热加载。 --- ## 版本更新记录 ### v0.1.0 (2026-07-15) **初始版本,六大异动检测全量实现。** - 实现暴力拉升/砸盘检测(1H 涨跌幅 ≥ 5%) - 实现高低点反转检测(触及 24H 极值后反转 ≥ 2%) - 实现 60 日突破检测(价格创 60 日新高/新低) - 实现持仓异动检测(1H 持仓量变化 ≥ 5%) - 实成交放量检测(1H 成交额占 24H ≥ 30%) - 实现 BTC 金叉/死叉检测(日线 & 4H EMA25/EMA99) - WebSocket 三条数据通道(kline / ticker / BTC 4H) - REST 持仓量轮询(10 分钟快照,6 点覆盖 1 小时) - 通知渠道:控制台 / 企业微信 / 钉钉 / Telegram - 冷却去重机制(5 分钟冷却) - 24 小时定时重连(23 小时主动断开) - 交易对动态刷新(6 小时检测新上线/下线) - `.env` 配置支持(python-dotenv) - Windows 启动脚本(run.bat) - 核心逻辑单元测试(7 组全部通过) - 对照币安官方 API 文档修正 WebSocket 分流路径(`/market/` 前缀) - 代理环境兼容(`WS_USE_DEMO` 切换)