# 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<RwLock<观察者>>）
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 个变体：

| 变体 | 左中右关系 |
|------|-----------|
| `上` | 向上类 + 向上类 |
| `下` | 向下类 + 向下类 |
| `顶` | 向上类 + 向下类（<u>Λ</u> 形） |
| `底` | 向下类 + 向上类（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<Option<分型结构>>,
    分型特征值: SyncF64,   // 历史高低点极值
    周期, 标识,
    原始起始序号,           // 包含处理前
    原始结束序号: AtomicI64, // 包含处理后更新
    标的K线: RwLock<Arc<K线>>,
    买卖点信息: RwLock<HashSet<String>>,
}
```
- 核心算法：`_兼并()` — 顺序/逆序包含合并, 重复提交检测, 原地修改
- `分析()` — 完整的普K→缠K+分型管线
- 指标匹配：`与MACD柱子匹配()` / `与RSI匹配()` / `与KDJ匹配()`
- 时间戳对齐：跨周期对齐至基线
- `相等()` — 20+ 字段逐项递归校验

#### 分型 (`structure::fractal_obj`) — 顶/底分型
```
分型 {
    左: Option<Arc<缠论K线>>,
    中: Arc<缠论K线>,       // 核心K线
    右: Option<Arc<缠论K线>>,
    结构: 分型结构,         // 构造时缓存
    时间戳: i64,            // 构造时缓存
    分型特征值: f64,        // 构造时缓存
}
```
- **分型模式** (`分型模式: AtomicBool`): 全局开关
  - `true` (默认) — `时间戳()/结构()/分型特征值()` 返回构造时缓存值
  - `false` — 从 `中` 缠K 实时读取（逆序包含后使用）
- 提供方法：`强度()` (强/中/弱), `关系组()` (左中右三组关系), `与MACD柱子分型匹配()`
- `相等()` — 递归校验左/中/右缠K + 自有缓存字段
- 实现 `有高低` trait: 高/低 → 中.高/中.低

#### 虚线 (`structure::dash_line`) — 笔和线段的通用数据结构
```
虚线 {
    标识: RwLock<String>,      // "笔"/"线段"/"扩展线段"/"线段<线段>" 等
    序号: AtomicI64,
    级别: AtomicI64,           // 笔=1, 线段=2, 线段<线段>=3, ...
    文: Arc<分型>,             // 起点分型（不可变）
    武: RwLock<Arc<分型>>,     // 终点分型（可变，用于动态更新）
    有效性: AtomicBool,
    基础序列: RwLock<Vec<Arc<虚线>>>,     // 构成虚线的子级虚线序列
    特征序列: RwLock<Vec<Option<Arc<线段特征>>>>,  // 线段特征序列
    实_中枢序列: RwLock<Vec<Arc<中枢>>>,
    虚_中枢序列: RwLock<Vec<Arc<中枢>>>,
    合_中枢序列: RwLock<Vec<Arc<中枢>>>,
    确认K线: RwLock<Option<Arc<缠论K线>>>,
    模式: RwLock<String>,                  // 买卖点匹配模式
    _特征序列_显示: AtomicBool,
    前一缺口: RwLock<Option<缺口>>,
    前一结束位置: RwLock<Option<Arc<虚线>>>,
    短路修正: 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<String>,
    线段方向: 相对方向,
    基础序列: Vec<Arc<虚线>>,    // 构成该元素的虚线序列
}
```
- 虚拟端点：`文()` — 取特征值最大/最小的起点分型
- 虚拟端点：`武()` — 取特征值最大/最小的终点分型
- tiebreaker: 同特征值时取后时间戳
- `高()/低()` — 文/武中分型特征值的较大/较小者
- `方向()` — 线段方向的翻转
- 静态分析：从虚线序列生成特征序列元素列表，含分型替换逻辑
- 分型序列：从连续特征序列元素中提取特征分型

#### 特征分型 (`structure::feat_fractal`)
```
特征分型 {
    左: Arc<线段特征>,
    中: Arc<线段特征>,
    右: Arc<线段特征>,
    结构: 分型结构,             // 由左中右三元素分析得出
}
```

#### 中枢 (`algorithm::hub`)
```
中枢 {
    序号: AtomicI64,
    标识: RwLock<String>,       // "笔中枢<0>"/"线段中枢<1>" 等
    级别: AtomicI64,
    基础序列: RwLock<Vec<Arc<虚线>>>,  // 至少3根, 延伸后可达9+
    第三买卖线: RwLock<Option<Arc<虚线>>>,
    本级_第三买卖线: RwLock<Option<Arc<虚线>>>,
}
```
- 属性：`高()` (前三根虚线的最高重叠), `低()` (前三根虚线的最低重叠)
- `文()` → `武()` → `方向()`
- `延伸序列()` → 首尾之外的虚线
- `获取数据文本()` — 完整中枢结构化描述
- `相等()` — 逐项递归校验基础序列和第三买卖线
- 向序列中添加/更新中枢（含显示名称映射）

#### 基础买卖点 (`business::bsp`)
```
基础买卖点 {
    备注: String,
    类型: 买卖点类型,
    买卖点分型: Arc<分型>,
    买卖点K线: Arc<缠论K线>,    // = 买卖点分型.中
    当前K线: Arc<K线>,
    失效K线: Option<Arc<K线>>,
    终结K线: Option<Arc<K线>>,
    破位值: f64,
    结构: Option<分型结构>,
    当前缠K序号: Option<i64>,
}
```
- `偏移()` — 当前缠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<String, f64>),
    单值(HashMap<String, f64>),
}
```

- 预注册默认槽位：`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<f64>,     // 快线EMA - 慢线EMA
    DEA: Option<f64>,     // DIF的信号线EMA
    MACD柱: f64,          // 2 * (DIF - DEA)
    快线EMA: Option<f64>, // 计算中间值（增量用）
    慢线EMA: Option<f64>,
    DEA_EMA: Option<f64>,
}
```

- `首次计算(收盘价, 时间戳, 快线周期, 慢线周期, 信号周期)` — 初始EMA=SMA近似
- `增量计算(prev, 收盘价, 时间戳)` — EMA递推公式
- `计算K线MACD(普K序列, 快, 慢, 信号)` — 遍历序列批量计算

### RSI (`indicators::rsi`, 240 行)

```
相对强弱指数 {
    时间戳, 收盘价, 周期,
    超买阈值, 超卖阈值,
    RSI: Option<f64>,
    RSI_SMA: Option<f64>,  // RSI的SMA信号线
    平均上涨: Option<f64>, // Wilder平滑中间值（增量用）
    平均下跌: Option<f64>,
}
```

- Wilder SMA 平滑算法
- `首次计算()` — 初始均值=SMA
- `增量计算()` — Wilder递推

### KDJ (`indicators::kdj`, 289 行)

```
随机指标 {
    时间戳, 最高价, 最低价, 收盘价,
    RSV周期, K值平滑周期, D值平滑周期,
    超买阈值, 超卖阈值,
    K: Option<f64>,  // RSV的移动平均
    D: Option<f64>,  // K的移动平均
    J: Option<f64>,  // 3*K - 2*D
}
```

- `首次计算(全体)` — 从序列计算初始KDJ值
- `增量计算(全体, 当前, 周期, K平滑, D平滑)` — 增量更新

### BOLL (`indicators::boll`, 169 行)

```
布林带 {
    时间戳, 收盘价, 周期,
    标准差倍数,
    中轨: Option<f64>,  // SMA
    上轨: Option<f64>,  // 中轨 + 倍数 * 标准差
    下轨: Option<f64>,  // 中轨 - 倍数 * 标准差
}
```

---

## 线程安全与并发

### 内部可变性策略

缠K/虚线/中枢等结构体需要在多 `Arc` 共享时支持原地修改（如笔动态替换武、中枢延伸添加虚线）。Rust 中 `Arc` 的 `&self` 是不可变的，因此大量字段使用以下策略实现内部可变性：

| 机制 | 类型 | 适用场景 |
|------|------|---------|
| `SyncF64` | `AtomicU64` 位转换 | 价格字段 (高/低/分型特征值)，需跨线程原子读写 |
| `AtomicI64` | 原子整数 | 序号/时间戳/原始结束序号 |
| `AtomicBool` | 原子布尔 | 有效性/短路修正/特征序列显示 |
| `RwLock<T>` | 读写锁 | 复杂字段 (Arc<分型>/Vec/标识/模式/中枢序列) |

### 全局缓存

- **买卖意义缓存**: `LazyLock<Mutex<LruCache<(usize, usize), (bool, String)>>>` — 128条目，key为 (虚线指针, 观察者指针) 地址对
- **与 Python 对齐**：Python 使用 `@lru_cache(maxsize=128)` 装饰器，Rust 使用全局 `LazyLock<Mutex<>>` 替代 PyO3 的 `thread_local!`（解决跨线程不可见问题）

### Send + Sync 保证

所有核心数据结构（`缠论K线`, `虚线`, `中枢`, `观察者`）均实现 `Send + Sync`，可以安全地跨线程传递和共享：

```rust
// 编译期断言
fn _需要_Send_Sync<T: Send + Sync>() {}
_需要_Send_Sync::<缠论K线>();
_需要_Send_Sync::<虚线>();
_需要_Send_Sync::<中枢>();
```

`观察者` 使用 `Arc<RwLock<观察者>>` 模式，多线程可以并发读取同一个观察者的分析结果。

### 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 图表可视化程序
