# chanlun — 缠论技术分析 Rust 核心库 [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Rust](https://img.shields.io/badge/rust-1.85%2B-orange.svg)](https://www.rust-lang.org) [![edition](https://img.shields.io/badge/edition-2024-9cf.svg)](https://doc.rust-lang.org/edition-guide/rust-2024/) 基于[缠中说禅](https://zh.wikipedia.org/wiki/%E7%BC%A0%E4%B8%AD%E8%AF%B4%E7%A6%85)理论的量化技术分析核心库,将 Python 参考实现 (`chan.py`, ~4200行) 完整移植为 Rust,同时保持了 API 的完全兼容。 **约 13,700 行 Rust 代码**,39 个源文件,覆盖缠论的完整算法体系:K线包含处理、分型识别、笔划分、线段划分(含特征序列与缺口处理)、中枢识别(含延伸/扩展/多级中枢)、背驰检测(MACD/斜率/测度三种方式)、买卖点识别(18种类型)、多周期联立分析。 核心 crate 位于 `chanlun/` 目录。Python 绑定通过独立的 [`chanlun-py`](../chanlun-py/) crate 实现,使用 PyO3 将 Rust 核心封装为 Python 模块,API 与 `chan.py` 完全一致。所有类型名、方法名、字段名均使用中文标识符,与 Python 版本保持 1:1 对应。 --- ## 目录 - [核心概念](#核心概念) - [项目结构](#项目结构) - [快速开始](#快速开始) - [数据管线](#数据管线) - [核心类型详解](#核心类型详解) - [配置体系](#配置体系) - [算法模块](#算法模块) - [技术指标](#技术指标) - [线程安全与并发](#线程安全与并发) - [Python 绑定](#python-绑定) - [数据序列化](#数据序列化) - [测试](#测试) - [许可](#许可) --- ## 核心概念 缠论是一种源自中国的技术分析理论,将价格走势分解为层级结构,从最底层K线逐渐向上构造: ``` 原始K线 → 包含处理 → 缠论K线 → 顶底分型 → 笔 → 线段 → 中枢 → 买卖点 ``` 核心理念: - **走势终完美**:任何级别的任何走势类型终要完成 - **自同构性**:不同级别的走势呈现相同的形态结构,可通过递归分析进行多级别联立 - **完全分类**:将走势分为上涨、下跌、盘整三种,每个节点都可通过买卖点找到操作依据 --- ## 项目结构 ``` chanlun/ ├── Cargo.toml # 依赖: serde, byteorder, chrono, cached, tracing └── src/ ├── lib.rs # 模块注册 (#![allow(non_snake_case)]) ├── main.rs # 入口(CLI 工具) ├── config.rs # 缠论配置 (62 字段, serde, 622 行) │ ├── types/ # 基础类型 (5 文件, 514 行) │ ├── mod.rs # 重导出: 买卖点类型, 相对方向, 分型结构, 缺口, SyncF64 │ ├── direction.rs # 相对方向 (9 变体): 向上/向下/向上缺口/向下缺口/衔接向上/衔接向下/顺/逆/同 │ ├── bsp_type.rs # 买卖点类型 (18 变体): 一二三买/卖 + T1/T1P/T2/T2S/T3A/T3B │ ├── fractal.rs # 分型结构 (5 变体) + 有高低 trait │ ├── gap.rs # 缺口: 高/低价格区间 + 居中截取 │ └── sync_f64.rs # SyncF64: 基于 AtomicU64 的线程安全 f64 容器 │ ├── kline/ # K线层 (2 文件, 1113 行) │ ├── mod.rs # │ ├── bar.rs # 原始K线 (388 行): OHLCV + RwLock<指标容器>, Clone/Display, 大端字节序序列化 │ └── chan_kline.rs # 缠论K线 (725 行): 经包含处理后的K线, 分型标记, AtomicI64/SyncF64 内部可变性 │ ├── indicators/ # 技术指标 (6 文件, 1589 行) │ ├── mod.rs # K线取值: 开/高/低/收/高低均值/高低收均值/开高低收均值 │ ├── macd.rs # 平滑异同移动平均线 (215 行): EMA 快慢线 + DIF/DEA/MACD柱 │ ├── rsi.rs # 相对强弱指数 (240 行): Wilder SMA 平滑 + 超买超卖线 │ ├── kdj.rs # 随机指标 (289 行): RSV → K → D → J + 超买超卖阈值 │ ├── boll.rs # 布林带 (169 行): 中轨/上轨/下轨 + 带宽 │ ├── calculator.rs # 指标计算器 (476 行): 增量计算 + 回填新指标 + 均线 │ └── container.rs # 指标容器 (202 行): 注册表模式, 动态指标存取 │ ├── algorithm/ # 核心算法 (4 文件, 4987 行) │ ├── mod.rs # │ ├── bi.rs # 笔划分算法 (1009 行): 递归分析, 笔弱化, 次级成笔, 实际高/低点 │ ├── segment.rs # 线段划分算法 (2078 行): 特征序列, 缺口处理, 四种修正机制, 扩展线段 │ ├── hub.rs # 中枢识别算法 (1041 行): 重叠检测, 延伸/扩展, 第三买卖点, 多级中枢 │ └── divergence.rs # 背驰检测 (227 行): MACD背驰/斜率背驰/测度背驰 + 四种组合模式 │ ├── structure/ # 结构体 (4 文件, 2089 行) │ ├── mod.rs # │ ├── dash_line.rs # 虚线 (1712 行): 笔/线段的通用抽象, 买卖意义, MACD行为统计, 分段, 背驰检测 │ ├── fractal_obj.rs # 分型 (344 行): 左中右构型, 分型模式开关, 强度判定, MACD分型匹配 │ ├── segment_feat.rs # 线段特征 (668 行): 特征序列元素, 文/武取极值, 静态分析, 分型序列 │ └── feat_fractal.rs # 特征分型 (62 行): 三线段特征元素构成的分型 │ ├── business/ # 业务层 (4 文件, 1648 行) │ ├── mod.rs # │ ├── observer.rs # 观察者 (1138 行): 单周期分析器, 流式管线, 3级线段/扩展/混合扩展 │ ├── bsp.rs # 基础买卖点 + 买卖点工厂 (595 行): 18种类型, 偏移/失效/终结 │ ├── synthesizer.rs # K线合成器 (161 行): 小周期→大周期合成, 时间戳对齐 │ └── multi_frame.rs # 立体分析器 (192 行): 多周期联立, 合成器+观察者协调 │ └── utils/ # 工具 (2 文件, 145 行) ├── mod.rs # ├── datetime.rs # 时间戳转换: 字符串↔Unix时间戳 └── format.rs # 格式化: f64→最小字符串 (format_f64_g) ``` --- ## 快速开始 ### Cargo 依赖 ```toml [dependencies] chanlun = { path = "path/to/chanlun" } ``` ### 基本用法 — 单周期分析 ```rust use chanlun::config::缠论配置; use chanlun::kline::bar::K线; use chanlun::business::observer::观察者; // 1. 创建配置(所有字段带默认值) let 配置 = 缠论配置::default(); // 2. 创建观察者(返回 Arc>) let 观察员 = 观察者::new("BTCUSD".into(), 3600, 配置); // 3. 逐根投喂K线(流式增量分析,每根K线触发全管线运算) for k线 in k线数据流 { 观察员.write().unwrap().增加原始K线(k线); } // 4. 读取分析结果 let obs = 观察员.read().unwrap(); println!("笔数量: {}", obs.笔序列.len()); println!("线段数量: {}", obs.线段序列().len()); println!("中枢数量: {}", obs.中枢序列().len()); // 遍历笔 for 笔 in &obs.笔序列 { println!("笔方向: {}, 高: {}, 低: {}", 笔.方向(), 笔.高(), 笔.低()); } ``` ### 便捷投喂 — 直接从 OHLCV ```rust let 观察员 = 观察者::new("ETHUSD".into(), 300, Default::default()); let mut obs = 观察员.write().unwrap(); obs.投喂原始数据(1736640000, 3500.0, 3550.0, 3480.0, 3520.0, 1200.0); // ... 继续投喂 ... ``` ### 加载 .nb 数据文件 ```rust let 观察员 = 观察者::new("btcusd".into(), 300, Default::default()); 观察员.write().unwrap().读取数据文件("btcusd-300-1000000-1100000.nb", Default::default())?; ``` ### 多周期分析 ```rust use chanlun::business::multi_frame::立体分析器; // 周期组: [最小输入周期, 更多显示周期...] // 只投喂最小周期K线,大周期自动合成 let mut 分析器 = 立体分析器::new( "BTCUSD".into(), vec![60, 300, 1800, 7200], // 1分钟 → 5分钟 → 30分钟 → 2小时 None, // 默认配置 None, // 无周期特定配置 ); // 投喂最小周期K线 for k线 in 小周期K线流 { 分析器.投喂K线(k线); } // 获取各周期观察者 if let Some(日线观察员) = 分析器.获取观察者(86400) { let obs = 日线观察员.read().unwrap(); println!("日线笔数: {}", obs.笔序列.len()); } ``` --- ## 数据管线 缠论分析按严格的层级顺序进行,每收到一根新K线,**增量更新**所有层级(而非批量重算)。这是该库适合实时交易系统的关键设计。 ### 管线流程 ``` 原始K线 (K线) │ ├── 指标计算: MACD / RSI / KDJ / BOLL (增量更新, 含回填新指标) │ ├── K线取值: 开/高/低/收/高低均值/高低收均值/开高低收均值 │ ├── 多参数组: MACD_参数列表 / RSI_周期列表 / KDJ_参数列表 / BOLL_参数列表 │ └── 均线组: SMA/EMA (均线_类型列表 × 均线_周期列表) │ ├── 包含处理 → 缠论K线 (缠论K线) │ ├── 顺序包含合并 (顺方向取极值) │ ├── 逆序包含合并 (更新时间/标的K线) │ ├── 方向判定 (相对方向: 向上/向下/向上缺口/向下缺口/衔接/包含) │ └── 合并替换模式: 缠K合并替换=false(原地修改) / true(产出新缠K) │ ├── 分型识别 → 分型 (分型) │ ├── 由左中右三根缠论K线构成 │ ├── 类型: 顶分型 / 底分型 / 三连向上 / 三连向下 / 向右扩散 │ ├── 强度: 强 / 中 / 弱 (基于左中右收盘价关系) │ ├── 分型模式: 全局开关控制缓存/实时读取 │ └── MACD柱子分型匹配 (左中右MACD柱形态判定) │ ├── 笔划分 → 笔 (虚线, 标识="笔", 级别=1) │ ├── 递归分析算法: 顶底分型交替验证 │ ├── 成笔条件: 笔内元素数量≥5 (弱化模式≥3) │ ├── 笔弱化策略: 放宽条件时尝试次高/次低成笔 │ ├── 实际高/低点选择: first/last (笔内相同终点取舍) │ ├── 笔内起始分型包含整笔验证 │ └── 笔内原始K线包含整笔验证 │ ├── 线段划分 → 线段 (虚线, 标识="线段", 级别=2) │ ├── 特征序列提取: 从笔序列中提取同向特征序列元素 (线段特征.静态分析) │ ├── 缺口处理: │ │ ├── 有缺口 (老阴/老阳): 严格包含处理, 等待特征分型完成 │ │ └── 无缺口 (小阳/少阴): 允许逆序包含 │ ├── 四种修正机制 (依次尝试): │ │ ├── _缺口突破: 老阳/老阴时价格突破前线段极值 │ │ ├── _非缺口下穿刺: 贯穿伤后出现方向相同的3笔 │ │ ├── _缺口后紧急修正: 前一线段有缺口时自动修正 │ │ └── _修正: 配置启用的短路修正 (≥9笔) │ ├── 线段破坏判定: 新线段形成后前一线段被破坏 │ ├── 3级递归: 线段 → 线段<线段> → 线段<线段<线段>> │ └── 扩展线段分析: 扩展线段 → 扩展线段<扩展线段> → ... │ ├── 中枢识别 → 中枢 (中枢) │ ├── 基础检查: 三条连续虚线重叠且方向关系正确 │ ├── 中枢延伸: 后继虚线未离开中枢则加入基础序列 │ ├── 第三买卖点: 虚线离开中枢后不回中枢, 记录第三买卖线 │ ├── 中枢完成: 第三买卖线确立后开始新中枢 │ ├── 中枢扩展: ≥9段时调用扩展分析生成扩展中枢 │ └── 多级中枢: │ ├── 笔中枢 (级别=1, 基于笔序列) │ ├── 线段中枢 (级别=2, 基于线段序列) │ ├── 扩展线段中枢 (基于扩展线段序列) │ ├── 混合扩展中枢 (基于扩展线段<线段>序列) │ └── 线段<线段>中枢 / 扩展线段<扩展线段>中枢 等 │ └── 买卖点识别 → 基础买卖点 (18种类型) ├── 6 类经典买卖点: 一买/一卖/二买/二卖/三买/三卖 ├── 12 类扩展买卖点: T1/T1P/T2/T2S/T3A/T3B 各含买卖 ├── 指标匹配: MACD柱子匹配 / KDJ金叉死叉 / RSI超买超卖 ├── 背驰确认: MACD背驰 / 斜率背驰 / 测度背驰 ├── 中枢来源策略: 实 / 虚 / 合 ├── 买卖意义缓存: LRU 128条目, 指针身份key └── 偏移/失效偏移/终结K线管理 ``` ### 流式增量处理 `观察者.__处理数据` 每收到一根新K线: 1. 计算指标并挂载到新K线 2. 执行缠K包含处理,产出缠K 3. 识别分型,添加到分型序列 4. 递归分析笔(可能生成新笔或修改最后一笔) 5. 递归分析中枢(笔中枢) 6. 递归分析线段(3级递归:线段→线段<线段>→线段<线段<线段>>) 7. 递归分析扩展线段(3级递归) 8. 递归分析混合扩展线段(3级递归,源序列为线段序列组[i]) 每步都只处理最后几个元素,时间复杂度 O(1) 均摊。 --- ## 核心类型详解 ### 枚举类型 #### 相对方向 (`types::direction`) 用于描述两个价格区间(两根K线或两个分型)之间的位置关系,共 9 个变体: | 变体 | 说明 | 示例场景 | |------|------|---------| | `向上` | 后K线高低点均高于前K线,且不构成缺口 | 正常上涨 | | `向下` | 后K线高低点均低于前K线,且不构成缺口 | 正常下跌 | | `向上缺口` | 后K线低点 > 前K线高点 | 大幅高开 | | `向下缺口` | 后K线高点 < 前K线低点 | 大幅低开 | | `衔接向上` | 后K线低点 == 前K线高点 | 精准衔接上涨 | | `衔接向下` | 后K线高点 == 前K线低点 | 精准衔接下跌 | | `顺` | 前K线包含后K线(前高≥后高 且 前低≤后低) | 顺序包含 | | `逆` | 后K线包含前K线(前高≤后高 且 前低≥后低) | 逆序包含 | | `同` | 两K线高低点完全相同 | 重复数据 | 提供方法:`翻转()`, `是否向上()`, `是否向下()`, `是否包含()`, `是否缺口()`, `是否衔接()`, `分析(前高,前低,后高,后低)` #### 分型结构 (`types::fractal`) 三根K线构成的结构形态,共 5 个变体: | 变体 | 左中右关系 | |------|-----------| | `上` | 向上类 + 向上类 | | `下` | 向下类 + 向下类 | | `顶` | 向上类 + 向下类(Λ 形) | | `底` | 向下类 + 向上类(V 形) | | `散` | 逆序包含 + 逆序包含 | 提供方法:`分析(左,中,右, 可以逆序包含, 忽视顺序包含)` — 通用分型识别 #### 买卖点类型 (`types::bsp_type`) 18 种买卖点分类: | 类别 | 买点 | 卖点 | 说明 | |------|------|------|------| | 一类 | `一买` | `一卖` | 中枢背驰后的第一类买卖点 | | 二类 | `二买` | `二卖` | 回调到中枢内的第二类买卖点 | | 三类 | `三买` | `三卖` | 离开中枢后不回中枢的第三类买卖点 | | 扩展T1 | `T1买` | `T1卖` | 事后确认型 | | 扩展T1P | `T1P买` | `T1P卖` | 事后确认型+ | | 扩展T2 | `T2买` | `T2卖` | 中枢回调型 | | 扩展T2S | `T2S买` | `T2S卖` | 中枢回调次级 | | 扩展T3A | `T3A买` | `T3A卖` | 第三类扩展A | | 扩展T3B | `T3B买` | `T3B卖` | 第三类扩展B | 提供方法:`是买点()`, `是卖点()` ### 数据结构详解 #### K线 (`kline::bar`) — 原始OHLCV + 指标 ``` K线 { 标识, 序号, 周期, 时间戳, 高, 低, 开盘价, 收盘价, 成交量, 指标: RwLock<指标容器> // MACD/RSI/KDJ/BOLL/均线 } ``` - 实现 `Clone` (深拷贝, 包括指标容器) - 支持大端字节序序列化 (`to_bytes()` → 48字节, `from_bytes()`) - 提供 `创建普K()` 工厂方法, `相等()` 结构化校验 - `获取MACD()` 计算两K线间的 MACD 柱面积 (阳/阴/合/总) - `截取rc()` 按 Arc 指针截取序列片段 #### 缠论K线 (`kline::chan_kline`) — 包含处理后的K线 ``` 缠论K线 { 序号: AtomicI64, 时间戳: AtomicI64, 高: SyncF64, // 经包含处理可能被拉高 低: SyncF64, // 经包含处理可能被压低 方向: RwLock<相对方向>, 分型: RwLock>, 分型特征值: SyncF64, // 历史高低点极值 周期, 标识, 原始起始序号, // 包含处理前 原始结束序号: AtomicI64, // 包含处理后更新 标的K线: RwLock>, 买卖点信息: RwLock>, } ``` - 核心算法:`_兼并()` — 顺序/逆序包含合并, 重复提交检测, 原地修改 - `分析()` — 完整的普K→缠K+分型管线 - 指标匹配:`与MACD柱子匹配()` / `与RSI匹配()` / `与KDJ匹配()` - 时间戳对齐:跨周期对齐至基线 - `相等()` — 20+ 字段逐项递归校验 #### 分型 (`structure::fractal_obj`) — 顶/底分型 ``` 分型 { 左: Option>, 中: Arc<缠论K线>, // 核心K线 右: Option>, 结构: 分型结构, // 构造时缓存 时间戳: i64, // 构造时缓存 分型特征值: f64, // 构造时缓存 } ``` - **分型模式** (`分型模式: AtomicBool`): 全局开关 - `true` (默认) — `时间戳()/结构()/分型特征值()` 返回构造时缓存值 - `false` — 从 `中` 缠K 实时读取(逆序包含后使用) - 提供方法:`强度()` (强/中/弱), `关系组()` (左中右三组关系), `与MACD柱子分型匹配()` - `相等()` — 递归校验左/中/右缠K + 自有缓存字段 - 实现 `有高低` trait: 高/低 → 中.高/中.低 #### 虚线 (`structure::dash_line`) — 笔和线段的通用数据结构 ``` 虚线 { 标识: RwLock, // "笔"/"线段"/"扩展线段"/"线段<线段>" 等 序号: AtomicI64, 级别: AtomicI64, // 笔=1, 线段=2, 线段<线段>=3, ... 文: Arc<分型>, // 起点分型(不可变) 武: RwLock>, // 终点分型(可变,用于动态更新) 有效性: AtomicBool, 基础序列: RwLock>>, // 构成虚线的子级虚线序列 特征序列: RwLock>>>, // 线段特征序列 实_中枢序列: RwLock>>, 虚_中枢序列: RwLock>>, 合_中枢序列: RwLock>>, 确认K线: RwLock>>, 模式: RwLock, // 买卖点匹配模式 _特征序列_显示: AtomicBool, 前一缺口: RwLock>, 前一结束位置: RwLock>>, 短路修正: AtomicBool, } ``` - 静态工厂:`创建笔()` (级别=1), `创建线段()` (级别=笔级别+1, 基础序列=笔序列) - 属性:`方向()`, `高()`, `低()`, `之前是()`, `之后是()` - 数据访问:`获取普K序列()`, `获取缠K序列()`, `获取_武()` (递归到底层笔) - 买卖点模式匹配:`全量/任意/配置/相对` 四种指标组合策略 - MACD相关:`计算MACD柱子均值()`, `武之MACD均值()`, `武之MACD极值()` - 趋势分析:`计算K线序列MACD趋向背驰()` (MACD柱/DIF/DEA三项背驰) - 分段:`计算MACD柱子分段()` (按正负号分段) - 行为统计:`统计MACD行为()` → `MACD行为统计 {DIF上下穿0, DEA上下穿0, 金叉/死叉次数, 密集交叉区域}` - 核心判断:`买卖意义()` — LRU 缓存 128 条目,指针身份作为 key - 序列化:`获取数据文本()` — 笔输出简洁格式,线段输出完整格式 - `相等()` — 递归校验文/武/基础序列/特征序列/中枢序列/确认K线/模式/缺口/结束位置等全部字段 #### 线段特征 (`structure::segment_feat`) — 特征序列元素 ``` 线段特征 { 序号: AtomicI64, 标识: RwLock, 线段方向: 相对方向, 基础序列: Vec>, // 构成该元素的虚线序列 } ``` - 虚拟端点:`文()` — 取特征值最大/最小的起点分型 - 虚拟端点:`武()` — 取特征值最大/最小的终点分型 - tiebreaker: 同特征值时取后时间戳 - `高()/低()` — 文/武中分型特征值的较大/较小者 - `方向()` — 线段方向的翻转 - 静态分析:从虚线序列生成特征序列元素列表,含分型替换逻辑 - 分型序列:从连续特征序列元素中提取特征分型 #### 特征分型 (`structure::feat_fractal`) ``` 特征分型 { 左: Arc<线段特征>, 中: Arc<线段特征>, 右: Arc<线段特征>, 结构: 分型结构, // 由左中右三元素分析得出 } ``` #### 中枢 (`algorithm::hub`) ``` 中枢 { 序号: AtomicI64, 标识: RwLock, // "笔中枢<0>"/"线段中枢<1>" 等 级别: AtomicI64, 基础序列: RwLock>>, // 至少3根, 延伸后可达9+ 第三买卖线: RwLock>>, 本级_第三买卖线: RwLock>>, } ``` - 属性:`高()` (前三根虚线的最高重叠), `低()` (前三根虚线的最低重叠) - `文()` → `武()` → `方向()` - `延伸序列()` → 首尾之外的虚线 - `获取数据文本()` — 完整中枢结构化描述 - `相等()` — 逐项递归校验基础序列和第三买卖线 - 向序列中添加/更新中枢(含显示名称映射) #### 基础买卖点 (`business::bsp`) ``` 基础买卖点 { 备注: String, 类型: 买卖点类型, 买卖点分型: Arc<分型>, 买卖点K线: Arc<缠论K线>, // = 买卖点分型.中 当前K线: Arc, 失效K线: Option>, 终结K线: Option>, 破位值: f64, 结构: Option<分型结构>, 当前缠K序号: Option, } ``` - `偏移()` — 当前缠K序号与买卖点K线序号的差 - `有效性()` — 失效K线是否存在 ### 服务类型 | 类型 | 职责 | 位置 | |------|------|------| | `观察者` | 单周期分析器, 接收K线流, 维护所有层级序列, 3级递归线段分析 | `business::observer` | | `K线合成器` | 小周期→大周期合成, 高取max/低取min/量求和, 时间戳对齐 | `business::synthesizer` | | `立体分析器` | 多周期联立, 内含合成器 + 每周期一个观察者, 对齐缠K序列 | `business::multi_frame` | ### 静态算法类 | 类型 | 职责 | 位置 | |------|------|------| | `笔` | 笔划分: 分型→笔 (递归分析, 笔弱化, 次级成笔, 实际高/低点, 是否背驰过) | `algorithm::bi` | | `线段` | 线段划分: 笔→线段 (特征序列+缺口处理+四种修正+扩展分析+内部背驰判断) | `algorithm::segment` | | `中枢` | 中枢识别: 虚线→中枢 (重叠检测+延伸/扩展+第三买卖点+向序列添加) | `algorithm::hub` | | `背驰分析` | 背驰检测: MACD/斜率/测度 + 全量/任意/配置/相对四种组合 | `algorithm::divergence` | | `指标计算器` | 指标增量计算: MACD/RSI/KDJ/BOLL + 回填新指标 + 均线 | `indicators::calculator` | --- ## 配置体系 `缠论配置` 是一个 serde 驱动的结构体,**62 个字段**全部带默认值,支持 JSON 往返和部分反序列化容错。 ### 完整配置表 #### 基础设置 | 字段 | 默认值 | 说明 | |------|--------|------| | `标识` | `"bar"` | 品种标识 | #### 缠K设置 | 字段 | 默认值 | 说明 | |------|--------|------| | `缠K合并替换` | `false` | false=原地修改, true=产出新缠K | #### 笔设置 | 字段 | 默认值 | 说明 | |------|--------|------| | `笔内元素数量` | `5` | 成笔最低缠K数 | | `笔内相同终点取舍` | `false` | false=取first, true=取last | | `笔内起始分型包含整笔` | `false` | 起点分型区间必须包含整笔 | | `笔内起始分型包含整笔_包括右` | `false` | 同上+包含右端点 | | `笔内原始K线包含整笔` | `false` | 原始K线区间必须包含整笔 | | `笔次级成笔` | `false` | 允许在非分型处成笔 | | `笔弱化` | `false` | 放宽成笔条件 | | `笔弱化_原始数量` | `3` | 弱化模式最小原始K线数 | #### 线段设置 | 字段 | 默认值 | 说明 | |------|--------|------| | `线段_非缺口下穿刺` | `false` | 非缺口下的穿刺处理 | | `线段_特征序列忽视老阴老阳` | `false` | 缺口时不严格处理包含 | | `线段_缺口后紧急修正` | `true` | 缺口后自动修正 | | `线段_修正` | `false` | 短路修正(不推荐) | | `线段内部中枢图显` | `true` | 线段内部中枢图表显示 | | `扩展线段_当下分析` | `false` | 扩展线段实时分析模式 | #### 分析开关 | 字段 | 默认值 | 说明 | |------|--------|------| | `分析笔` | `true` | | | `分析线段` | `true` | | | `分析扩展线段` | `true` | | | `分析笔中枢` | `true` | | | `分析线段中枢` | `true` | | #### 终止 | 字段 | 默认值 | 说明 | |------|--------|------| | `手动终止` | `""` | 手动终止时间字符串 | #### 指标设置 | 字段 | 默认值 | 说明 | |------|--------|------| | `计算指标` | `true` | 是否计算技术指标 | | `计算BOLL` | `false` | 是否计算布林带 | | `指标计算方式` | `"收"` | 开/高/低/收/高低均值/高低收均值/开高低收均值 | #### MACD 参数 | 字段 | 默认值 | 说明 | |------|--------|------| | `平滑异同移动平均线_快线周期` | `13` | | | `平滑异同移动平均线_慢线周期` | `31` | | | `平滑异同移动平均线_信号周期` | `11` | | | `MACD_参数列表` | `[]` | 多参数变体: `Vec<(key, 快, 慢, 信号)>` | #### RSI 参数 | 字段 | 默认值 | 说明 | |------|--------|------| | `相对强弱指数_周期` | `13` | RSI计算周期 | | `相对强弱指数_移动平均线周期` | `13` | RSI SMA平滑周期 | | `相对强弱指数_超买阈值` | `75.0` | | | `相对强弱指数_超卖阈值` | `25.0` | | | `RSI_周期列表` | `[]` | 多周期变体: `Vec<(key, 周期)>` | #### KDJ 参数 | 字段 | 默认值 | 说明 | |------|--------|------| | `随机指标_RSV周期` | `13` | | | `随机指标_K值平滑周期` | `5` | | | `随机指标_D值平滑周期` | `5` | | | `随机指标_超买阈值` | `80.0` | | | `随机指标_超卖阈值` | `20.0` | | | `KDJ_参数列表` | `[]` | 多参数变体 | #### BOLL 参数 | 字段 | 默认值 | 说明 | |------|--------|------| | `布林带_周期` | `20` | | | `布林带_标准差倍数` | `2.0` | | | `BOLL_参数列表` | `[]` | 多参数变体 | #### 均线参数 | 字段 | 默认值 | 说明 | |------|--------|------| | `均线_类型列表` | `[]` | `["SMA", "EMA", ...]` | | `均线_周期列表` | `[]` | `[5, 10, 20, ...]` | #### 推送/图表显示 | 字段 | 默认值 | |------|--------| | `图表展示` | `true` | | `推送K线` | `true` | | `推送笔` | `true` | | `推送线段` | `true` | | `推送中枢` | `true` | | `图表展示_笔` | `true` | | `图表展示_线段` | `true` | | `图表展示_扩展线段` | `true` | | `图表展示_扩展线段_线段` | `true` | | `图表展示_线段_线段` | `true` | | `图表展示_中枢_笔` | `true` | | `图表展示_中枢_线段` | `true` | | `图表展示_中枢_扩展线段` | `true` | | `图表展示_中枢_扩展线段_线段` | `true` | | `图表展示_中枢_线段_线段` | `true` | | `图表展示_中枢_线段内部` | `true` | #### 买卖点设置 | 字段 | 默认值 | 说明 | |------|--------|------| | `买卖点偏移` | `1` | 最大偏移量 | | `买卖点激进识别` | `false` | | | `买卖点与MACD柱强相关` | `false` | | | `买卖点错过误差值` | `0.01` | | | `买卖点_指标模式` | `"配置"` | 任意/配置/全量/相对 | | `买卖点_指标匹配_MACD` | `true` | | | `买卖点_指标匹配_KDJ` | `true` | | | `买卖点_指标匹配_RSI` | `true` | | | `买卖点_背离率` | `INFINITY` | 不使用 | | `买卖点_T2_回调阈值` | `1.0` | | | `买卖点_T2S_最大层级` | `3` | | | `买卖点_峰值条件` | `false` | | | `买卖点_计算方式` | `"峰"` | | | `买卖点_计算线段BSP1` | `true` | | | `买卖点_处理BSP2` | `true` | | | `买卖点_计算线段BSP3` | `true` | | | `买卖点_依赖T1` | `true` | | | `买卖点_中枢来源` | `"合"` | 实/虚/合 | | `买卖点_调试输出` | `false` | | #### 背驰设置 | 字段 | 默认值 | 说明 | |------|--------|------| | `线段内部背驰_MACD` | `true` | 使用 MACD 背驰 | | `线段内部背驰_斜率` | `true` | 使用斜率背驰 | | `线段内部背驰_测度` | `true` | 使用测度背驰 | | `线段内部背驰_模式` | `"相对"` | 任意/配置/全量/相对 | #### 文件 | 字段 | 默认值 | 说明 | |------|--------|------| | `加载文件路径` | `""` | 数据文件路径 | ### 配置方法 ```rust // JSON 往返 let json = config.to_json(); // 序列化 let config2 = 缠论配置::from_json(&json)?; // 反序列化 // 文件 I/O config.保存配置("/path/to/config.json")?; // 保存 let loaded = 缠论配置::加载配置("/path/to/config.json")?; // 加载 // 部分反序列化(缺失字段→默认值) let config: 缠论配置 = serde_json::from_str(r#"{"笔内元素数量": 7}"#)?; // 静默模式 let silent = config.不推送(); // 所有推送/展示开关设为 false // 差异对比 let diffs = config_a.对比(&config_b); // → ["笔内元素数量", ...] // 多参数解析(列表非空则使用列表,否则使用默认单组) let macd参数 = config._解析MACD参数列表(); // Vec<(key, 快, 慢, 信号)> let rsi周期 = config._解析RSI周期列表(); // Vec<(key, 周期)> let kdj参数 = config._解析KDJ参数列表(); // Vec<(key, RSV, K, D)> let boll参数 = config._解析BOLL参数列表(); // Vec<(key, 周期, 倍数)> // 复合key重组(兼容旧版 "1_open" 格式) let configs = 缠论配置::按序号重组字典(&default_config, &raw_json); ``` --- ## 算法模块 ### 笔划分 (`algorithm::bi`, 1009 行) `笔` 是一个纯静态方法命名空间,核心方法: | 方法 | 说明 | |------|------| | `分析()` | 主算法:接收分型,递归分析生成笔 | | `_获取缠K数量()` | 计算可成笔的缠K数量(含弱化模式) | | `_实际高点() / _实际低点()` | 潜在成笔区域的最高/最低缠K | | `_获取成笔核心分型()` | 笔弱化模式下获取次高/次低成笔的候选分型 | | `根据缠K找笔()` | 在笔序列中查找包含指定缠K的笔 | | `是否背驰过()` | 检查笔范围内是否发生过MACD背驰 | 关键设计: - 笔弱化:当严格条件不满足时,允许 `笔弱化_原始数量` (≥3) 根原始K线成笔 - 次级成笔:允许次高/次低成笔的候选分型 - 相同终点取舍:false=取first, true=取last (Python `list.index` 行为) - 笔内验证:起始分型包含整笔 / 原始K线包含整笔 ### 线段划分 (`algorithm::segment`, 2078 行) `线段` 是**最复杂的算法模块**,核心方法: | 方法 | 说明 | |------|------| | `分析()` | 主算法:从笔序列计算线段 | | `扩展分析()` | 扩展线段分析(不同的缺口处理策略) | | `分割序列()` | 将特征序列分割为前/后/三/贯穿伤四个部分 | | `特征序列状态()` | 返回 (特征_a, 特征_b, 特征_c) 布尔标志 | | `四象()` | 判断特征序列的类型:老阳/老阴/小阳/少阴 | | `获取缺口()` | 获取特征序列第一二元素间的缺口 | | `判断线段内部是否背驰()` | 线段内部进入段vs离开段背驰判断 | | `是否背驰过()` | 线段范围内是否发生过背驰 | | `获取所有停顿位置()` | 获取线段内部所有可能的停顿位置 | | `获取内部中枢序列()` | 获取线段内部的中枢序列 | 四种修正机制(按优先级): 1. `_缺口突破` — 老阳/老阴状态 + 价格突破前线段极值 → 线段完成 2. `_非缺口下穿刺` — 贯穿伤存在 + 方向相同的3笔 → 线段完成 3. `_缺口后紧急修正` — 前一线段有缺口 + 价格反向突破 → 修正前一结束位置 4. `_修正` — 短线路径 (≥9笔) → 快速完成 ### 中枢识别 (`algorithm::hub`, 1041 行) `中枢` 既是数据结构也是算法命名空间: | 方法 | 说明 | |------|------| | `分析()` | 主算法:虚线→中枢,同时识别第三买卖点 | | `线段扩展分析()` | 中枢扩展:≥9段时生成扩展中枢 | | `高()` | 前三根虚线重叠区域的最高值 | | `低()` | 前三根虚线重叠区域的最低值 | | `文()` | 第一根虚线的起点分型 | | `武()` | 第三根虚线的终点分型 | | `方向()` | 当中枢高 > 中枢低时为向上,否则向下 | | `延伸序列()` | 首尾之外的虚线 | | `获取离开虚线()` | 找到离开中枢的虚线(第三买卖点) | | `获取剩余虚线()` | 第三买卖点之后的虚线 | | `获取第N买卖线()` | 获取第N个买卖点相关的虚线 | 中枢识别核心逻辑: 1. 基础检查:三条连续虚线必须重叠(`max(低) < min(高)`)且方向关系正确 2. 中枢延伸:在后继虚线中找离开中枢的虚线,未离开则加入基础序列 3. 第三买卖点:虚线离开中枢且不回中枢,记录 `第三买卖线` 4. 中枢完成:`第三买卖线` 确立后,在上方虚线开始新中枢 5. 中枢扩展:≥9段时调用 `线段扩展分析` 生成扩展中枢 ### 背驰检测 (`algorithm::divergence`, 227 行) `背驰分析` 提供三种检测方式: | 方式 | 原理 | 方法 | |------|------|------| | MACD背驰 | 进入段vs离开段的MACD柱面积对比 (`阳 + |阴|` 绝对值和) | `MACD背驰()` | | 斜率背驰 | 价格变化速率 (dy/dx) 减弱 | `斜率背驰()` | | 测度背驰 | 价格-时间向量长度 (√(dx²+dy²)) 缩减 | `测度背驰()` | 四种组合模式: | 模式 | 条件 | |------|------| | `全量` | MACD 且 斜率 且 测度 全满足 | | `任意` | MACD 或 斜率 或 测度 任意满足 | | `配置` | 根据 `线段内部背驰_MACD/斜率/测度` 配置组合 | | `相对` | 至少两种方式满足(多数投票) | --- ## 技术指标 所有指标位于 `indicators/` 模块,均支持**首次计算**和**增量计算**两种模式。 ### 统一指标容器 (`indicators::container`) 基于注册表模式,通过 `指标值` 枚举统一管理五种指标类型: ```rust pub enum 指标值 { MACD(平滑异同移动平均线), RSI(相对强弱指数), KDJ(随机指标), BOLL(布林带), 均线(HashMap), 单值(HashMap), } ``` - 预注册默认槽位:`macd`, `rsi`, `kdj`, `boll`, `均线`, `单值` - 支持多参数变体:`MACD_13_31_11`, `RSI_14`, `KDJ_9_3_3` 等 - 便捷方法:`macd()`, `rsi()`, `kdj()`, `boll()`, `均线()` - 动态注册:`注册(name, default_value)`, `设置(name, value)` ### 指标计算器 (`indicators::calculator`, 476 行) `指标计算器::计算并挂载(全序列, 配置)` 是一次完整的指标计算周期: 1. **MACD组** — 遍历 `_解析MACD参数列表()`,对每个 (key, 快, 慢, 信号) 计算 2. **RSI组** — 遍历 `_解析RSI周期列表()` 3. **KDJ组** — 遍历 `_解析KDJ参数列表()` 4. **BOLL组** — 遍历 `_解析BOLL参数列表()` 5. **均线** — 遍历 `均线_类型列表 × 均线_周期列表`,MA/EMA 计算 6. **回填新指标** — 如果当前K线有前序K线遗漏的指标,回溯填充 K线取值 (`K线取值()`) 支持 7 种计算方式: `开` / `高` / `低` / `收` / `高低均值` / `高低收均值` / `开高低收均值` ### MACD (`indicators::macd`, 215 行) ``` 平滑异同移动平均线 { 时间戳, 收盘价, 快线周期, 慢线周期, 信号周期, DIF: Option, // 快线EMA - 慢线EMA DEA: Option, // DIF的信号线EMA MACD柱: f64, // 2 * (DIF - DEA) 快线EMA: Option, // 计算中间值(增量用) 慢线EMA: Option, DEA_EMA: Option, } ``` - `首次计算(收盘价, 时间戳, 快线周期, 慢线周期, 信号周期)` — 初始EMA=SMA近似 - `增量计算(prev, 收盘价, 时间戳)` — EMA递推公式 - `计算K线MACD(普K序列, 快, 慢, 信号)` — 遍历序列批量计算 ### RSI (`indicators::rsi`, 240 行) ``` 相对强弱指数 { 时间戳, 收盘价, 周期, 超买阈值, 超卖阈值, RSI: Option, RSI_SMA: Option, // RSI的SMA信号线 平均上涨: Option, // Wilder平滑中间值(增量用) 平均下跌: Option, } ``` - Wilder SMA 平滑算法 - `首次计算()` — 初始均值=SMA - `增量计算()` — Wilder递推 ### KDJ (`indicators::kdj`, 289 行) ``` 随机指标 { 时间戳, 最高价, 最低价, 收盘价, RSV周期, K值平滑周期, D值平滑周期, 超买阈值, 超卖阈值, K: Option, // RSV的移动平均 D: Option, // K的移动平均 J: Option, // 3*K - 2*D } ``` - `首次计算(全体)` — 从序列计算初始KDJ值 - `增量计算(全体, 当前, 周期, K平滑, D平滑)` — 增量更新 ### BOLL (`indicators::boll`, 169 行) ``` 布林带 { 时间戳, 收盘价, 周期, 标准差倍数, 中轨: Option, // SMA 上轨: Option, // 中轨 + 倍数 * 标准差 下轨: Option, // 中轨 - 倍数 * 标准差 } ``` --- ## 线程安全与并发 ### 内部可变性策略 缠K/虚线/中枢等结构体需要在多 `Arc` 共享时支持原地修改(如笔动态替换武、中枢延伸添加虚线)。Rust 中 `Arc` 的 `&self` 是不可变的,因此大量字段使用以下策略实现内部可变性: | 机制 | 类型 | 适用场景 | |------|------|---------| | `SyncF64` | `AtomicU64` 位转换 | 价格字段 (高/低/分型特征值),需跨线程原子读写 | | `AtomicI64` | 原子整数 | 序号/时间戳/原始结束序号 | | `AtomicBool` | 原子布尔 | 有效性/短路修正/特征序列显示 | | `RwLock` | 读写锁 | 复杂字段 (Arc<分型>/Vec/标识/模式/中枢序列) | ### 全局缓存 - **买卖意义缓存**: `LazyLock>>` — 128条目,key为 (虚线指针, 观察者指针) 地址对 - **与 Python 对齐**:Python 使用 `@lru_cache(maxsize=128)` 装饰器,Rust 使用全局 `LazyLock>` 替代 PyO3 的 `thread_local!`(解决跨线程不可见问题) ### Send + Sync 保证 所有核心数据结构(`缠论K线`, `虚线`, `中枢`, `观察者`)均实现 `Send + Sync`,可以安全地跨线程传递和共享: ```rust // 编译期断言 fn _需要_Send_Sync() {} _需要_Send_Sync::<缠论K线>(); _需要_Send_Sync::<虚线>(); _需要_Send_Sync::<中枢>(); ``` `观察者` 使用 `Arc>` 模式,多线程可以并发读取同一个观察者的分析结果。 ### RwLock 死锁预防 Rust 的 `RwLock` 是**非递归锁**。在已有读锁的线程中尝试获取写锁会死锁。核心规则: - 将读锁作用域化:在所有调用带写锁的方法之前释放 `prev_guard` - 典型模式:`{ let prev_guard = ... ; /* 使用 prev_guard */ } // 作用域结束释放 → 安全调用回填` --- ## Python 绑定 Python 调用通过独立的 [`chanlun-py`](../chanlun-py/) crate 提供,使用 PyO3 包装。所有类型、方法、字段名与 `chan.py` **完全一致**,API 兼容。 ```bash cd chanlun-py maturin develop --release ``` ```python import chanlun # 创建/修改配置 config = chanlun.缠论配置() config.笔内元素数量 = 7 config.MACD_参数列表 = [("my_macd", 12, 26, 9)] # 创建观察者 obs = chanlun.观察者("BTCUSD", 3600, config) # 通过 Python 属性直接修改配置(自动同步到核心层) obs.配置.笔弱化 = True # 投喂K线 k = chanlun.K线.创建普K("bar", 1736640000, 50000, 51000, 49000, 50500, 100, 0, 3600) obs.增加原始K线(k) # 获取分析结果 print(f"笔数量: {len(obs.笔序列)}") print(f"线段数量: {len(obs.线段序列)}") print(f"中枢数量: {len(obs.中枢序列)}") # 全局开关 chanlun.分型模式 = False # 从缠K实时读取分型值(逆序包含后使用) ``` ### 绑定层特性 - **配置缓存**: `obs.配置` 返回同一个 Python 对象(而非每次新建),确保 Python 端修改后 Rust 端可见 - **分型模式**: 模块级 `chanlun.分型模式` getter/setter,控制分型值的读取策略 - **数据文件兼容**: `chanlun.读取数据文件("file.nb", config, 观察员=obs)` 与 Python 版签名一致 - **跨线程身份**: 全局 `LazyLock` 保证跨线程 `is` 判断一致 --- ## 数据序列化 ### K线二进制格式 与 Python `struct.pack(">6d")` 完全兼容的大端字节序格式,每根K线 48 字节: | 偏移 | 大小 | 字段 | |------|------|------| | 0 | 8 字节 | 时间戳 (Unix秒 as f64) | | 8 | 8 字节 | 开盘价 | | 16 | 8 字节 | 最高价 | | 24 | 8 字节 | 最低价 | | 32 | 8 字节 | 收盘价 | | 40 | 8 字节 | 成交量 | ```rust // 序列化 let bytes: [u8; 48] = k线.to_bytes(); // 反序列化 let k线 = K线::读取大端字节数组(&bytes, 周期, 标识); // 解析原始数据(不构造K线) let (时间戳, 开, 高, 低, 收, 量) = K线::解析原始数据(&bytes)?; // 批量保存 K线::保存到DAT文件("output.dat", &[&k1, &k2])?; ``` ### 配置 JSON ```json { "标识": "BTCUSD", "笔内元素数量": 5, "平滑异同移动平均线_快线周期": 13, "平滑异同移动平均线_慢线周期": 31, "买卖点_指标模式": "配置", "线段内部背驰_模式": "相对" } ``` - 使用 `#[serde(default)]` 实现前向/后向兼容,缺失字段自动使用默认值 - 字符串枚举字段(`指标计算方式`, `买卖点_指标模式`, `线段内部背驰_模式`)带有自定义反序列化器,非法值自动回退默认值并发出 `warn!` 日志 ### 结构化相等校验 所有核心结构体都实现了 `相等(&self, other, 浮点容差) → (bool, String)` 方法,递归校验包括: - 浮点字段使用容差比较(而非直接 `==`) - `Arc` 指针共享的结构体深度校验值语义 - 嵌套容器(Vec, Option, HashMap)逐一比对 - 返回详细的差异描述,便于调试 --- ## 测试 ### 核心层测试 (`chanlun/`) ```bash cargo test # 运行所有测试 cargo test -- test_重复计算 # 运行匹配模式的测试 ``` 测试覆盖: - **配置**: 默认值、JSON 往返、部分反序列化、非法值回退、不推送模式 - **K线**: 方向判定、大端字节序列化往返 - **缠K**: 创建/镜像/包含合并/分型识别、三K线生成分型 - **分型**: 左中右构造、字段读写、关联指针 - **虚线**: Cell/RefCell 读写、Clone 后 Rc 指针一致、多 Arc 共享可见性、获取武递归、武修改不影响文 - **线段特征**: 文取max/min, 武取max/min, tiebreaker, 添加/删除 - **中枢**: 字段读写、Clone 后指针一致、多 Arc 共享 - **买卖点**: 偏移/失效偏移/有效性、18种类型生成 - **观察者**: 指针一致性 (普K/分型/笔/线段/中枢)、重复计算确定性、重置后数据一致、RefCell 借用安全、跨线程 Send/Sync ### Python 绑定层测试 (`chanlun-py/tests/test_all.py`) ```bash cd chanlun-py && maturin develop python3 -m pytest tests/test_all.py -v # 107+ tests, 涵盖: # - 指标挂载与回填 # - 跨线程身份一致性 (is 判断) # - 买卖意义/趋向背驰/行为统计/停顿位置/线段内部背驰等 双端(Rust绑定 vs chan.py)数据对比 ``` --- ## 许可 MIT License. 详见 [LICENSE](LICENSE). --- ## 相关项目 - [`chan.py`](../chan.py) — Python 参考实现(~4200 行) - [`chanlun-py`](../chanlun-py/) — PyO3 绑定,将本 crate 导出为 Python `chanlun` 模块 - [`main.py`](../main.py) — Python 图表可视化程序