基于缠论(Chan Theory)与 XGBoost 的数字货币交易信号模型。
缠论检测到买卖点 → XGBoost 给这个买卖点打分 → 高分就发信号
模型不自己找买卖点,它只做一件事:判断 chan.py 找出来的买卖点靠不靠谱。
├── prepare_data.py # 从币安拉取历史 K 线
├── chan_analyzer.py # 缠论分析引擎(chan.py 封装)
├── feature_extractor.py # 61 维特征提取
├── nesting_validator.py # 区间套验证(V1 共振 / V2 真递归)
├── train.py # ★ 主训练脚本
├── validate_onnx.py # ONNX 一致性验证
├── visualize_features.py # 特征可视化
├── self_iterate.py # 自迭代重训
├── drift_detector.py # 漂移检测
├── signal_rules.py # 信号滤波规则(参考实现)
│
├── contract/
│ ├── signal_schema.json # 数据契约
│ └── mock_push_server.py # 模拟推送服务
│
├── lib/chan.py/ # 缠论库
│
├── data/
│ ├── processed/ # 清洗后的 CSV K 线
│ └── training/ # 训练特征缓存
│
├── models/
│ ├── model_{tf}.onnx # ★ 各周期 ONNX 模型
│ ├── model_{tf}_{seed}.onnx # Ensemble 子模型
│ ├── feature_meta_{tf}.json # 特征顺序
│ ├── norm_stats_{tf}.json # 标准化参数
│ ├── ensemble_meta_{tf}.json# Ensemble 元数据
│ └── archive/ # 历史版本归档
│
└── config.yaml # 所有配置
| 周期 | 样本量 | 单个 AUC-PR | Ensemble AUC-PR | 用途 |
|---|---|---|---|---|
| 5m | 9,610 | 0.811 | 0.895 | 短线主力(信号最多) |
| 15m | 2,740 | 0.736 | 0.938 | 中短线 |
| 1h | 1,614 | 0.681 | 0.944 | 中线(最稳健) |
| 4h | 122 | 0.697 | 0.866 | 中长线 |
| 1d | 22 | — | — | 样本太少,仅供参考 |
每个周期独立训练,互不依赖。
git clone https://github.com/vespa314/chan.py lib/chan.py
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# 依赖清单:numpy, pandas, xgboost, ccxt, onnxruntime,
# onnxmltools, optuna, scikit-learn, pyyamlchan.py 需要 Python 3.11+
# 拉取全部配置的币种 + 周期(默认 BTC/ETH/SOL/BNB/XRP)
python prepare_data.py
# 指定参数
python prepare_data.py --symbol BTCUSDT --timeframe 1h --start 2023-01-01# 全流程训练(所有周期)
python train.py
# 只训练特定周期
python train.py --timeframes 1h
# 指定币种
python train.py --symbols BTCUSDT
# 跳过 Optuna 调参(快速验证)
python train.py --no-tune训练产出:
models/
├── model_1h.onnx # XGBoost → ONNX
├── model_1h_7.onnx # Ensemble 子模型 (×7)
├── feature_meta_1h.json # 61 维特征顺序
├── norm_stats_1h.json # 标准化参数
└── ensemble_meta_1h.json # Ensemble 集成信息
python validate_onnx.py
# → XGBoost vs ONNX 误差 < 1e-5 ✅flowchart LR
A[币安 API] -->|原始 K 线| B[prepare_data.py]
B -->|清洗后 CSV| C[chan_analyzer.py<br/>step_load 逐步回放]
C -->|BSP 快照| D[feature_extractor.py<br/>61 维特征]
C -->|全量 K 线| E[label_bsp_snapshots<br/>V2 标注]
D -->|特征矩阵| F[train_xgboost<br/>Walk-Forward + Optuna]
E -->|标签| F
F -->|XGBoost 模型| G[export_onnx<br/>→ ONNX]
F -->|XGBoost 模型| H[train_ensemble<br/>多种子投票]
H -->|7 个 ONNX| I[ensemble_meta.json]
python train.py
# 内部循环:
# for tf in [5m, 15m, 1h, 4h, 1d]:
# 对每个币种跑缠论分析
# 对每个 BSP 做区间套验证
# 提取 61 维特征
# 训练 XGBoost
# 导出 ONNX + Ensemble
# 记录版本- 窗口:3~24 根 K 线
- 阈值:自适应 ATR(高波动 2.0×,低波动 1.2×,默认 1.5×)
- 成本扣除:手续费 0.1% + 滑点 0.05%
- 反向截断:窗口内出现反向 BSP 立即标为失败
- 正例率:~58%(扣除成本后)
大级别 K 线由小级别 K 线构成,不是"附近有没有":
4h K 线 12:00-16:00
└── 1h K 线 [12:00, 13:00, 14:00, 15:00]
4h 出买点 → 只查这 4 根 1h K 线内部有没有 1h 买点
→ 不查 11:00(不构成这根 4h K 线)
在 train.py 开头改 import:
# V1:共振式(时间窗口匹配)
from nesting_validator import IntervalNestingValidator
# V2:真递归(K 线构成关系,推荐)
from nesting_validator import TrueIntervalNestingValidator as IntervalNestingValidator| 模型 | 次级别 | 构成比 |
|---|---|---|
| 1d | 4h | 6 根 4h = 1 根 1d |
| 4h | 1h | 4 根 1h = 1 根 4h |
| 1h | 15m | 4 根 15m = 1 根 1h |
| 15m | 5m | 3 根 5m = 1 根 15m |
| 5m | 1m | 5 根 1m = 1 根 5m |
| 类别 | 数量 | 来源 | 说明 |
|---|---|---|---|
| BSP one-hot | 12 | bsp_meta |
买卖点类型编码(1/1p/2/2s/3a/3b) |
| 技术指标 | 28 | tech |
价格动量、均线偏离、波动率、RSI、BOLL、MACD、成交量、趋势 |
| 缠论特征 | 19 | chan |
笔斜率、中枢宽度、线段方向、背驰率等 |
| 区间套 | 4 | chan |
区间套确认、置信度提升、方向一致性、微 BSP 计数 |
from feature_extractor import FeatureExtractor
fe = FeatureExtractor()
fe.feature_source() # → {"bi_slope": "chan", "rsi": "tech", ...}
fe.tech_feature_names() # → 28 个外部服务可自算的特征
fe.chan_feature_names() # → 23 个需 Python 推送的特征当外部服务(Go/Rust)承载推理时,Python 缠论侧车按此格式推送消息:
{
"symbol": "BTCUSDT",
"timeframe": "1h",
"bsp": {
"direction": "buy",
"types": ["1"],
"price": 67540.01,
"timestamp": "2026-06-19 10:00:00"
},
"recent_klines": [
{"timestamp": "2026-06-19 09:00", "open": 67420, "high": 67600, "low": 67380, "close": 67540, "volume": 123.4},
{"timestamp": "2026-06-19 10:00", "open": 67540, "high": 67710, "low": 67428, "close": 67655, "volume": 566.5}
],
"chan_features": {
"bi_slope": 0.0032,
"zs_count": 2,
"nesting_confirmed": 1
}
}Schema 定义:contract/signal_schema.json
外部服务在运行中收集 (特征向量, 实际结果) → 触发增量重训:
# 单次迭代
python self_iterate.py
# 持续监控(漂移检测 + 自动重训)
python self_iterate.py --watch
# 强制重训(忽略漂移检查)
python self_iterate.py --force
# 版本管理
python self_iterate.py --list
python self_iterate.py --rollback v20260619_084458| 检测 | 方法 | 阈值 |
|---|---|---|
| 预测分布偏移 | PSI | > 0.25 |
| 特征分布偏移 | Z-score | > 3σ |
| 信号性能衰减 | Rolling Sharpe | < 0.5 |
| 维度 | 值 |
|---|---|
| 训练数据 | 5 币种 × 3.5 年(2023-01 ~ 今) |
| 特征维度 | 61 |
| 1h Ensemble AUC-PR | 0.944 |
| 1h Ensemble AUC-ROC | 0.925 |
| 泛化差距(训练-测试) | 0.011 ✅ |
| ONNX 一致性误差 | < 1e-6 |
这个模型能直接喂原始订单吗? 不能。需先聚合为 K 线,再用 Python 侧车跑缠论检测 BSP,然后拼成 61 维特征向量送入 ONNX。
为什么不用深度学习端到端?
可以,那是一个独立的项目。当前 XGBoost 方案在 ~8000 样本下能达到 AUC 0.94,性价比远高于深度学习。参见 chan-distill 项目(另建)。
如何切换区间套 V1 / V2?
改 train.py 第一行的 import。V2(真递归)更符合缠论理论,V1(共振)更宽松。
各周期模型怎么用? 外部服务按需加载。5m 做短线信号主力,1h 做中长线确认。信号组合规则由外部服务实现。
Chan-XGB: 缠论 + XGBoost → 信号评分(当前项目)
chan.py 检测 BSP,XGBoost 评分
Chan-Distill: 将缠论蒸馏进 Transformer → 单模型推理(另建项目)
一个 ONNX 搞定全部,不需要外部缠论引擎