diff --git a/README.md b/README.md
index 8695711..4d02335 100644
--- a/README.md
+++ b/README.md
@@ -127,2002 +127,63 @@ easy-tdx serve # 行情终端 + 回测工作台
随便用,随便改,随便分发。
**数据面前,人人平等。**
+
## 项目架构
-七层分层,请求自上而下、数据(pandas DataFrame)自下而上:**① 用户接口层**(Web UI / CLI / Python API / 桌面 EXE)→ **② Web 服务层**(FastAPI + SSE 实时推送 + 异步任务)→ **③ 领域层**(回测 / 指标 / 缠论 / 因子 / 选股 / 组合,纯计算零网络)→ **④ 数据持久层**(DuckDB K 线仓库 + 通达信本地 vipdoc 文件)→ **⑤ 客户端网关层**(8 个客户端 + 健康分 / 故障转移)→ **⑥ 协议层**(通达信二进制协议编解码)→ **⑦ 外部数据源**(通达信服务器 / 中金所 / 新浪 / 巨潮 / LLM)。虚线为旁路直连(HTTP 数据源 / 本地文件 / CLI 与 Python API 越层直调)。
+七层分层,请求自上而下、数据(pandas DataFrame)自下而上:**用户接口层**(Web UI / CLI / Python API / 桌面 EXE)→ **Web 服务层**(FastAPI + SSE 实时推送 + 异步任务)→ **领域层**(回测 / 指标 / 缠论 / 因子 / 选股 / 组合,纯计算零网络)→ **数据持久层**(DuckDB K 线仓库 + 通达信本地 vipdoc 文件)→ **客户端网关层**(8 个客户端 + 健康分 / 故障转移)→ **协议层**(通达信二进制协议编解码)→ **外部数据源**(通达信服务器 / 中金所 / 新浪 / 巨潮 / LLM)。
-🖼️ 交互版架构图(可缩放平移、悬停查看 38 个模块的职责详情、一键导出 PNG):[docs/architecture.html](./docs/architecture.html)
+🖼️ 交互版架构图(38 模块职责详情)+ 源码树 + 分层要点:[docs/architecture.md](./docs/architecture.md) · [architecture.html](./docs/architecture.html)
## 安装
```bash
-pip install easy-tdx
+pip install easy-tdx # 自动注册 easy-tdx CLI 命令
+pip install -e ".[dev]" # 开发模式(测试 / 静态检查工具链)
+pip install -e ".[web]" # Web API 模式(FastAPI + Uvicorn)
```
-安装后自动注册 `easy-tdx` CLI 命令:
+可选依赖分组:`warehouse`(DuckDB 本地 K 线仓库)、`baostock`(通达信全部路径失败时的最后一级兜底数据源,仅日/周/月线,`EASY_TDX_BAOSTOCK=0` 可关闭)、`packaging`(PyInstaller 打包 EXE)。开发环境初始化(uv)与完整开发流程见 [docs/development.md](./docs/development.md)。
-```bash
-easy-tdx --help
-```
-
-开发模式:
-
-```bash
-pip install -e ".[dev]"
-
-# 开发 Web API 模式(含 FastAPI + Uvicorn)
-pip install -e ".[web]"
-```
-
-### 可选:baostock 自动兜底数据源
-
-通达信协议依赖第三方行情服务器,为了"部分兜底、总好过全挂",可选安装 baostock 作为最后一级自动回退:
-
-```bash
-pip install "easy-tdx[baostock]"
-```
-
-装完即自动生效,平时**一次都不会调用**——只有当 MAC 协议与标准协议两条 TDX 路径全部失败或返回空时才启用,响应中会带 `source: "baostock"` 字段标注数据来源。设置环境变量 `EASY_TDX_BAOSTOCK=0` 可随时关闭。边界:baostock 是收盘后更新的数据源(当日数据约 17:30 后才有),因此只兜 **日/周/月 K 线** 的历史数据(覆盖沪深,不含北交所),实时行情、分时、板块等能力仍由通达信协议提供。本地 K 线仓库同步同样支持:`easy-tdx warehouse sync --symbols SH:600519 --source auto|tdx|baostock`(默认 auto)。
-
-## CLI 参考
-
-`easy-tdx` 默认输出 JSON(一行一条记录),`--table` 切换表格,`--output csv` 输出 CSV。
-
-### 基础
-
-```bash
-easy-tdx ping # 服务器测速
-easy-tdx version # 版本号
-```
-
-### 行情
-
-```bash
-# K 线
-easy-tdx kline SZ 000001 --count 30 --table
-easy-tdx kline SH 600519 --period 5MIN --adjust QFQ
-
-# 实时报价
-easy-tdx quote "SZ 000001,SH 600519" --table
-
-# 市场分类报价(按涨幅排序)
-easy-tdx quote-list A --count 20 --table
-easy-tdx quote-list KCB --sort TOTAL_AMOUNT --order ASC
-easy-tdx quote-list CYB --count 50
-```
-
-### 分时 / 成交
-
-```bash
-easy-tdx tick SZ 000001 --table
-easy-tdx tick SH 600519 --days 5
-easy-tdx tick SZ 000001 --date 20250115
-
-easy-tdx transaction SZ 000001 --count 100 --table
-easy-tdx transaction SH 600519 --date 20250115
-```
-
-### 板块
-
-```bash
-easy-tdx board-list --type GN --table
-easy-tdx board-list --type HY --count 200
-easy-tdx board-members 881001 --table
-easy-tdx belong-board SZ 000001 --table
-easy-tdx board-summary 881001 --table # 板块汇总(成交额/主力净流入/涨跌家数)
-easy-tdx board-summary 881001 --members --table # 含成分股明细
-easy-tdx board-ranking --type HY --top 10 --table # 行业板块排行
-easy-tdx board-ranking --type GN --sort-by amount # 概念板块按成交额排行
-
-# 板块 N 日涨跌幅排行(默认全部,支持指定日期)
-easy-tdx board-change-ranking --table # 行业 20 日涨跌幅排行
-easy-tdx board-change-ranking --type GN --days 10 --table # 概念 10 日涨跌幅排行
-easy-tdx board-change-ranking --type HY --date 20250530 --days 20 --table
-easy-tdx board-change-ranking --type HY --top 10 --asc # 行业跌幅前10
-```
-
-### 资金 / 监控
-
-```bash
-easy-tdx capital-flow SH 600519 --table
-easy-tdx auction SZ 000001 --table
-easy-tdx unusual SH --count 100 --table
-easy-tdx market-stat --table
-easy-tdx server-info --table
-easy-tdx symbol-info SZ 000001 --table
-```
-
-### 公告检索(巨潮资讯网)
-
-```bash
-easy-tdx announcement 688017 # 默认 30 条,JSON 输出
-easy-tdx announcement 601088 --count 10 --page 2 # 翻页
-easy-tdx announcement 000001 --table # 表格输出(不截断 url)
-
-# 下载最新 5 条公告的 PDF 到 ./pdfs 目录
-easy-tdx announcement 601088 --count 5 --download 5 --download-dir ./pdfs
-```
-
-> 独立数据源(巨潮资讯网),无需连接 TDX 行情服务器即可使用。
-> 返回的 ``url`` 含 4 参数可直接打开,``pdf_url`` 为 PDF 直链。
-
-### 中金所成交持仓排名(v1.29.1)
-
-```bash
-easy-tdx ccpm IF --table # 最近有数据的交易日(缺省自动回溯)
-easy-tdx ccpm IF --date 2026-09-02 # 指定交易日
-easy-tdx ccpm all --date 2026-08-28 --table # 全部 8 个品种一次抓取
-easy-tdx ccpm TL --refresh # 忽略本地缓存,强制重新抓取
-```
-
-> 独立数据源(中金所官网),无需连接 TDX 行情服务器。品种:IF 沪深300 / IH 上证50 / IC 中证500 / IM 中证1000 股指期货,TS/TF/T/TL 为 2/5/10/30 年期国债期货。
-> 每个交易日收盘后约 16:15 发布,含该品种**全部合约 × 三类排名(成交量 / 持买单量·多单 / 持卖单量·空单)× 各前 20 名会员**;
-> 数据发布后不可变,按日缓存到 `~/.easy_tdx/cache/ccpm/`,历史二次查询零网络。
-> JSON 输出为英文列名(vol/long_pos/short_pos 等,机器友好),`--table` 自动切换中文表头。
-> WebUI 对应「期货持仓排名」页(含新手科普),API 为 `GET /api/v1/ccpm/rank`。
-
-### 技术指标
-
-```bash
-easy-tdx indicator-list --table # 列出所有可用指标
-easy-tdx indicator MACD -m SH -c 600519 --table # MACD
-easy-tdx indicator KDJ -m SZ -c 000001 --table # KDJ
-easy-tdx indicator RSI -m SH -c 600519 --table # RSI
-easy-tdx indicator BOLL -m SH -c 600519 --table # BOLL 布林带
-easy-tdx indicator DMI -m SH -c 600519 --table # DMI 动向指标
-easy-tdx indicator ATR -m SH -c 600519 --table # ATR 真实波幅
-easy-tdx indicator WR -m SH -c 600519 --table # WR 威廉指标
-easy-tdx indicator CCI -m SH -c 600519 --table # CCI 顺势指标
-easy-tdx indicator BIAS -m SZ -c 000001 --table # BIAS 乖离率
-easy-tdx indicator BIAS_SIGNAL -m SH -c 600519 --table # 30日乖离率信号
-easy-tdx indicator OBV -m SZ -c 000001 --table # OBV 能量潮
-
-# 多指标同时计算
-easy-tdx indicator MACD,KDJ,RSI,BOLL -m SH -c 600519 --count 10 --table
-
-# 自定义参数
-easy-tdx indicator MACD -m SH -c 600519 --params SHORT=10,LONG=22
-
-# 分钟线指标
-easy-tdx indicator MACD -m SH -c 600519 --period 5MIN --count 50
-
-# 仅输出指标值(不含 OHLCV)
-easy-tdx indicator RSI -m SZ -c 000001 --no-ohlcv
-```
-
-### 缠论分析
-
-基于缠论理论的技术分析,计算管道:`K 线合并 → 分型识别 → 笔 → 中枢 → 线段 → 买卖点 → 背驰`。默认输出 JSON,加 `--table` 输出可读表格。
-
-```bash
-easy-tdx chanlun SZ 000001 --table
-easy-tdx chanlun SH 600519 --adjust QFQ --table
-easy-tdx chanlun SZ 000001 --period 30MIN
-
-# 多级别联立:分析日线最后一笔在 30 分钟级别中的走势结构
-easy-tdx chanlun SZ 000001 --multi-level 30MIN --table
-easy-tdx chanlun SH 600519 --multi-level 5MIN
-```
-
-#### 输出示例
-
-以 `easy-tdx chanlun SH 601088 --table` 为例,输出分五个部分:
-
-**概要统计**
-
-```
-标的: 601088 周期: DAILY
-原始K线: 800 缠论K线: 589
-分型: 275 笔: 131 中枢: 21 线段: 40
-买卖点: 125 背驰: 73
-```
-
-| 字段 | 含义 |
-|------|------|
-| 原始 K 线 | 从服务端获取的原始 K 线条数 |
-| 缠论 K 线 | 经过包含处理(合并)后的 K 线条数,数量一定 ≤ 原始 K 线 |
-| 分型 | 识别出的顶分型 + 底分型总数 |
-| 笔 | 相邻两个异向分型之间的连线(涨跌方向交替) |
-| 中枢 | 至少 3 笔重叠区域形成的密集成交区间 |
-| 线段 | 由笔构成的更大级别走势单位 |
-| 买卖点 | 一二三类买卖点信号总数 |
-| 背驰 | 力度衰减信号总数(笔背驰 / 盘整背驰 / 趋势背驰) |
-
-**笔**
-
-```
-[0] ↑ 2023-02-17 → 2023-02-23 h=28.46 l=26.76 ✓
-[1] ↓ 2023-02-23 → 2023-02-28 h=28.46 l=27.8 ✓
-[2] ↑ 2023-02-28 → 2023-03-09 h=29.77 l=27.8 ✓
-```
-
-笔是缠论的基本走势单位。每条笔连接一个顶分型和一个底分型,方向严格交替(↑↓↑↓…)。`✓` 表示已确认(后续出现了反向笔),`…` 表示仍在进行中。
-
-- `↑`:向上笔,起点是底分型(低点),终点是顶分型(高点)
-- `↓`:向下笔,起点是顶分型(高点),终点是底分型(低点)
-- `h`/`l`:该笔范围内的最高价 / 最低价
-
-**中枢**
-
-```
-[0] zg=28.46 zd=28.11 gg=32.56 dd=26.76 lines=11 ✓
-[1] zg=31.2 zd=30.45 gg=32.56 dd=27.9 lines=3 ✓
-```
-
-中枢是至少 3 笔重叠形成的密集成交区间,代表多空博弈的平衡区域。`✓` 表示已脱离,`…` 表示价格仍在中枢区间内震荡。
-
-| 字段 | 含义 |
-|------|------|
-| `zg` | 中枢上沿(区间内最高的低点)— 支撑/压力的关键分界 |
-| `zd` | 中枢下沿(区间内最低的高点) |
-| `gg` | 中枢区间内的最高价 |
-| `dd` | 中枢区间内的最低价 |
-| `lines` | 构成该中枢的笔数,笔数越多代表震荡越充分 |
-
-中枢的意义:价格在中枢内震荡 → 突破中枢上沿看涨,跌破下沿看跌。`zg`/`zd` 是实战中最常用的参考价位。
-
-**线段**
-
-```
-[0] ↑ 2023-02-17 → 2023-03-09 h=29.77 l=26.76
-[1] ↓ 2023-02-28 → 2023-03-29 h=29.77 l=27.18
-```
-
-线段是比笔更大的走势单位,由多笔重叠组合而成。线段的方向不严格交替,可能出现连续同向(如连续多段向上),代表更高一级的趋势方向。实战中通常在线段级别判断大方向,在笔级别找买卖点。
-
-**买卖点**
-
-```
-1buy: 中枢下方力度衰减,一类买点 (l=27.30 < zd=46.72)
-2buy: 回调不创新低,二类买点 (l=27.33)
-3buy: 回调不破中枢上沿,三类买点 (l=27.80 > zg=27.58)
-1sell: 中枢上方力度衰减,一类卖点 (h=50.38 > zg=46.97)
-2sell: 反弹不创新高,二类卖点 (h=29.32)
-3sell: 反弹不破中枢下沿,三类卖点 (h=28.46 < zd=46.72)
-```
-
-缠论定义三类买点和三类卖点:
-
-| 类型 | 买点含义 | 卖点含义 |
-|------|----------|----------|
-| 一类 | 下跌趋势末端,力度衰减后的第一个低点(抄底) | 上涨趋势末端,力度衰减后的第一个高点(逃顶) |
-| 二类 | 一类买点后的回调不创新低(确认反转) | 一类卖点后的反弹不创新高(确认反转) |
-| 三类 | 回调不进入中枢上沿(趋势确认,中枢上方买) | 反弹不进入中枢下沿(趋势确认,中枢下方卖) |
-
-括号内的条件是该信号的触发依据,如 `l=27.80 > zg=27.58` 表示回调低点 27.80 高于中枢上沿 27.58,所以是三类买点。
-
-**背驰**
-
-```
-[✓] bi: 笔背驰: 笔[4] 力度=1.32 < 笔[2] 力度=1.97
-[✓] pz: 盘整背驰: 中枢[11] 内末笔力度=2.49 < 首笔力度=6.64
-[✓] qs: 趋势背驰(上): 中枢[1] 离开力度=3.32 < 中枢[0] 离开力度=4.45
-```
-
-背驰是力度衰减信号,表明当前走势动力正在减弱,可能即将反转。力度通过 MACD 面积计算,数值越小力度越弱。
-
-| 类型 | 含义 |
-|------|------|
-| `bi`(笔背驰) | 同向相邻两笔比较,后一笔力度 < 前一笔 → 该方向动力减弱 |
-| `pz`(盘整背驰) | 同一中枢内,末笔力度 < 首笔 → 中枢内动力衰减,即将突破 |
-| `qs`(趋势背驰) | 两个同向中枢之间比较,后一中枢离开力度 < 前一中枢 → 趋势可能终结 |
-
-`[✓]` 表示确认背驰。趋势背驰(上)代表上涨趋势可能结束,趋势背驰(下)代表下跌趋势可能结束。
-
-### 回测引擎
-
-> 📖 **完整使用手册**:[docs/backtest_usage.md](docs/backtest_usage.md) ——
-> 涵盖策略编写(`init()`/`next()`)、行情数据访问、指标注册、订单模拟、
-> 绩效指标、组合回测、调仓引擎与完整示例。回测相关用法以该手册为准。
-
-内置向量回测引擎,加载 Python 策略文件即可跑回测。策略继承 `Strategy` 基类,在 `init()` 注册指标,在 `next()` 逐 bar 生成买卖信号,引擎完成订单模拟、持仓跟踪和绩效分析。
-
-**单策略回测:**
-
-```bash
-easy-tdx backtest SZ 300308 --strategy-file strategies/expma_cross.py --count 2000 --cash 1000000 --adjust QFQ --table
-# 推荐加上 --slippage 0.01 模拟真实滑点(元/股),使回测更贴近实盘
-
-# 缠论自动桥接:引擎自动计算缠论分析并注入策略 self.chanlun
-easy-tdx backtest SZ 000001 --strategy-file strategies/chanlun_strategy.py --chanlun-level DAILY --table
-```
-
-**样本外验证(v1.25):**
-
-```bash
-# 附加 Walk-Forward 七窗样本外验证(每窗独立开仓,窗口数可调)
-easy-tdx backtest SZ 300308 --strategy-file strategies/expma_cross.py --wf --wf-windows 7
-
-# 一条龙评估:回测 + WF + 适配性体检 + 综合评分 + S-D 评级 + 买入持有基准对比
-easy-tdx backtest SZ 300308 --strategy-file strategies/expma_cross.py --evaluate
-```
-
-输出示例:
-
-```
-=== 回测绩效概要 ===
-总收益率: 1413.51%
-年化收益: 40.85%
-最大回撤: 76.75%
-夏普比率: 0.88
-胜率: 20.8%
-交易次数: 24
-```
-
-> ⚠️ **回测 ≠ 实盘**。以上收益率为历史数据回测结果,包含幸存者偏差和过拟合风险,
-> 不构成投资建议。实际交易需考虑滑点、流动性、涨跌停无法成交等因素。
-> 请在充分理解策略逻辑后谨慎使用。
-
-**参数网格寻优(optimize)与内置策略列表(strategies):**
-
-```bash
-# 列出全部内置策略(名称/参数默认值/预设寻优网格)
-easy-tdx strategies
-
-# 单策略网格寻优(预设网格或 --param 自定义,--workers 4 进程并行)
-easy-tdx optimize SZ 000001 --strategy ma_cross
-easy-tdx optimize SZ 000001 --strategy ma_cross --param fast=5,10,15 --param slow=20,60
-
-# 一键寻优所有内置策略:逐策略按预设网格寻优后全局排名(对应 Web UI /optimize 页)
-easy-tdx optimize SZ 000001 --all --workers 4 --table
-```
-
-**全策略批量对比(CLI):**
-
-`easy-tdx run-all` 一行命令跑完 `strategies/` 下所有策略并排名:
-
-```bash
-easy-tdx run-all SZ 300308 --count 2000 --cash 1000000 --adjust QFQ
-
-# 多因子组合回测
-easy-tdx run-all SZ 300308 --combo 2 --combo-mode MAJORITY
-
-# 加 --show 自动弹出最佳策略的资金曲线 vs 股价对比图
-easy-tdx run-all SZ 300308 --count 2000 --cash 1000000 --adjust QFQ --show
-
-# 自定义策略目录
-easy-tdx run-all SZ 300308 --strategies-dir my_strategies/
-```
-
-也可使用项目自带的 `run_all_strategies.py` 脚本(功能相同):
-
-```bash
-python -X utf8 run_all_strategies.py SZ 300308 --count 2000 --cash 1000000 --adjust QFQ
-
-# 加 --show 自动弹出最佳策略的资金曲线 vs 股价对比图
-python -X utf8 run_all_strategies.py SZ 300308 --count 2000 --cash 1000000 --adjust QFQ --show
-```
-
-**多因子组合回测:**
-
-自动遍历所有 2 因子 / 3 因子组合,找到最优搭配:
-
-```bash
-# 自动寻找最佳 2 因子和 3 因子组合(MAJORITY 模式)
-python -X utf8 run_all_strategies.py SZ 300308 --combo 2 --combo 3 --combo-mode majority
-
-# CLI 方式
-easy-tdx run-all SZ 300308 --combo 2 --combo 3 --combo-mode majority
-```
-
-CLI 指定策略文件组合:
-
-```bash
-easy-tdx backtest SZ 000001 \
- --combo-strategies strategies/macd_cross.py,strategies/rsi_reversal.py,strategies/bollinger_breakout.py \
- --combo-mode majority --table
-```
-
-Python API:
-
-```python
-from easy_tdx.backtest import CombinationRunner
-
-runner = CombinationRunner(
- strategy_classes=[MACDStrategy, RSIStrategy, BollingerStrategy],
- df=df, cash=100000,
-)
-results = runner.screen(combo_sizes=(2, 3), mode="MAJORITY")
-for r in results[:5]:
- print(f"{r.name}: 收益={r.result.performance['total_return']:.2%}")
-```
-
-信号合并模式:
-
-| 模式 | 买入条件 | 卖出条件 | 特点 |
-|------|---------|---------|------|
-| `AND` | 所有因子都看多 | 所有因子都看空 | 极保守,交易少但精确 |
-| `MAJORITY` | 过半因子看多 | 过半因子看空 | 平衡,推荐默认 |
-| `OR` | 任一因子看多 | 任一因子看空 | 激进,信号多噪声大 |
-
-`--show` 会用 matplotlib 弹出一个双轴对比窗口:左轴蓝色线是归一化股价,右轴红色线是最佳策略的资金曲线,绿三角=买入、黄三角=卖出,标题显示股票名称和关键绩效指标。需要 `pip install matplotlib`。
-
-**多标的组合回测(portfolio):**
-
-`easy-tdx portfolio` 对多只股票同时回测,共享资金池,按均等比例分配,汇总组合整体绩效:
-
-```bash
-# 两只股票组合回测
-easy-tdx portfolio --stocks SZ:000001,SH:600519 --strategy-file strategies/ma_cross.py --table
-
-# 自定义资金和周期
-easy-tdx portfolio --stocks SZ:000001,SH:600519,SH:600036 \
- --strategy-file strategies/expma_cross.py --cash 500000 --period DAILY --count 1000 --table
-
-# 搭配缠论桥接
-easy-tdx portfolio --stocks SZ:000001,SH:600519 \
- --strategy-file strategies/chanlun_strategy.py --chanlun-level DAILY --table
-
-# 组合级 Walk-Forward / 一条龙评估(与 Web UI /portfolio 页同构)
-easy-tdx portfolio --stocks SZ:000001,SH:600519 \
- --strategy-file strategies/ma_cross.py --wf --wf-windows 7
-easy-tdx portfolio --stocks SZ:000001,SH:600519 \
- --strategy-file strategies/ma_cross.py --evaluate
-```
-
-输出示例:
-
-```
-=== 组合回测绩效概要 ===
-标的数量: 3
-总资金: 200,000
-组合收益率: 28.50%
-组合年化: 28.50%
-
-── 各标的详情 ──
- SZ000001: 收益=35.20% 夏普=0.92 回撤=15.30% 分配=33% 交易=12
- SH600519: 收益=18.40% 夏普=0.68 回撤=8.50% 分配=33% 交易=8
- SH600036: 收益=31.90% 夏普=0.85 回撤=12.10% 分配=33% 交易=15
-```
-
-| 参数 | 说明 |
-|------|------|
-| `--stocks` | 股票列表:逗号分隔的 `市场:代码`(如 `SZ:000001,SH:600519`) |
-| `--cash` | 总资金(默认 20 万) |
-| `--allocation` | 资金分配方式(目前支持 `equal` 均等分配) |
-| `--chanlun-level` | 自动计算缠论分析并注入策略(如 DAILY/30MIN) |
-
-### 通达信公式(v1.27)
-
-粘贴通达信公式即可计算 / 选股 / 回测——命名布尔输出自动成为买卖信号(名字含「买/卖」或 BUY/SELL 优先),30+ 白名单函数(MA/EMA/SMA/HHV/LLV/REF/CROSS/LONGCROSS/MACD/KDJ/RSI/BOLL/ATR…)向量化求值,无未来数据:
-
-```bash
-# 公式计算(最后一根各列值 + 最近信号明细)
-easy-tdx formula compute SH 600519 --formula "金叉: CROSS(MA(C,5), MA(C,20));"
-
-# 批量选股:信号在最后一根 = 1 的标的(--symbols 支持逗号分隔或 @文件)
-easy-tdx formula screen --symbols SH:600519,SZ:000001 --formula "金叉: CROSS(MA(C,5), MA(C,20));"
-
-# 公式回测:买/卖列自动挑选,信号下一根开盘成交,输出绩效 + 评级 + 评分
-easy-tdx formula backtest SH 600519 --file my_formula.txt
-```
-
-### 本地 K 线仓库(v1.26)
-
-行情沉淀为 DuckDB 单文件列存(可选依赖:`pip install easy-tdx[warehouse]`),增量同步 + 临时收盘价状态机 + 健康自检:
-
-```bash
-easy-tdx warehouse sync --symbols SH:600519,SZ:000001 # 首次全量,此后只补尾部
-easy-tdx warehouse query SH 600519 --count 30 # 默认忽略未收盘的临时 bar
-easy-tdx warehouse stats # 各标的行数 / 数据范围
-easy-tdx warehouse check # 缺口 / 除权跳变 / 新鲜度体检
-```
-
-**行情终端 + 回测可视化 Web UI(v1.17 新增,v1.23 升级为行情终端):**
-
-
-
-
-
-
-
-不想写命令行?用浏览器。`easy-tdx serve` 一条命令启动,浏览器自动打开 `http://localhost:8000`。
-
-Web UI 包含两大模块:
-
-- **行情终端**——侧边栏专业终端布局(行情:市场看板 / 行业总览 / 概念总览 / 自选行情 / 龙头池 / 期货持仓排名):
- - **市场看板**:五大指数实时行情(SSE 推送)、全市场涨跌统计(涨/跌/平/涨停/跌停 + 堆叠条)、行业/概念板块热度榜、涨幅榜/跌幅榜、两市异动雷达(加速拉升/封涨停板/大单托盘等),点击个股打开五档盘口 + 分时/日K 对话框;
- - **行业总览 / 概念总览**(v1.32.1):全部行业(一级/二级可切)/概念板块一屏尽览——板块广度统计条、涨跌幅分布直方图、热力图与表格双视图、搜索过滤、涨幅/跌幅/涨速异动三榜、翻红/翻绿轮动时间线,30s 自动刷新(休市暂停);点击板块复用详情弹窗(分时/日K + 成分股涨跌榜直达个股);
- - **自选行情**:输入 6 位代码一键加自选(SQLite 持久化),全表实时刷新(SSE),行内迷你分时图,点击行看个股详情;
- - **龙头池**:159 只核心龙头名单一键只扫龙头(名单仅为扫描范围,不构成任何推荐);
- - **期货持仓排名**(v1.29.1):中金所每日成交/持仓前 20 名会员一键采集(品种下拉 + 日期选择 + 自动回溯最近交易日开关),合约页签自动标注主力,前 20 名合计多单/空单/净持仓概览,三组排名并排表格;附「品种一览」「多单空单加减仓怎么看」新手科普(重点:排名看不出套保还是投机,空单多 ≠ 看空市场);
- - **实时推送架构**:后端单条轮询循环 fan-out 到所有 SSE 连接(交易时段 ~8s 一拍,盘外降频 60s,无人订阅自动休眠),前端指数退避重连。
-- **回测工作台**——浏览器里选标的、挑策略、调参数,K 线买卖点、净值回撤、25 项绩效指标一目了然。支持组合回测、参数网格寻优、多策略结果对比、策略库(SQLite 持久化)与多策略资金分仓、信号雷达、Walk-Forward / 一条龙附加分析、**AI 解读与解读历史**(分析:单标的回测 / 组合回测 / 参数寻优 / 结果对比 / 策略库 / 信号雷达 / AI 解读历史),全程零代码。
-
-**前置条件:**
-
-```bash
-# 需安装 web 可选依赖(FastAPI + Uvicorn)
-pip install -e ".[web]"
-```
-
-**启动(一条命令):**
-
-```bash
-# 启动后端 + 自动打开浏览器(默认 http://localhost:8000)
-easy-tdx serve
-
-# 自定义端口/不自动开浏览器
-easy-tdx serve --port 8080 --no-open-browser
-```
-
-> 后端启动后约 1-2 秒会自动弹出浏览器。前端界面已编译进 `web-ui/dist/`,由后端同源托管,无需单独跑前端开发服务器。后端行情连接失败时回测路由仍可用(用内联数据),但取行情功能需要后端连通通达信服务器。
-
-**不想装 Python?下载 EXE 直接用(面向零基础用户):**
-
-Windows 用户可以下载打包好的单一 EXE(约 80-150MB),双击即可使用,无需安装 Python/Node 或任何依赖:
-
-1. 到 [Releases 页面](../../releases) 下载最新的 `easy-tdx-<版本>-windows.exe`
-2. 双击运行(首次会被 SmartScreen 拦截,点"更多信息 → 仍要运行")
-3. 等待 2-5 秒,浏览器自动打开回测界面
-4. 右下角任务栏出现小图标,右键 → "退出" 可关闭
-
-EXE 打包方法见 [`docs/packaging.md`](./docs/packaging.md)。
-
-打开浏览器后,「分析」分组下是回测工作台的核心页面:
-
-**1. 单标的回测**(首页 `/`)
-
-左侧配置面板从上到下填写,右侧自动出图:
-
-- **取行情**:选市场(深/沪/北),填 6 位代码,选周期(日线/周线/分钟线),设日期范围(默认最近 3 年),点「取行情」。超过 800 根会自动翻页拼接
-- **选策略**:下拉选 18 个内置策略之一(双均线交叉、MACD、布林带、RSI、KDJ、唐安奇通道、CCI 等),选中后参数表单自动出现,按推荐范围调参
-- **资金与成本**:初始资金、佣金率、滑点、成交模式(默认 next_open 下一根开盘成交)
-- 点「开始回测」,右侧依次出:K 线主图(红三角=买入、绿钉=卖出)、净值曲线与回撤双轴图、25 项绩效指标表(总收益/夏普/最大回撤/胜率/盈亏比/Ulcer/VaR/SQN 等)、成交记录明细
-- 结果区右上角有「💾 保存策略」按钮,把当前策略 + 标的 + 成绩快照存进策略库,下次直接载入或参与组合回测
-
-**2. 组合回测**(`/portfolio`)
-
-- 添加多只标的(如 SZ:000001、SH:600519),选策略和日期范围
-- 点「开始组合回测」,右侧出:组合整体绩效(加权收益率)、组合净值曲线(各标的按日期对齐求和)、各标的净值归一化叠加对比图、各标的绩效横向对比表
-- 同样有「保存策略」按钮,可把整个组合配置存进策略库
-
-**3. 参数寻优**(`/optimize`)
-
-- 先取行情(同单标的),选策略
-- 勾选 1-2 个想寻优的参数,填入取值列表(逗号分隔,如 fast 填 `5,10,20,30`),页面实时显示网格点数(上限 200)
-- 点「开始寻优」,右侧出:最优结果摘要、参数热力图(2 参数时,颜色映射收益率)、所有网格点排名表
-- 排名表每行有「查看」按钮,点击跳转单标的回测页,自动填充该参数组合跑完整回测
-
-**4. 结果对比**(`/compare`)
-
-- 左侧列出最近 20 个已完成的回测任务(含单标的和组合)
-- 勾选 2-4 个,右侧出:归一化净值叠加图(初始=1,看相对走势)、8 项核心指标横向对比表(总收益/夏普/最大回撤/胜率/盈亏比/交易数/年化/波动率)
-
-**5. 策略库**(`/strategies`,v1.17.11 新增)
-
-- 保存你觉得不错的策略,下次直接载入或重跑。数据存在本地 SQLite 单文件(`~/.easy_tdx/strategies.db`,重启不丢)
-- 每张卡片展示策略名、标的、保存时的成绩快照(总收益/夏普/回撤)、标签、备注、创建时间
-- **载入**:点「载入」跳转对应回测页(单标的/组合),自动回填标的、日期、策略参数,可直接重跑
-- **多策略组合回测**:勾选多个单标的策略(卡片左上角复选框),点顶部「组合回测(N)」——每个策略各拿 1/N 资金、各跑在它保存时的原标的上(取最新行情),净值曲线按日期对齐求和,看综合表现。结果区展示:组合净值曲线、25 项完整绩效指标(与单标的同口径)、各策略绩效对比表、净值叠加图、各策略当前持仓表(回测结束时谁还套着票)
-
-> ⚠️ **任务不持久化**:回测结果存在后端进程内存,重启 `easy-tdx serve` 后清空。对比页只能选当前运行期间产生的任务。**策略库除外**——保存到策略库的策略持久存在 SQLite,重启不丢。
-
-技术栈:Vue 3 + Vite + TypeScript + Pinia + ECharts(按需引入,构建产物约 800KB)。前端代码在 `web-ui/` 目录,独立 `package.json`,不依赖 Python 环境。
-
-
-
-```
-发现 9 个策略文件
-标的: SZ 300308 | K线: 2000 | 资金: 1,000,000 | 复权: QFQ
-================================================================================
-
->> 运行策略: bias_reversal ... 完成 (2.4s)
->> 运行策略: bollinger_breakout ... 完成 (0.6s)
->> 运行策略: expma_cross ... 完成 (0.6s)
->> 运行策略: kdj_golden ... 完成 (0.1s)
->> 运行策略: ma_cross ... 完成 (1.4s)
->> 运行策略: macd_cross ... 完成 (2.1s)
->> 运行策略: rsi_reversal ... 完成 (0.2s)
->> 运行策略: turtle_breakout ... 完成 (0.1s)
->> 运行策略: volume_price ... 完成 (6.3s)
-
-================================================================================
-[*] 策略绩效排名 (按总收益率降序)
-================================================================================
- 排名 策略 总收益率 年化收益 最大回撤 夏普 胜率 交易次数 盈亏比
-----------------------------------------------------------------------------------------------------
- *1* 1 expma_cross 1413.51% 40.85% 76.75% 0.88 20.8% 24 6.45
- *2* 2 ma_cross 1258.07% 38.94% 58.01% 0.87 38.2% 55 2.21
- *3* 3 turtle_breakout 905.07% 33.76% 48.30% 0.83 75.0% 4 10.14
- 4 bias_reversal 504.94% 25.47% 42.25% 0.70 66.3% 95 2.08
- 5 macd_cross 387.67% 22.11% 61.08% 0.60 40.0% 85 2.20
- 6 volume_price 247.72% 17.01% 65.73% 0.50 43.3% 254 1.40
- 7 bollinger_breakout 169.65% 13.32% 49.71% 0.44 66.7% 24 1.93
- 8 rsi_reversal 95.89% 8.85% 56.51% 0.33 57.1% 7 2.48
- 9 kdj_golden 89.10% 8.36% 61.86% 0.32 66.7% 3 10.49
-```
-
-综合评分(夏普 × 0.4 + 收益/回撤 × 0.3 + 胜率 × 0.3):
-
-```
- *1* 1 turtle_breakout 23.04 0.83 0.70 75.0%
- *2* 2 bias_reversal 20.35 0.70 0.60 66.3%
- *3* 3 bollinger_breakout 20.26 0.44 0.27 66.7%
-```
-
-换一个标的再跑:
-
-```bash
-# 贵州茅台
-python -X utf8 run_all_strategies.py SH 600519 --count 2000 --cash 1000000 --adjust QFQ
-```
-
-#### `--show` 可视化效果
-
-
- 
- SH601088 中国神华 — bollinger_breakout 策略 | 收益 1281.8%
-
-
-
- 
- SH600522 中天科技 — kdj_golden 策略 | 收益 568.6%
-
-
-
- 
- SH601179 中国西电 — expma_cross 策略 | 收益 168.0%
-
-
-
- 
- SH600519 贵州茅台 — bollinger_breakout 策略 | 收益 187.0%
-
-
-> **⚠️ Demo 展示,不作为操作依据。** 历史回测收益不代表未来表现,策略参数未经过样本外验证。
-
-#### 自带策略示例
-
-`strategies/` 目录下有 16 个开箱即用的策略文件,可直接用于 `--strategy-file`:
-
-| 文件 | 策略 | 类型 | 适合行情 |
-|------|------|------|----------|
-| `ma_cross.py` | 双均线交叉(MA5/MA20) | 趋势跟踪 | 单边趋势 |
-| `expma_cross.py` | EMA12/EMA50 交叉 | 趋势跟踪 | 单边趋势(比 MA 更灵敏) |
-| `macd_cross.py` | MACD 金叉死叉 | 趋势跟踪 | 中长线趋势 |
-| `bollinger_breakout.py` | 布林带突破 | 震荡反转 | 横盘震荡 |
-| `rsi_reversal.py` | RSI 超买超卖 | 反转 | 震荡市 |
-| `kdj_golden.py` | KDJ 低位金叉/高位死叉 | 反转 | 短线震荡 |
-| `turtle_breakout.py` | 海龟交易法(唐安奇通道) | 趋势突破 | 牛市启动 |
-| `bias_reversal.py` | 乖离率反转 | 反转 | 震荡回归 |
-| `volume_price.py` | 量价配合 | 综合判断 | 放量突破 |
-| `zhuoyao_momentum.py` | 捉妖大师多周期共振 | 趋势跟踪 | 多周期共振强势股 |
-| `dmi_trend.py` | DMI/ADX 趋势强度跟踪 | 趋势跟踪 | 单边趋势(过滤震荡) |
-| `cci_breakout.py` | CCI ±100 区间突破 | 区间突破 | 震荡转趋势 |
-| `mfi_volume.py` | MFI 量价反转 | 量价反转 | 震荡市(带量能确认) |
-| `trix_cross.py` | TRIX 三重平滑趋势交叉 | 趋势跟踪 | 中长线(抗噪音) |
-| `mtm_momentum.py` | MTM 动量零线穿越 | 动量 | 趋势拐点 |
-| `obv_trend.py` | OBV 能量潮趋势 | 量价趋势 | 资金持续流入的上升趋势 |
-
-编写自定义策略只需继承 `Strategy` 基类:
-
-```python
-from easy_tdx.backtest import Strategy
-from easy_tdx import MyTT
-
-
-class MyStrategy(Strategy):
- def init(self):
- self.ma = self.I(MyTT.MA, self.data.close, 10)
-
- def next(self):
- if self.data.close[0] > self.ma[self._bar_index]:
- self.buy(size=0) # size=0 表示全仓
- elif self.position["size"] > 0:
- self.sell(size=0) # size=0 表示清仓
-```
-
-完整 API 参考:[docs/backtest_usage.md](docs/backtest_usage.md)
-
-### 量化因子与组合管理
-
-新增三大模块:**因子引擎**(19 个内置因子 + 自定义扩展)、**因子分析**(IC/分层/衰减)、**组合管理**(4 种优化器 + 再平衡引擎)。加上**高级回测增强**:可插拔滑点模型(方根冲击/成交量比例)、执行仿真(TWAP/VWAP/限价单)、归因分析(Brinson + 因子归因)。
-
-```python
-from easy_tdx.factor import FactorEngine, FactorAnalyzer, preprocess
-from easy_tdx.portfolio import RebalanceEngine, FactorWeightedOptimizer
-from easy_tdx.backtest import BacktestEngine
-from easy_tdx.backtest.slippage import SquareRootSlippage
-from easy_tdx.backtest.execution import TWAPExecution
-
-# 因子研究
-engine = FactorEngine()
-factor_data = engine.compute_cross_section(data, ["momentum_20d", "rsi_14"])
-clean = preprocess(factor_data, ["momentum_20d", "rsi_14"])
-forward_returns = engine.compute_forward_returns(data, period=5)
-report = FactorAnalyzer(clean, forward_returns).full_report("momentum_20d")
-print(f"IC均值={report.mean_ic:.4f} ICIR={report.icir:.4f}")
-
-# 组合回测
-result = RebalanceEngine(
- FactorWeightedOptimizer(), factor_name="momentum_20d", n_stocks=50, cash=1_000_000,
-).run(data, start_date=20230101, end_date=20240101)
-print(f"年化={result.performance['annual_return']:.2%}")
-
-# 高级回测(滑点 + 执行仿真)
-engine = BacktestEngine(
- MyStrategy, cash=1_000_000,
- slippage_model=SquareRootSlippage(impact_coeff=0.1),
- execution_model=TWAPExecution(n_bars=3),
-)
-```
-
-详细用法和完整工作流示例:**[docs/quantitative-guide.md](docs/quantitative-guide.md)**
-
-### 策略选股扫描(screen)
-
-把策略翻转成选股器:给定一个策略,扫描全市场找出今天触发买入信号的股票,再对这些信号做历史回测排名。**纯离线数据**,读取本地通达信 `.day` 文件,全市场约 30-60 秒。
-
-两步走工作流:
-
-**第一步:信号扫描(scan)**
-
-```bash
-# 扫描沪深全 A,找出 RSI 超卖触发的股票
-easy-tdx screen scan --strategy strategies/rsi_reversal.py --output signals.json
-
-# 缩小范围
-easy-tdx screen scan --strategy strategies/macd_cross.py --universe sz --output signals.json
-
-# 从自定义股票列表扫描
-easy-tdx screen scan --strategy strategies/bollinger_breakout.py --universe my_stocks.txt --output signals.json
-
-# 并发扫描(推荐 4-8 进程,速度提升 4-8 倍)
-easy-tdx screen scan --strategy strategies/rsi_reversal.py --workers 4 --output signals.json
-
-# 增量扫描(缓存未修改的 .day 文件,跳过重复计算)
-easy-tdx screen scan --strategy strategies/rsi_reversal.py --cache scan_cache.json --output signals.json
-```
-
-输出示例(JSON):
-
-```json
-{
- "scan_time": "2026-06-10T18:30:00",
- "strategy": "RSIStrategy",
- "total_scanned": 4832,
- "total_signals": 37,
- "signals": [
- {"code": "000001", "market": "SZ", "signal_date": 20260610, "last_close": 12.35},
- {"code": "600519", "market": "SH", "signal_date": 20260610, "last_close": 1800.0}
- ]
-}
-```
-
-**第二步:回测排名(rank)**
-
-```bash
-# 按夏普比率排名(默认)
-easy-tdx screen rank --from signals.json --sort sharpe --top 20 --table
-
-# 按最大回撤排名(越小越好,用 --sort-reverse)
-easy-tdx screen rank --from signals.json --sort max_drawdown --sort-reverse --table
-
-# 管道模式:一步到位
-easy-tdx screen scan --strategy strategies/rsi_reversal.py | easy-tdx screen rank --from - --table
-
-# 补齐股票名称(需要网络)
-easy-tdx screen rank --from signals.json --sort sharpe --top 10 --table --names
-```
-
-输出示例(`--table`):
-
-```
-[*] 信号排名 (按 sharpe 降序, 共 37 只)
-══════════════════════════════════════════════════════════════════════════
-排名 代码 名称 总收益率 年化收益 最大回撤 夏普 胜率 交易
- *1 SZ300308 中际旭创 45.23% 18.72% 12.35% 1.85 62.5% 16
- *2 SH600519 贵州茅台 38.10% 15.90% 8.21% 1.62 58.3% 12
-```
-
-| 参数 | 说明 |
-|------|------|
-| `--universe` | `all`(默认,沪深全 A)/ `sh` / `sz` / 文件路径(每行 "市场 代码") |
-| `--vipdoc` | 离线数据目录(默认自动检测通达信安装路径) |
-| `--workers` | 并发进程数:`0` 串行(默认)/ `2+` ProcessPoolExecutor 并发(推荐 4-8) |
-| `--cache` | 增量扫描缓存文件路径(JSON,mtime 未变的文件自动跳过) |
-| `--sort` | 排序指标:`sharpe`(默认)/ `total_return` / `max_drawdown` / `win_rate` 等 |
-| `--sort-reverse` | 升序(用于回撤等越小越好的指标) |
-| `--names` | 在线补齐股票名称(默认关闭,只查排名中的几十只) |
-| `--count` | rank 使用最近 N 条 K 线(0=全部,默认 0) |
-
-#### 强势股排名(strength)
-
-按 **5 / 20 / 60 日涨幅加权**合成强势分,从全市场选出"最近最强"的股票。**纯离线数据**,读取本地通达信 `.day` 文件,全市场约 30-60 秒(并发可压到 10 秒内)。
-
-**三种预设模式:**
-
-| 模式 | 性格 | 权重 (w5/w20/w60) | 波动率惩罚 | 适合 |
-|------|------|-------------------|-----------|------|
-| `steady`(默认) | 中长期稳健 | 0.2 / 0.3 / 0.5 | ✅ 除以 vol_20 | 选"稳着涨"的票,妖股被高波动压低 |
-| `breakout` | 近期妖股爆发 | 0.6 / 0.3 / 0.1 | ❌ 纯加权涨幅 | 选"短期最猛"的票,妖股本身就是高波动 |
-| `balanced` | 三周期均衡 | 等权 + vol 调整 | ✅ 除以 vol_20 | 不确定时的安全默认 |
-
-> 💡 **为什么 breakout 不除波动率?** 妖股本质高波动,除以 vol 会把它压下去,与"找妖股"目标矛盾。steady 除以 vol 是为了奖励"稳着涨"的票(vol 小,score 放大)。
-
-```bash
-# 中长期稳健强势 Top 50(默认 steady 模式)
-easy-tdx screen strength --preset steady --top 50 --table
-
-# 近期妖股爆发 Top 20(补齐股票名称)
-easy-tdx screen strength --preset breakout --top 20 --names --table
-
-# 三周期均衡
-easy-tdx screen strength --preset balanced --top 30 --table
-
-# 自定义权重(自动归一化,5:3:2 = 0.5:0.3:0.2)
-easy-tdx screen strength --w5 0.5 --w20 0.3 --w60 0.2 --top 30 --table
-
-# 并发扫描(推荐 4-8 进程)
-easy-tdx screen strength --preset steady --top 100 --workers 4 --table
-
-# 过滤低流动性(最近 5 日日均成交额 ≥ 5000 万)
-easy-tdx screen strength --preset breakout --top 30 --min-amount 50000000 --table
-
-# 缩小范围 + 输出到文件
-easy-tdx screen strength --universe sz --top 30 --output sz_strength.json
-```
-
-输出示例(`--table`):
-
-```
-[*] 强势股排名 [steady] 共 50 只
- 数据截止: 2026-06-24 | 中长期稳健强势:权重偏 60 日,波动率惩罚,选出稳着涨的票
-════════════════════════════════════════════════════════════════════════════════
-排名 代码 名称 现价 5日 20日 60日 波动率 强势分
- *1 SZ300308 中际旭创 85.20 8.12% 15.34% 30.21% 0.0180 9.52
- *2 SH600519 贵州茅台 1800.00 3.25% 5.10% 10.05% 0.0120 6.21
-```
-
-输出示例(JSON):
-
-```json
-{
- "scan_time": "2026-06-25T10:30:00",
- "preset": "steady",
- "preset_desc": "中长期稳健强势:权重偏 60 日,波动率惩罚...",
- "data_date": 20260624,
- "total_ranked": 50,
- "ranking": [
- {"rank": 1, "code": "300308", "market": "SZ", "name": "中际旭创",
- "last_close": 85.20, "last_date": 20260624,
- "ret_5": 0.0812, "ret_20": 0.1534, "ret_60": 0.3021,
- "vol_20": 0.0180, "strength": 9.52}
- ]
-}
-```
-
-| 参数 | 说明 |
-|------|------|
-| `--preset` | 预设模式:`steady`(默认)/ `breakout` / `balanced` |
-| `--w5` `--w20` `--w60` | 自定义三周期权重(覆盖预设,自动归一化) |
-| `--vol-adjusted` / `--no-vol-adjusted` | 波动率惩罚开关(覆盖预设) |
-| `--top` | 返回前 N 名(默认 50) |
-| `--universe` | `all`(默认)/ `sh` / `sz` / 文件路径 |
-| `--min-listed-days` | 最小上市天数(默认 65,保证能算 60 日涨幅) |
-| `--min-amount` | 最近 5 日日均成交额下限(元,默认 0 不过滤) |
-| `--workers` | 并发进程数:`0` 串行 / `4+` 并发(推荐 4-8) |
-| `--names` | 在线补齐股票名称(默认关闭) |
-| `--output` | 输出 JSON 文件(默认 stdout) |
-
-> ⚠️ **数据时效**:strength 依赖本地 `.day` 文件。输出中的 `data_date` / `last_date` 字段标注数据截止日,请先用 `easy-tdx offline sync` 同步最新数据。
-
-### 捉妖大师(重点)
-
-捉妖大师是多周期涨幅共振指标,通过 20/60/120 日涨幅及指数平滑判断短中长线趋势是否同向,用于筛选趋势刚启动的强势股。
-
-```bash
-easy-tdx indicator ZHUOYAO -m SH -c 600519 --count 30 --table
-
-# 自定义周期参数
-easy-tdx indicator ZHUOYAO -m SZ -c 000001 --params N1=90,N2=45,N3=15
-
-# 结合其他指标一起看
-easy-tdx indicator ZHUOYAO,MACD,KDJ -m SH -c 600519 --count 20 --table
-```
-
-输出列说明:
-
-| 列名 | 含义 |
-|------|------|
-| `ZY_LONG` | 长线 — 120 日涨幅的 10 日指数平滑 |
-| `ZY_MID` | 中线 — 60 日涨幅(%) |
-| `ZY_SHORT` | 短线 — 20 日涨幅(%) |
-| `ZY_TREND` | 趋势 — 中线的 10 日指数平滑 |
-
-**核心信号:** 四线全部 > 0 且短线 > 中线 > 长线 = 短中长趋势完全一致向上,是强势股特征。详见 [捉妖大师指标详解](docs/indicator-zhuoyao.md)。
-
-### 30日乖离率信号(重点)
-
-30日乖离率信号指标,在标准乖离率(BIAS)基础上叠加短/长信号线,通过三者位置关系判断趋势方向和转折点。源自通达信经典指标。
-
-```bash
-easy-tdx indicator BIAS_SIGNAL -m SH -c 600519 --count 60 --table
-
-# 自定义周期参数
-easy-tdx indicator BIAS_SIGNAL -m SZ -c 000001 --params P=5,M=20
-
-# 结合其他指标一起看
-easy-tdx indicator BIAS_SIGNAL,MACD,KDJ -m SH -c 600519 --count 30 --table
-```
-
-输出列说明:
-
-| 列名 | 含义 |
-|------|------|
-| `BS_X` | M日乖离率 — 当前价格偏离30日均线的百分比 |
-| `BS_SMA` | 短周期信号线 — 乖离率的 P 日均线,过滤短期噪音 |
-| `BS_LMA` | 长周期信号线 — 乖离率的 M 日均线,捕捉中期趋势方向 |
-
-**核心信号:** X > S_SMA 且 X_LMA 上升 = 多头确认(通达信红色);S_SMA > X 或 X_LMA 下降 = 空头预警(通达信绿色)。多空判断非对称设计——多头需两个条件同时满足,空头只需其一,偏向保守预警。详见 [30日乖离率信号指标详解](docs/indicator-bias-signal.md)。
-
-```python
-# Python API 用法
-from easy_tdx import MacClient, Market
-
-with MacClient.from_best_host() as c:
- df = c.get_stock_kline_with_indicators(
- Market.SH, "600519",
- indicators=["BIAS_SIGNAL"],
- count=60,
- )
- # df 包含: datetime, open, close, high, low, vol, amount
- # + BS_X, BS_SMA, BS_LMA
-```
-
-支持 34 个指标:MACD, KDJ, RSI, BOLL, DMI, ATR, WR, CCI, BIAS, BIAS_SIGNAL, OBV, VR, EMV, MFI, BRAR, ASI, TRIX, DPO, MTM, ROC, EXPMA, BBI, PSY, DFMA, CR, KTN, XSII, MASS, TAQ, ZHUOYAO, SAR, VWAP, AROON, FK。
-
-```python
-# Python API 用法
-from easy_tdx import MacClient, Market
-
-with MacClient.from_best_host() as c:
- df = c.get_stock_kline_with_indicators(
- Market.SH, "600519",
- indicators=["ZHUOYAO"],
- count=30,
- )
- # df 包含: datetime, open, close, high, low, vol, amount
- # + ZY_LONG, ZY_MID, ZY_SHORT, ZY_TREND
-```
-
-支持 34 个指标:MACD, KDJ, RSI, BOLL, DMI, ATR, WR, CCI, BIAS, BIAS_SIGNAL, OBV, VR, EMV, MFI, BRAR, ASI, TRIX, DPO, MTM, ROC, EXPMA, BBI, PSY, DFMA, CR, KTN, XSII, MASS, TAQ, ZHUOYAO, SAR, VWAP, AROON, FK。
-
-### 财务
-
-```bash
-easy-tdx f10 600519 # 茅台利润表,最近 8 期(默认 lrb)
-easy-tdx f10 600519 --type fzb --num 4 # 资产负债表,最近 4 期
-easy-tdx f10 000001 --type llb --table # 平安现金流量表,表格输出
-```
-
-> 新浪财经数据源,``--type`` 支持 ``lrb``(利润表)/``fzb``(资产负债表)/``llb``(现金流量表)。
-> 独立于 TDX 行情服务器,``item_value`` 已转 float 可直接数值计算,同比附 ``{科目}_同比`` 列。
-
-### 通达信原生 F10 与最新财务快照
-
-走通达信协议(与 Web 层 ``/finance`` ``/company/*`` 端点同源),覆盖 ``f10``(新浪三表)之外的 F10 全文板块。完整示例见 [examples/06_finance/](./examples/06_finance/README.md)。
-
-```bash
-easy-tdx finance-info SH 600519 --table # 最新财务快照(30+ 项单期指标)
-easy-tdx company-info SH 600519 # F10 板块目录(最新提示/公司概况/...)
-easy-tdx company-info SH 600519 "公司概况" # 读板块完整正文(自动解析+读全,无需 offset/length)
-easy-tdx company-info SH 600519 600519.txt # 也可直接传文件名(此时用 --offset/--length)
-```
-
-- ``finance-info``:最新一期财务快照,含股本结构、资产负债、利润、现金流、每股指标(37 字段)。与 ``f10`` 互补——前者是单期快照,后者是多期三表。
-- ``company-info``:**一个命令两种用法**——无板块名参数列 F10 板块目录,有板块名参数读正文。目录含 16 个板块(最新提示、公司概况、财务分析、股东研究、股本结构、资本运作、业内点评、行业分析、公司大事、研究报告、经营分析、主力追踪、分红扩股、高层治理、龙虎榜单、关联个股)。
-- 读正文时传板块名即可自动读取完整内容(按目录 length 分块循环,大板块如「公司大事」也能一次读全);``--offset``/``--length`` 仅在传文件名时生效。通达信多服务器目录版本不一致时自动重试命中。
-
-
-### 扩展市场(港股/美股/期货)
-
-```bash
-easy-tdx ex markets # 列出可用市场
-easy-tdx ex kline HK_MAIN_BOARD 00700 --count 30 --table # 港股 K 线
-easy-tdx ex kline US_STOCK AAPL --table # 美股 K 线
-easy-tdx ex quote US_STOCK TSLA --table # 美股报价
-easy-tdx ex quote-list HK_MAIN_BOARD --table # 港股商品列表
-easy-tdx ex tick HK_MAIN_BOARD 00700 --table # 港股分时
-```
-
-### 离线数据(读取 + 写入同步)
-
-从本地通达信安装目录直接读取数据文件,无需网络连接:
-
-```bash
-easy-tdx offline home # 检测通达信安装目录
-easy-tdx offline daily SH 600000 --count 10 --table # A 股日线
-easy-tdx offline min SZ 000001 --type lc5 --table # 分钟线(5min/lc1/lc5)
-easy-tdx offline ex-files --table # 列出扩展市场可用文件
-easy-tdx offline ex-daily 38#2_CPI --count 5 --table # 扩展市场日线(期货/港股/外盘)
-easy-tdx offline gbbq C:\new_jyplug\T0002\hq_cache\gbbq --table # 股本变迁
-easy-tdx offline financial C:\new_jyplug\vipdoc\fin\gpcw20260331.dat # 历史财务
-easy-tdx offline blocks C:\new_jyplug\T0002\blocknew --table # 自定义板块
-```
-
-从服务端获取最新日线并写入本地 .day 文件,替代通达信内置下载功能:
-
-```bash
-# 同步单只股票日线(自动增量/全量)
-easy-tdx offline sync-daily SZ 000001
-easy-tdx offline sync-daily SH 600519 --vipdoc C:\new_jyplug\vipdoc
-
-# 一键同步沪深全市场(每天一条命令)
-easy-tdx offline sync-all
-```
-
-> 建议在通达信关闭时执行 sync 命令,避免文件被锁定。空文件自动全量下载,已有数据只做增量追加。
-
-## Web API
-
-将 easy-tdx 暴露为 REST + WebSocket 服务,供前端、其他语言或远程调用。无需额外注册,零配置启动。
-
-### 安装
-
-```bash
-# 标准安装
-pip install easy-tdx[web]
-
-# 开发模式(从源码安装,支持热重载)
-pip install -e ".[web]"
-```
-
-### 快速启动
-
-```bash
-# 启动 Web API 服务器(自动连接最优 TDX 服务器)
-easy-tdx serve
-
-# 启动后浏览器打开 http://127.0.0.1:8000/docs 查看完整 API 文档(Swagger UI)
-# 也可以访问 http://127.0.0.1:8000/redoc 查看 ReDoc 格式文档
-
-# 指定端口和 TDX 服务器
-easy-tdx serve --port 8080 --tdx-host 119.147.212.81
-
-# 开发模式(代码修改后自动重载)
-easy-tdx serve --reload
-```
-
-> 💡 启动后访问 **http://127.0.0.1:8000/docs** 可以看到完整的交互式 API 文档,支持在线调试每个接口。
-
-### REST API 示例
-
-```bash
-# ── 基础行情 ──
-# 获取深圳市场证券数量
-curl "http://localhost:8000/api/v1/security/count?market=SZ"
-
-# 获取股票K线
-curl "http://localhost:8000/api/v1/bars?market=SZ&code=000001&category=DAY&count=100"
-
-# 批量获取实时行情
-curl -X POST "http://localhost:8000/api/v1/quotes" \
- -H "Content-Type: application/json" \
- -d '{"stocks": [{"market": "SZ", "code": "000001"}, {"market": "SH", "code": "600000"}]}'
-
-# 市场统计
-curl "http://localhost:8000/api/v1/market/stat"
-
-# 全市场强势股排名(基于本地 vipdoc 数据,扫描约 30-60 秒)
-# steady = 中长期稳健 / breakout = 近期妖股 / balanced = 均衡
-curl "http://localhost:8000/api/v1/market/strength?preset=breakout&top_n=20"
-
-# 自定义权重 + 过滤低流动性(日均成交额 ≥ 5000 万)
-curl "http://localhost:8000/api/v1/market/strength?w5=0.5&w20=0.3&w60=0.2&min_amount=50000000&top_n=30"
-
-# 板块信息(标准协议)
-curl "http://localhost:8000/api/v1/block?filename=block_gn.dat"
-
-# ── 板块分析(MAC 协议)──
-# 行业板块列表
-curl "http://localhost:8000/api/v1/board-mac/list?board_type=HY&count=50"
-
-# 板块成分股(按涨幅排序)
-curl "http://localhost:8000/api/v1/board-mac/members?board_symbol=881001&count=20"
-
-# 个股所属板块
-curl "http://localhost:8000/api/v1/board-mac/belong?market=SZ&code=000001"
-
-# 板块摘要(含主力净流入、涨跌家数)
-curl "http://localhost:8000/api/v1/board-mac/summary?board_symbol=881001"
-
-# 行业板块涨幅排名 Top 10
-curl "http://localhost:8000/api/v1/board-mac/ranking?board_type=HY&top_n=10"
-
-# 板块 20 日涨幅排行
-curl "http://localhost:8000/api/v1/board-mac/change-ranking?board_type=HY&days=20&top_n=10"
-
-# ── 资金 / 信息 ──
-# 个股资金流向(主力/散户净流入)
-curl "http://localhost:8000/api/v1/mac/capital-flow?market=SH&code=600519"
-
-# 个股基本信息快照
-curl "http://localhost:8000/api/v1/mac/symbol-info?market=SZ&code=000001"
-
-# 服务器交易时段信息
-curl "http://localhost:8000/api/v1/mac/server-info"
-
-# ── 公告检索(巨潮资讯网,独立数据源)──
-# 检索公司公告(无需 TDX 行情服务器)
-curl "http://localhost:8000/api/v1/announcements?code=688017&count=30&page=1"
-# 返回每条含 url(4 参数可直点打开)和 pdf_url(PDF 直链):
-# {"data": [{"title":"...","type":"...","date":"...","url":".../detail?stockCode=...","pdf_url":"http://static.cninfo.com.cn/.../xxx.PDF",...}], "count": 30}
-
-# ── 财报三表(新浪财经,独立数据源)──
-# 利润表(type: lrb/fzb/llb)
-curl "http://localhost:8000/api/v1/sina/financial-report?code=600519&type=lrb&num=8"
-# 返回每行一期(最新在前),列为科目名(float)+ {科目}_同比(如有):
-
-# ── 排行 / 竞价 / 异动 ──
-# 全 A 涨幅排行前 20
-curl "http://localhost:8000/api/v1/mac/quote-list?category=A&count=20&sort_type=CHANGE_PCT"
-
-# 集合竞价数据
-curl "http://localhost:8000/api/v1/mac/auction?market=SZ&code=000001"
-
-# 市场异动行情
-curl "http://localhost:8000/api/v1/mac/unusual?market=SH&count=50"
-
-# ── 扩展市场(期货/港股/美股)──
-# 港股 K 线
-curl "http://localhost:8000/api/v1/ex/bars?market=HK_MAIN_BOARD&code=00700&category=DAY&count=30"
-
-# 美股实时报价
-curl "http://localhost:8000/api/v1/ex/quote?market=US_STOCK&code=AAPL"
-
-# ── 技术指标 ──
-# 列出所有可用指标
-curl "http://localhost:8000/api/v1/indicator/list"
-
-# 计算 MACD + KDJ 指标
-curl -X POST "http://localhost:8000/api/v1/indicator/compute" \
- -H "Content-Type: application/json" \
- -d '{"data": [{"open":10,"close":10.5,"high":11,"low":9.5,"vol":1000}], "indicators": ["MACD", "KDJ"]}'
-
-# ── 缠论分析 ──
-curl -X POST "http://localhost:8000/api/v1/chanlun/analyze" \
- -H "Content-Type: application/json" \
- -d '{"market": "SZ", "code": "000001", "category": "DAY", "count": 200}'
-
-# ── 板块总览(一次取全部板块:当日涨跌幅 + 涨速 + 3/5/20日/YTD 涨幅 + 领涨股,服务端 15s 缓存)──
-# board_type: HY 行业一级 / HY2 行业二级 / GN 概念 / FG 风格 / DQ 地区
-curl "http://localhost:8000/api/v1/board-mac/overview?board_type=HY"
-curl "http://localhost:8000/api/v1/board-mac/overview?board_type=GN"
-
-# ── 回测任务(WebUI 回测工作台同款后端)──
-# 列出内置策略及参数 schema
-curl "http://localhost:8000/api/v1/backtest/strategies"
-# 提交异步回测(strategy 见 /backtest/strategies;完整字段与 portfolio/multi/optimize/wf/evaluate
-# 各端点的请求体以 /docs 的 Swagger 为准),返回 task_id
-curl -X POST "http://localhost:8000/api/v1/backtest/run/async" \
- -H "Content-Type: application/json" \
- -d '{"strategy": "ma_cross", "symbol": "SZ:000001", "category": "DAY", "count": 2000}'
-# 轮询任务结果(对比页/导出亦走 /backtest/tasks)
-curl "http://localhost:8000/api/v1/backtest/tasks/"
-
-# ── 策略库(保存的策略持久化 SQLite)──
-curl "http://localhost:8000/api/v1/strategies"
-
-# ── 自选股 ──
-curl "http://localhost:8000/api/v1/watchlist"
-curl -X POST "http://localhost:8000/api/v1/watchlist" \
- -H "Content-Type: application/json" -d '{"market": "SH", "code": "600519", "name": "贵州茅台"}'
-
-# ── AI 解读(模型 Key 只存本地 ~/.easy_tdx/llm.json)──
-curl "http://localhost:8000/api/v1/llm/config" # 当前配置 + Provider 预设
-curl -X POST "http://localhost:8000/api/v1/llm/chat/async" \
- -H "Content-Type: application/json" \
- -d '{"prompt": "解读这份回测报告:..."}' # 后台任务,GET /llm/chat/tasks/{id} 轮询
-
-# ── 交易时段(自动刷新门控用)──
-curl "http://localhost:8000/api/v1/market/session"
-```
-
-### WebSocket 实时行情
-
-`/api/v1/ws/realtime/{symbol}`(v1.28 起接通数据源):连接即订阅指定标的,服务端
-经 `RealtimeDataFeed`(按 `interval` 秒轮询五档快照 → `EventBus`)推送 tick 帧;
-连接断开自动退订,无人订阅时完全停止轮询。盘外时段默认只睡不拉(交易时段过滤),
-本地冒烟/演示可配合 `EASY_TDX_E2E_MOCK=1` 的合成行情随时验证(见
-`scripts/ws_smoke.py`)。
-
-```javascript
-const ws = new WebSocket("ws://localhost:8000/api/v1/ws/realtime/SZ000001");
-
-ws.onmessage = (event) => {
- const frame = JSON.parse(event.data);
- if (frame.type === "tick") {
- // {type:"tick", symbol:"SZ000001", market:"SZ", code:"000001",
- // price:10.5, volume:12345, ts:1760000000.0,
- // open, high, low, pre_close, amount, name}
- console.log(frame.symbol, frame.price, frame.ts);
- } else if (frame.type === "ping") {
- // 服务端 30s 空闲心跳,忽略即可(客户端无须回包)
- }
-};
-
-// 动态订阅更多标的(服务端回 {"type":"status","msg":"subscribed SH600000"})
-ws.send(JSON.stringify({action: "subscribe", symbol: "SH600000"}));
-// 退订
-ws.send(JSON.stringify({action: "unsubscribe", symbol: "SH600000"}));
-```
-
-浏览器接入建议(自动重连 + 心跳容忍):`onclose` 后指数退避重连(参考
-`web-ui/src/stores/quotes.ts` 对 SSE 的同类处理);`{"type":"ping"}` 心跳帧直接
-忽略、不回包;连续 N 秒无任何帧(含 ping)再视为僵死连接主动重连。协议字段完整
-说明见 `docs/api_reference.md` 的 WebSocket 一节;单标的 WS 订阅与看板 SSE
-(全量快照)并存不冲突,按需选用。
-
-### API 文档
-
-启动服务后访问:
-- Swagger UI: http://localhost:8000/docs
-- ReDoc: http://localhost:8000/redoc
-
-### 编程 API
-
-```python
-from easy_tdx.web import create_app
-import uvicorn
-
-app = create_app(host="119.147.212.81", port=7709)
-uvicorn.run(app, host="0.0.0.0", port=8000)
-```
-
-## CLI 命令汇总
-
-| 命令 | 说明 |
-|------|------|
-| `ping` | 服务器延迟测速 |
-| `version` | 版本号 |
-| `kline` | K 线(日/周/月/分钟,支持复权) |
-| `quote` | 实时报价(单只/批量) |
-| `quote-list` | 市场分类排序报价(A/SH/SZ/KCB/CYB) |
-| `tick` | 分时图(单日/多日/历史) |
-| `transaction` | 逐笔成交 |
-| `board-list` | 板块列表(行业/概念/风格) |
-| `board-members` | 板块成分股报价 |
-| `board-summary` | 板块汇总(成交额、主力净流入、涨跌家数) |
-| `board-ranking` | 板块涨跌幅排行榜(行业/概念排行) |
-| `board-change-ranking` | 板块 N 日涨跌幅排行(支持指定截止日期) |
-| `belong-board` | 个股所属板块 |
-| `capital-flow` | 资金流向 |
-| `auction` | 集合竞价 |
-| `unusual` | 市场异动 |
-| `market-stat` | 全市场涨跌统计 |
-| `server-info` | 服务器交易时段 |
-| `symbol-info` | 个股特征快照 |
-| `indicator` | 技术指标计算(34 个:MACD/KDJ/RSI/BOLL/DMI/ATR...) |
-| `indicator-list` | 列出可用技术指标 |
-| `backtest` | 回测引擎(加载策略文件,输出绩效报告) |
-| `portfolio` | 多标的组合回测(共享资金池,均等分配,汇总绩效) |
-| `factor list` | 列出所有内置因子 |
-| `factor analyze` | 因子分析(IC/分层/衰减) |
-| `pfactor backtest` | 组合因子选股回测 |
-| `run-all` | 批量运行所有策略并排名(绩效排名 + 综合评分 + 可选图表) |
-| `optimize` | 参数网格寻优(单策略网格搜索,或 `--all` 一键寻优所有内置策略并排名) |
-| `strategies` | 列出内置策略注册表(名称/中文标签/参数默认值/预设寻优网格) |
-| `formula compute` | 通达信公式计算(命名布尔输出即买卖信号) |
-| `formula screen` | 公式批量选股(信号在最后一根 = 1 的标的) |
-| `formula backtest` | 公式回测(买/卖列自动挑选,输出绩效 + 评级 + 评分) |
-| `warehouse sync` | 本地 K 线仓库增量同步(DuckDB,需 `easy-tdx[warehouse]`) |
-| `warehouse query` | 仓库查询(默认忽略未收盘的临时 bar) |
-| `warehouse stats` | 仓库统计(各标的行数/数据范围) |
-| `warehouse check` | 仓库健康自检(缺口/除权跳变/新鲜度) |
-| `ccpm` | 中金所成交持仓排名(官网每日发布,按日落盘缓存) |
-| `announcement` | 公告检索(巨潮资讯网,独立数据源,支持下载 PDF) |
-| `screen scan` | 策略选股扫描(纯离线,全市场信号扫描) |
-| `screen rank` | 扫描结果回测排名(按夏普/回撤等指标排序) |
-| `screen strength` | 强势股排名(5/20/60 日涨幅加权,steady/breakout/balanced 三预设) |
-| `serve` | 启动 Web API 服务器(REST + WebSocket,需 `easy-tdx[web]`) |
-| `f10` | 财报三表(新浪:利润表/资产负债表/现金流量表) |
-| `finance-info` | 最新财务快照(通达信协议,30+ 项单期指标) |
-| `company-info` | F10 公司信息(无板块名列目录 / 有板块名读正文) |
-| `fund-flow` | 历史资金流向(CLI 暂未实现,Web API `/fund-flow/history` 可用) |
-| `ex kline` | 扩展市场 K 线 |
-| `ex quote` | 扩展市场报价 |
-| `ex quote-list` | 扩展市场商品列表 |
-| `ex tick` | 扩展市场分时 |
-| `ex markets` | 列出可用扩展市场 |
-| `offline home` | 检测通达信安装目录 |
-| `offline daily` | A 股日线(本地 .day 文件) |
-| `offline sync-daily` | 从服务端同步单只股票日线到本地 .day 文件 |
-| `offline sync-all` | 一键同步沪深全市场日线(扫描本地 .day 文件) |
-| `offline min` | 分钟线(本地 .5/.lc1/.lc5 文件) |
-| `offline ex-files` | 列出扩展市场可用文件 |
-| `offline ex-daily` | 扩展市场日线(期货/港股/外盘) |
-| `offline gbbq` | 股本变迁数据 |
-| `offline financial` | 历史财务数据 |
-| `offline blocks` | 自定义板块数据 |
-
-## Python API
-
-### 连接管理
-
-所有客户端支持 `from_best_host()` 自动选最低延迟服务器:
-
-```python
-from easy_tdx import MacClient
-
-with MacClient.from_best_host() as c:
- df = c.get_stock_kline(...)
-```
-
-| 客户端 | 端口 | 覆盖范围 |
-|--------|------|----------|
-| `MacClient` / `AsyncMacClient` | 7709 | A 股行情(MAC 协议,推荐) |
-| `MacExClient` / `AsyncMacExClient` | 7727 | 港股/美股/期货(MAC 协议) |
-| `UnifiedTdxClient` / `AsyncUnifiedTdxClient` | 自动 | A 股 + 扩展市场统一入口 |
-| `TdxClient` / `AsyncTdxClient` | 7709 | A 股行情(标准协议) |
-
-### MAC 协议(推荐)
-
-#### 报价
-
-```python
-from easy_tdx import MacClient, Market, Category, SortType, SortOrder
-
-with MacClient.from_best_host() as c:
- # 批量报价(最多 80 只/次)
- df = c.get_stock_quotes([(Market.SH, "600519"), (Market.SZ, "000858")])
-
- # 市场分类排序报价
- df = c.get_stock_quotes_list(
- Category.A, count=20,
- sort_type=SortType.CHANGE_PCT,
- sort_order=SortOrder.DESC,
- )
-```
-
-返回列:`market, code, name` + 动态字段(`pre_close, open, high, low, close, vol, amount, turnover, vol_ratio` 等)。
-
-#### K 线(支持复权)
-
-```python
-from easy_tdx import MacClient, Market, Period, Adjust
-
-with MacClient.from_best_host() as c:
- # 日K前复权
- df = c.get_stock_kline(Market.SH, "600519", Period.DAILY, count=10, adjust=Adjust.QFQ)
- # 5分钟线
- df = c.get_stock_kline(Market.SZ, "000001", Period.MIN_5, count=100)
-```
-
-返回列:`datetime, open, close, high, low, vol, amount`。
-
-#### 技术指标
-
-自动获取 200+ 条历史数据预热 EMA,返回最后 `count` 条带指标的结果:
-
-```python
-from easy_tdx import MacClient, Market, Period, Adjust
-from easy_tdx.indicator import compute_indicators, list_indicators
-
-with MacClient.from_best_host() as c:
- # 便捷方法:获取 K 线 + 计算指标一步完成(默认前复权)
- df = c.get_stock_kline_with_indicators(
- Market.SH, "600519",
- indicators=["MACD", "KDJ", "RSI", "BOLL"],
- count=30,
- )
- # df 包含: datetime, open, close, high, low, vol, amount
- # + MACD_DIF, MACD_DEA, MACD_HIST, KDJ_K, KDJ_D, KDJ_J, RSI,
- # BOLL_UPPER, BOLL_MID, BOLL_LOWER
-
- # 自定义指标参数
- df = c.get_stock_kline_with_indicators(
- Market.SH, "600519",
- indicators=["MACD"],
- params={"MACD": {"SHORT": 10, "LONG": 22}},
- )
-
- # 独立使用:对已有 DataFrame 计算指标
- raw = c.get_stock_kline(Market.SH, "600519", Period.DAILY, count=200, adjust=Adjust.QFQ)
- result = compute_indicators(raw, ["ATR", "CCI", "WR"], tail=30)
-
- # 查看所有可用指标
- for info in list_indicators():
- print(info["name"], info["description"], info["outputs"])
-```
-
-支持 34 个技术指标:
-
-| 指标 | 输入 | 输出列 |
-|------|------|--------|
-| MACD | close | MACD_DIF, MACD_DEA, MACD_HIST |
-| KDJ | close, high, low | KDJ_K, KDJ_D, KDJ_J |
-| RSI | close | RSI |
-| BOLL | close | BOLL_UPPER, BOLL_MID, BOLL_LOWER |
-| DMI | close, high, low | DMI_PDI, DMI_MDI, DMI_ADX, DMI_ADXR |
-| ATR | close, high, low | ATR |
-| WR | close, high, low | WR1, WR2 |
-| CCI | close, high, low | CCI |
-| BIAS | close | BIAS1, BIAS2, BIAS3 |
-| OBV | close, vol | OBV |
-| VR | close, vol | VR |
-| EMV | high, low, vol | EMV, EMV_MA |
-| MFI | close, high, low, vol | MFI |
-| BRAR | open, close, high, low | AR, BR |
-| ASI | open, close, high, low | ASI, ASI_MA |
-| TRIX | close | TRIX, TRIX_MA |
-| DPO | close | DPO, DPO_MA |
-| MTM | close | MTM, MTM_MA |
-| ROC | close | ROC, ROC_MA |
-| EXPMA | close | EXPMA_12, EXPMA_50 |
-| BBI | close | BBI |
-| PSY | close | PSY, PSY_MA |
-| DFMA | close | DFMA_DIF, DFMA_DMA |
-| CR | close, high, low | CR |
-| KTN | close, high, low | KTN_UPPER, KTN_MID, KTN_LOWER |
-| XSII | close, high, low | XSII_TD1, XSII_TD2, XSII_TD3, XSII_TD4 |
-| MASS | high, low | MASS, MASS_MA |
-| TAQ | high, low | TAQ_UP, TAQ_MID, TAQ_DOWN |
-| ZHUOYAO | close | ZY_LONG, ZY_MID, ZY_SHORT, ZY_TREND |
-| BIAS_SIGNAL | close | BS_X, BS_SMA, BS_LMA |
-| SAR | high, low | SAR(抛物线转向/动态止损位) |
-| VWAP | close, high, low, vol | VWAP(N日滚动成交量加权均价) |
-| AROON | high, low | AROON_UP, AROON_DOWN, AROON_OSC |
-| FK | close | FK(EMA(2) 突破斜率外推 EMA(42)) |
-
-#### 分时
-
-```python
-with MacClient.from_best_host() as c:
- df = c.get_tick_chart(Market.SH, "600519") # 单日分时
- df = c.get_tick_charts(Market.SH, "600519", days=3) # 多日分时(最多5天)
- df = c.get_chart_sampling(Market.SH, "600519") # 240点缩略采样
-```
-
-#### 逐笔成交
-
-```python
-with MacClient.from_best_host() as c:
- df = c.get_transactions(Market.SH, "600519", count=100)
- df = c.get_transactions(Market.SH, "600519", count=100, date=20250115)
-```
-
-#### 板块
-
-```python
-from easy_tdx import BoardSortColumn, BoardType
-
-with MacClient.from_best_host() as c:
- df = c.get_board_list(BoardType.GN) # 概念板块
- df = c.get_board_list(sort_column=BoardSortColumn.SPEED) # 按涨速排序取涨速%
- df = c.get_board_members("881001", sort_type=SortType.CHANGE_PCT)
- df = c.get_belong_board(Market.SZ, "000001") # 个股所属板块
-
- # 板块汇总:成交额、主力净流入、涨跌家数
- summary = c.get_board_summary("881001")
- # summary = {
- # "member_count": 82,
- # "amount": 5823456000.0, # 板块总成交额(元)
- # "vol": 412356789, # 板块总成交量(股)
- # "main_net_amount": -123456.0, # 当日主力净流入
- # "main_net_3d": -567890.0, # 近3日主力净流入
- # "main_net_5d": -234567.0, # 近5日主力净流入
- # "up_count": 45,
- # "down_count": 37,
- # "members": DataFrame(...), # 成分股明细
- # }
-
- # 板块涨跌幅排行榜
- df = c.get_board_ranking(BoardType.HY, top_n=10, sort_by="change_pct")
- df = c.get_board_ranking(BoardType.GN, top_n=20, sort_by="main_net_amount")
- # 返回列:code, name, change_pct, amount, vol, main_net_amount, up_count, down_count, member_count
-
- # 板块 N 日涨跌幅排行(支持指定截止日期,默认全部)
- df = c.get_board_change_ranking(BoardType.HY, days=20)
- df = c.get_board_change_ranking(BoardType.GN, target_date=20250530, days=10, top_n=15)
- # 返回列:code, name, close_end, close_start, change_pct
-```
-
-#### 资金流向
-
-```python
-with MacClient.from_best_host() as c:
- df = c.get_capital_flow(Market.SH, "600519")
-```
-
-返回列:`date, main_in, main_out, main_net, small_in/out/net, mid_in/out/net, large_in/out/net`。
-
-#### 监控
-
-```python
-with MacClient.from_best_host() as c:
- df = c.get_auction(Market.SH, "600519") # 集合竞价
- df = c.get_unusual(Market.SH) # 市场异动
- df = c.get_symbol_info(Market.SZ, "000001") # 个股特征快照
- df = c.get_server_info() # 服务器交易时段
-```
-
-`get_unusual` 返回列含 `unusual_type`(类型码)与 `desc`(中文描述),共 19 种类型
-(主力买卖/加速拉升/急速拉升/盘中强弱/竞价异动/涨跌停/大单盘口等)。类型码→名称
-可用顶层常量映射:
-
-```python
-from easy_tdx import UNUSUAL_TYPE_NAMES
-
-df["type_name"] = df["unusual_type"].map(UNUSUAL_TYPE_NAMES)
-```
-
-### 扩展市场
-
-```python
-from datetime import date
-
-from easy_tdx import MacExClient, ExMarket, Period
-
-with MacExClient.from_best_host() as c:
- count = c.goods_count(ExMarket.HK_MAIN_BOARD)
- df = c.goods_list(ExMarket.HK_MAIN_BOARD, start=0, count=50)
- df = c.goods_kline(ExMarket.US_STOCK, "AAPL", Period.DAILY, count=10)
- df = c.goods_quotes([(ExMarket.HK_MAIN_BOARD, "00700")])
- df = c.goods_tick_chart(ExMarket.HK_MAIN_BOARD, "00700")
- df = c.goods_transaction(ExMarket.HK_MAIN_BOARD, "00700", count=100)
- df = c.goods_transaction_all(ExMarket.HK_MAIN_BOARD, "00700", date(2026, 7, 3)) # 港股当日全部逐笔
-```
-
-> **逐笔成交排序**:通达信协议为**倒序**——`start=0` 指向最新一笔(收盘方向),`count=2000` 默认只取最近 2000 笔。港股单日成交常达数万笔(如 02715 约 1.3 万笔/日),若需当日全部成交,用 `goods_transaction_all`(仅港股股票类市场,自动按 1800/页翻页取全天,安全上限 9 万条;返回协议原生倒序,需正序展示自行 `df.iloc[::-1]`)。
-
-### 统一客户端
-
-```python
-from easy_tdx import UnifiedTdxClient, ExMarket, Market, Period
-
-with UnifiedTdxClient() as client:
- # A 股 -- 自动路由到 MacClient
- df = client.get_stock_kline(Market.SH, "600519", Period.DAILY, count=5)
- df = client.get_stock_quotes([(Market.SH, "600519")])
- df = client.get_board_list()
-
- # 扩展市场 -- 自动路由到 MacExClient
- df = client.goods_kline(ExMarket.HK_MAIN_BOARD, "00700", Period.DAILY, count=5)
-```
-
-### 标准协议
-
-```python
-from easy_tdx import TdxClient, Market, KlineCategory
-
-with TdxClient.from_best_host() as c:
- count = c.get_security_count(Market.SH)
- stocks = c.get_security_list(Market.SH, start=0)
- quotes = c.get_security_quotes([(Market.SH, "600000"), (Market.SZ, "000001")])
- bars = c.get_security_bars(Market.SZ, "002176", KlineCategory.DAY, 0, 100)
- minute = c.get_minute_time_data(Market.SH, "600000")
- trades = c.get_transaction_data(Market.SH, "600000", 0, 20)
- flow = c.get_fund_flow(Market.SH, "600519")
- blocks = c.get_block_info("block_gn.dat")
- xdxr = c.get_xdxr_info(Market.SH, "600519")
- stat = c.get_market_stat()
-```
-
-> **资金流口径注意**(Issue #55):`get_fund_flow` / `get_history_fund_flow` 按 0x0fb5 逐笔接口的"单笔成交额"分档,而该接口返回的记录是交易所真实逐笔**聚合**后的(实测 000001.SZ 单日约 17:1),分档看的也不是挂单额。结果:高价股小单档可不足成交额 1%、主力档常占 95%+,`main_net_inflow` 实质更接近"当日主动买卖总失衡"。东财/同花顺的"主力净流入"基于 L2 逐笔委托、按挂单额分档——两套口径**不可比**(实证同规则选股信号重合度仅约 14%),勿混用于同一张表或同一个因子。
-
-`AsyncTdxClient` 提供对应的 `async def` 方法,接口一一对应。
-
-### SecurityQuote 字段说明
-
-`get_security_quotes()` 返回的 DataFrame 包含以下特殊字段:
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| `trading_status` | int | 交易状态标志。`0x8020`(32800) = 停牌,其余值表示正常交易或集合竞价 |
-| `open_amount` | float | 集合竞价成交金额(元)。仅个股有效,指数该字段无意义 |
-| `server_time` | str | 服务器时间,格式 `HH:MM:SS.mmm` |
-| `unknown_2` | int | 指数: 集合竞价成交金额/100;个股: 舍入残差≈0 |
-| `unknown_3` | int | 个股: 集合竞价成交金额/100;指数: 负值/无意义 |
-| `unknown_5-8` | int | 保留字段,恒为 0 |
-
-检测停牌:
-
-```python
-df = c.get_security_quotes([(Market.SH, "600000")])
-is_suspended = df.iloc[0]["trading_status"] == 0x8020
-```
-
-### 离线数据读取
-
-无需网络,从本地通达信安装目录直接读取:
-
-```python
-from easy_tdx.offline import detect_tdx_home, read_daily_bars, find_daily_bar_file
-from easy_tdx import Market
-
-home = detect_tdx_home()
-filepath = find_daily_bar_file(Market.SH, "600000")
-bars = read_daily_bars(filepath)
-```
-
-支持:日线、分钟线、扩展市场日线、板块、股本变迁、历史财务数据。
-
-### 离线数据写入同步
-
-从服务端获取最新数据并追加写入本地通达信数据文件:
-
-```python
-from easy_tdx.offline import (
- encode_daily_bar, append_daily_bars, get_last_bar_date,
- encode_5min_bar, append_5min_bars,
- encode_lc_min_bar, append_lc_min_bars,
-)
-from easy_tdx import Market
-from easy_tdx.client import TdxClient
-
-# 追加日线到 .day 文件(自动跳过重复日期)
-from easy_tdx.offline import sync_daily_bars_from_security_bars
-
-# 手动编码单条记录
-bar_bytes = encode_daily_bar(bar, price_coeff=0.01, vol_coeff=0.01)
-
-# 获取文件末尾日期
-last_date = get_last_bar_date("C:/new_jyplug/vipdoc/sh/lday/sh600000.day")
-```
-
-v1.5.0 起可通过 CLI 直接使用:
-
-```bash
-easy-tdx offline daily SH 600000 --count 10 --table
-easy-tdx offline ex-files --table
-easy-tdx offline ex-daily 29#A1801 --table
-```
-
-### 缠论分析
-
-基于缠论理论的技术分析模块,接收 easy_tdx 的 K 线 DataFrame,输出笔、中枢、线段、买卖点、背驰等分析结果:
-
-```python
-from easy_tdx.chanlun import ChanlunAnalyser, ChanlunConfig
-
-# 使用 easy_tdx 获取 K 线数据
-with TdxClient() as client:
- df = client.get_security_bars(Market.SH, "600519", KlineCategory.DAY, 0, 800)
-
-# 缠论分析
-analyser = ChanlunAnalyser("SH600519", "DAILY")
-result = analyser.process_klines(df)
-
-# 获取结果
-print(f"笔数: {len(result.bis)}")
-print(f"中枢数: {len(result.zss)}")
-print(f"线段数: {len(result.xds)}")
-print(f"买卖点: {[m.msg for m in result.mmds]}")
-print(f"背驰: {[b.msg for b in result.bcs]}")
-
-# JSON 兼容字典输出
-print(result.to_dict())
-```
-
-### 公告检索(巨潮资讯网)
-
-独立数据源(巨潮资讯网 cninfo),无需连接 TDX 行情服务器即可检索公司公告。
-标准库 urllib 实现,零额外依赖。
-
-```python
-from easy_tdx.cninfo import CninfoClient
-
-client = CninfoClient()
-
-# 检索公告(默认 30 条,最新在前)
-df = client.get_announcements("688017")
-# → DataFrame[title, type, date, url, code, org_id, announcement_id, announcement_time, pdf_url]
-
-# 翻页 + 自定义数量
-df = client.get_announcements("601088", count=10, page=2)
-
-# 返回示例(url 含 4 参数可直点打开,pdf_url 为 PDF 直链):
-# title type date url pdf_url
-# 0 关于召开2025年年度股东大会... 股东大会 2025-06-14 .../detail?stockCode=688017&announcementId=... http://static.cninfo.com.cn/.../xxx.PDF
-# 1 2024年年度报告 PDF 2025-03-28 .../detail?stockCode=688017&announcementId=... http://static.cninfo.com.cn/.../yyy.PDF
-```
-
-> - ``type`` 优先取 cninfo 的 ``announcementTypeName``;该字段对很多公告为 null
-> (数据源限制),此时回退到 ``adjunctType``(如 "PDF"),再为空给空字符串。
-> - ``url`` 必须含 4 参数(``stockCode``/``announcementId``/``orgId``/``announcementTime``)
-> 才能打开,少参数会 404。
-> - orgId 解析沿用 #19 修复:动态拉取官方映射表,查不到回退硬编码规则,
-> 保证 601xxx 等非标 orgId 段也能正常查询。
-
-#### 下载公告 PDF
-
-```python
-# 下载最新一条公告的 PDF 到当前目录
-df = client.get_announcements("601088", count=5)
-path = client.download_pdf(df.iloc[0]) # 接受 Announcement 或 DataFrame 的一行
-print(path) # /abs/path/20260605_1225351400.PDF
-
-# 批量下载
-for _, row in df.iterrows():
- try:
- path = client.download_pdf(row, dest_dir="./pdfs")
- except Exception as e:
- print(f"跳过(无附件或失败): {e}")
-```
-
-### 财报三表(新浪财经)
-
-独立数据源(新浪财经),无需连接 TDX 行情服务器即可获取利润表/资产负债表/现金流量表。
-标准库 urllib 实现,零额外依赖。
-
-```python
-from easy_tdx.sina import SinaClient
-
-client = SinaClient()
-
-# 利润表(默认 8 期,最新在前)
-df = client.get_financial_report("600519", report_type="lrb")
-# → DataFrame,每行一期,列 = [报告期, 营业总收入, 营业总收入_同比, ...]
-
-# 资产负债表 / 现金流量表(report_type 也接受中文别名:利润表/资产负债表/现金流量表)
-df = client.get_financial_report("600519", report_type="fzb", num=4)
-df = client.get_financial_report("600519", report_type="llb", num=4)
-
-# 返回示例(item_value 已转 float,可直接数值计算):
-# 报告期 营业总收入 营业总收入_同比 营业收入 营业收入_同比
-# 0 2026-03-31 54702912385.23 0.06336 53909252220.51 0.06538
-# 1 2025-12-31 174000000000.00 0.10000 NaN NaN
-```
-
-> - ``item_value`` 是字符串(新浪原始格式),本实现转 float;空/非数值转 None
-> - 有同比的科目附加 ``{科目}_同比`` 列(float 比例,如 0.06336 = +6.3%)
-> - 大类标题行(如 ``流动资产``,原 ``item_value=""``)保留为 None,反映报表结构
-
-### 实时行情轮询(RealtimeDataFeed)
-
-> ⚠️ 通达信协议**没有服务端推送**,只有请求/响应。本模块的「实时」是 **轮询五档快照近似**
-> (默认约 3 秒延迟),适合盘中信号提醒、轻量监控;**不适合高频 / 逐笔撮合**。
-
-`EventBus` 自身是纯发布/订阅管道,不会产生数据。要让 `RealtimeStrategy` 跑起来,
-需要配合 `RealtimeDataFeed`:它自动完成 `get_stock_quotes → MarketEvent → bus.publish`。
-
-```python
-import asyncio
-from easy_tdx.mac.client import AsyncMacClient
-from easy_tdx.realtime import (
- EventBus,
- RealtimeStrategy,
- MarketEvent,
- RealtimeDataFeed,
-)
-
-
-class MyStrategy(RealtimeStrategy):
- def on_tick(self, event: MarketEvent) -> None:
- print(f"{event.market}{event.code} price={event.price} vol={event.volume}")
-
-
-async def main():
- bus = EventBus()
- strategy = MyStrategy()
- bus.subscribe("SZ000001", strategy.on_tick) # 注意:key 必须带市场前缀
-
- feed = RealtimeDataFeed(
- bus=bus,
- symbols=[(0, "000001"), (1, "600519")], # [(Market.SZ, code), ...],单批 ≤80 只
- interval=3.0, # 轮询间隔(秒),下限 0.1
- dedup=True, # (price, volume) 未变的标的跳过发布
- # sessions=(), # 传空 tuple 表示全天轮询;默认仅 9:15-11:30 / 13:00-15:00
- )
- async with AsyncMacClient.from_best_host() as client:
- await feed.run_async(client) # Ctrl+C 或 feed.stop() 退出
-
-
-asyncio.run(main())
-```
-
-同步客户端(`MacClient`)用 `run_sync`,feed 会把阻塞调用丢到线程池,不卡事件循环:
-
-```python
-from easy_tdx.mac.client import MacClient
-
-with MacClient.from_best_host() as client:
- feed.run_sync(client)
-```
+## Web UI 零代码使用
-> **关键坑(issue #34)**:
-> - 订阅 key 必须与 `publish` 内部拼的 `f"{market}{code}"` 一致,即 `"SZ000001"`
-> 而不是 `"000001"`;否则事件分发匹配不到。
-> - 传给 `subscribe` 的必须是**实例的绑定方法** `strategy.on_tick`,
-> 不是未绑定的类方法 `MyStrategy.on_tick`。
-> - 整个流程跑在 `asyncio.run()` 里,否则协程不会被调度。
+`easy-tdx serve` 一条命令启动行情终端 + 回测工作台,浏览器自动打开 `http://localhost:8000`;不想装 Python 可下载 Windows 单文件 EXE 双击使用。页面操作手册见 [docs/web-ui.md](./docs/web-ui.md)。
-## 枚举参考
+## 文档导航
-### Period(K 线周期)
+**快速入口**:[GitHub Wiki](https://github.com/handsomejustin/easy_tdx/wiki) · [回测系统完全上手手册](./docs/回测系统完全上手手册.html)(零基础图文,13 章)· [交互式架构图](./docs/architecture.html)
-| 值 | 名称 | 说明 |
+| 域 | 文档 | 说明 |
|----|------|------|
-| 7 | `MIN_1` | 1 分钟 |
-| 0 | `MIN_5` | 5 分钟 |
-| 1 | `MIN_15` | 15 分钟 |
-| 2 | `MIN_30` | 30 分钟 |
-| 3 | `MIN_60` | 60 分钟 |
-| 4 | `DAILY` | 日线 |
-| 5 | `WEEKLY` | 周线 |
-| 6 | `MONTHLY` | 月线 |
-| 10 | `QUARTERLY` | 季线 |
-| 11 | `YEARLY` | 年线 |
+| CLI | [cli.md](./docs/cli.md) | 全部命令速查表 + 按域导航 |
+| CLI | [cli-market.md](./docs/cli-market.md) | 报价 / K线 / 分时 / 板块 / 资金 / 中金所 / 扩展市场 |
+| CLI | [cli-finance.md](./docs/cli-finance.md) | 巨潮公告检索 / 财报三表 / 通达信 F10 |
+| CLI | [cli-indicators.md](./docs/cli-indicators.md) | 34 个技术指标 / 通达信公式 / 捉妖 / 乖离率 |
+| CLI | [cli-backtest.md](./docs/cli-backtest.md) | backtest / optimize / portfolio / run-all |
+| CLI | [cli-screen.md](./docs/cli-screen.md) | 全市场选股扫描 / 强势股排名 |
+| 教程 | [chanlun.md](./docs/chanlun.md) | 缠论分析(CLI + Python) |
+| 教程 | [data-local.md](./docs/data-local.md) | 本地数据:DuckDB 仓库 / vipdoc 离线读写 |
+| Web | [web-api.md](./docs/web-api.md) | REST + WebSocket + SSE 端点与示例 |
+| Web | [web-ui.md](./docs/web-ui.md) | 行情终端与回测工作台操作手册 |
+| Web | [packaging.md](./docs/packaging.md) | Windows EXE 打包与分发 |
+| Python | [python-api.md](./docs/python-api.md) | 教程:连接 / 行情 / 指标 / 缠论 / 公告 / 财报 / 实时轮询 |
+| Python | [api_reference.md](./docs/api_reference.md) | 参考:客户端方法速查 |
+| Python | [field_mapping.md](./docs/field_mapping.md) | 参考:数据模型与枚举字段对照 |
+| 回测 | [backtest_usage.md](./docs/backtest_usage.md) | 引擎使用手册(策略 / 配置 / 结果) |
+| 回测 | [backtest-examples.md](./docs/backtest-examples.md) | 完整示例集 + 注意事项 |
+| 量化 | [quantitative-guide.md](./docs/quantitative-guide.md) | 因子引擎与组合管理 |
+| 量化 | [quantitative-advanced.md](./docs/quantitative-advanced.md) | 滑点 / 执行仿真 / 归因 / 完整工作流 |
+| 指标 | [indicator-zhuoyao.md](./docs/indicator-zhuoyao.md) | 捉妖大师信号详解 |
+| 指标 | [indicator-bias-signal.md](./docs/indicator-bias-signal.md) | 30 日乖离率信号详解 |
+| 开发者 | [architecture.md](./docs/architecture.md) | 七层架构 / 源码树 / 分层要点 |
+| 开发者 | [development.md](./docs/development.md) | 环境 / 测试 / CI / 发布流程 / 文档规范 |
+| 协议 | [protocol-reverse-engineering.md](./docs/protocol-reverse-engineering.md) | 通达信协议逆向过程 |
+| 协议 | [protocol-unknown-fields.md](./docs/protocol-unknown-fields.md) | 未知字段研究日志(活文档) |
-### Adjust(复权类型)
-
-| 值 | 名称 | 说明 |
-|----|------|------|
-| 0 | `NONE` | 不复权 |
-| 1 | `QFQ` | 前复权 |
-| 2 | `HFQ` | 后复权 |
-
-### Category(市场分类)
-
-| 值 | 名称 | 说明 |
-|----|------|------|
-| 0 | `SH` | 上证 A 股 |
-| 2 | `SZ` | 深证 A 股 |
-| 6 | `A` | 全部 A 股 |
-| 7 | `B` | B 股 |
-| 8 | `KCB` | 科创板 |
-| 12 | `BJ` | 北证 A 股 |
-| 14 | `CYB` | 创业板 |
-
-### BoardType(板块类型)
-
-| 值 | 名称 | 说明 |
-|----|------|------|
-| 0 | `HY` | 行业一级 |
-| 1 | `HY2` | 行业二级 |
-| 3 | `GN` | 概念 |
-| 4 | `FG` | 风格 |
-| 5 | `DQ` | 地区 |
-| 255 | `ALL` | 全部 |
-
-### SortType(排序字段)
-
-| 名称 | 说明 |
-|------|------|
-| `CODE` | 代码 |
-| `PRICE` | 现价 |
-| `CHANGE_PCT` | 涨幅% |
-| `VOLUME` | 成交量 |
-| `TOTAL_AMOUNT` | 成交额 |
-| `TURNOVER_RATE` | 换手% |
-| `MAIN_NET_AMOUNT` | 主力净额 |
-
-### ExMarket(扩展市场)
-
-| 值 | 名称 | 说明 |
-|----|------|------|
-| 28 | `ZZ_FUTURES` | 郑州商品 |
-| 29 | `DL_FUTURES` | 大连商品 |
-| 30 | `SH_FUTURES` | 上海期货 |
-| 31 | `HK_MAIN_BOARD` | 香港主板 |
-| 47 | `CFFEX_FUTURES` | 中金所期货 |
-| 48 | `HK_GEM` | 香港创业板 |
-| 74 | `US_STOCK` | 美国股票 |
-
-### Market(市场)
-
-| 值 | 名称 | 说明 |
-|----|------|------|
-| 0 | `SZ` | 深圳 |
-| 1 | `SH` | 上海 |
-| 2 | `BJ` | 北京 |
-
-## 完整 API 列表
-
-### MacClient / AsyncMacClient
-
-| 方法 | 说明 |
-|------|------|
-| `get_stock_quotes(stocks, fields)` | 批量实时报价 |
-| `get_stock_quotes_list(category, ...)` | 市场分类排序报价 |
-| `get_stock_kline(market, code, period, ...)` | K 线(支持复权) |
-| `get_stock_kline_with_indicators(market, code, indicators, ...)` | K 线 + 技术指标 |
-| `get_tick_chart(market, code, date)` | 单日分时图 |
-| `get_tick_charts(market, code, days)` | 多日分时图 |
-| `get_chart_sampling(market, code)` | 分时缩略采样 |
-| `get_transactions(market, code, ...)` | 逐笔成交 |
-| `get_symbol_info(market, code)` | 个股特征快照 |
-| `get_board_list(board_type, ..., sort_column)` | 板块列表(sort_value 列=排序键指标值) |
-| `get_board_members(board_symbol, ...)` | 板块成分股报价 |
-| `get_board_summary(board_symbol, ...)` | 板块汇总(成交额、主力净流入、涨跌家数) |
-| `get_board_ranking(board_type, top_n, sort_by, ...)` | 板块涨跌幅排行榜(行业/概念排行) |
-| `get_board_change_ranking(board_type, target_date, days, ...)` | 板块 N 日涨跌幅排行 |
-| `get_belong_board(market, code)` | 个股所属板块 |
-| `get_capital_flow(market, code)` | 资金流向 |
-| `get_auction(market, code)` | 集合竞价 |
-| `get_unusual(market, ...)` | 市场异动 |
-| `get_server_info()` | 服务器交易时段 |
-| `get_kline_offset(offset, count)` | K 线偏移信息 |
-| `get_goods_list(market, ...)` | 扩展市场商品列表 |
-
-### MacExClient / AsyncMacExClient
-
-| 方法 | 说明 |
-|------|------|
-| `goods_count(market)` | 商品总数 |
-| `goods_list(market, start, count)` | 商品列表 |
-| `goods_quotes(stocks, fields)` | 批量报价 |
-| `goods_quotes_list(market, ...)` | 市场分类报价列表 |
-| `goods_kline(market, code, period, ...)` | K 线(支持复权) |
-| `goods_tick_chart(market, code, ...)` | 分时图 |
-| `goods_chart_sampling(market, code)` | 分时缩略采样 |
-| `goods_transaction(market, code, ...)` | 逐笔成交 |
-
-### TdxClient / AsyncTdxClient
-
-| 方法 | 说明 |
-|------|------|
-| `get_security_count(market)` | 市场证券总数 |
-| `get_security_list(market, start)` | 证券列表(分页) |
-| `get_security_list_all()` | 沪深 A 股完整列表(含行业) |
-| `get_security_quotes(stocks)` | 批量五档行情 |
-| `get_security_bars(market, code, ...)` | 个股 K 线 |
-| `get_index_bars(market, code, ...)` | 指数 K 线 |
-| `get_minute_time_data(market, code)` | 今日分时 |
-| `get_history_minute_time_data(market, code, date)` | 历史分时 |
-| `get_transaction_data(market, code, ...)` | 当日逐笔成交 |
-| `get_history_transaction_data(...)` | 历史逐笔成交 |
-| `get_fund_flow(market, code)` | 当日资金流向(口径注意见上文) |
-| `get_history_fund_flow(market, code, ...)` | 历史资金流向(口径注意见上文) |
-| `get_xdxr_info(market, code)` | 除权除息历史 |
-| `get_finance_info(market, code)` | 最新财务数据 |
-| `get_company_info_category(market, code)` | 公司信息目录 |
-| `get_company_info_content(...)` | 公司信息文本 |
-| `get_block_info(filename)` | 板块信息 |
-| `get_report_file(filename)` | 下载服务器文件 |
-| `get_market_stat()` | 全市场涨跌统计 |
-| `get_price_limits(market, code, name, pre_close)` | 涨跌停价 |
-
-## 架构
-
-```
-src/easy_tdx/
-├── client.py # TdxClient / AsyncTdxClient(标准协议)
-├── unified.py # UnifiedTdxClient(统一入口)
-├── config.py # 服务器地址、端口、超时配置
-├── indicator.py # 技术指标计算(34 个,基于 MyTT)
-├── MyTT.py # 麦语言技术指标算法库
-├── mac/
-│ ├── client.py # MacClient / AsyncMacClient(MAC 协议)
-│ ├── enums.py # Period, Adjust, Category, ExMarket, SortType, ...
-│ ├── models.py # MacBar, MacQuoteField, MacTick, BoardInfo, ...
-│ └── commands/ # MAC 命令(build_request + parse_response,无 IO)
-├── ex/
-│ ├── client.py # ExTdxClient / AsyncExTdxClient(标准协议扩展市场)
-│ ├── mac_client.py # MacExClient / AsyncMacExClient(MAC 协议扩展市场)
-│ └── transport/ # ExTdxConnection(端口 7727)
-├── transport/
-│ ├── sync.py # TdxConnection + ping_host / ping_all
-│ └── async_.py # AsyncTdxConnection(asyncio)
-├── commands/ # 标准协议命令(无 IO)
-├── codec/ # price / volume / datetime / frame / bitmap 编解码
-├── chanlun/ # 缠论技术分析(K线合并/分型/笔/线段/中枢/买卖点/背驰)
-├── factor/ # 因子引擎(Factor ABC/19内置因子/截面计算/因子分析/预处理管道)
-├── portfolio/ # 组合管理(4优化器/风险模型/再平衡引擎)
-├── backtest/ # 回测引擎(Strategy基类/向量化引擎/多因子组合/滑点模型/执行仿真/归因分析)
-├── screen/ # 策略选股扫描(scan信号扫描/rank回测排名/并发扫描/增量缓存)
-├── realtime/ # 实时数据推送框架(EventBus/事件驱动/asyncio)
-├── web/ # Web API(FastAPI REST + WebSocket)
-├── models/ # 纯 dataclass,无业务逻辑
-├── offline/ # 离线数据读写模块(读取 + 写入同步)
-└── cli/ # easy-tdx CLI(click)
-```
-
-commands 层不依赖 transport,可独立单测。
-
-## 开发
-
-```bash
-python -m pytest tests/unit/ -v # 单元测试(无需网络)
-XMTDX_LIVE=1 python -m pytest tests/integration/ -v # 集成测试
-mypy src/ # 类型检查
-ruff check src/ tests/ # lint
-ruff format --check src/ tests/ # format check
-```
+> 📦 历史归档(均已实施/规划完成,供追溯):board-overview-design、hotspot-rolling-design、market-insights-roadmap、upgrade-plan-2026H2(见 docs/ 目录)与 docs/superpowers/(计划存档)。
+>
+> 完整文档索引(分类目录 + 归档标注)见 [docs/index.md](./docs/index.md)。
## 致谢
diff --git a/docs/api_reference.md b/docs/api_reference.md
index 2171671..6096f26 100644
--- a/docs/api_reference.md
+++ b/docs/api_reference.md
@@ -1,10 +1,11 @@
# easy_tdx API 参考文档
-> 版本: 1.16.2 | 运行时依赖: pandas / tzdata / click | 需要网络连接通达信行情服务器
+> 本文档为**方法速查参考**;上手教程见 [python-api.md](./python-api.md),数据模型与枚举字段见 [field_mapping.md](./field_mapping.md),Web 服务端点见 [web-api.md](./web-api.md)。
+>
+> 文档不写死版本号,对应版本以 [CHANGELOG.md](../CHANGELOG.md) 与 pyproject.toml 为准。
## 目录
-- [快速开始](#快速开始)
- [客户端](#客户端)
- [TdxClient(同步)](#tdxclient同步)
- [AsyncTdxClient(异步)](#asynctdxclient异步)
@@ -18,29 +19,10 @@
- [资金流向](#资金流向)
- [文件下载](#文件下载)
- [市场统计](#市场统计)
-- [数据模型](#数据模型)
-- [枚举](#枚举)
- [异常](#异常)
- [涨跌停价计算](#涨跌停价计算)
-
----
-
-## 快速开始
-
-```python
-from easy_tdx import TdxClient, Market, KlineCategory
-
-# 自动选择最优服务器
-with TdxClient.from_best_host() as c:
- # 沪市证券总数
- count = c.get_security_count(Market.SH)
-
- # 浦发银行日K线
- bars = c.get_security_bars(Market.SH, "600000", KlineCategory.DAY, 0, 10)
-
- # 实时行情
- quotes = c.get_security_quotes([(Market.SH, "600000"), (Market.SZ, "000001")])
-```
+- [全局常量](#全局常量)
+- [完整 API 列表(MAC 协议客户端)](#完整-api-列表mac-协议客户端)
---
@@ -396,193 +378,6 @@ c.get_market_stat() -> MarketStat
---
-## 数据模型
-
-### SecurityInfo
-
-证券列表条目。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| market | `Market` | 市场代码 |
-| code | `str` | 证券代码 |
-| name | `str` | 证券名称 |
-| volunit | `int` | 成交量单位(手 = volunit 股) |
-| decimal_point | `int` | 价格小数位数 |
-| pre_close | `float` | 昨收价 |
-| industry_tdx | `str` | 通达信行业代码(扩展字段) |
-| industry_sw | `str` | 申万行业代码(扩展字段) |
-
-### SecurityQuote
-
-实时五档行情。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| market | `Market` | 市场代码 |
-| code | `str` | 证券代码 |
-| price | `float` | 现价 |
-| pre_close | `float` | 昨收 |
-| open | `float` | 今开 |
-| high | `float` | 最高 |
-| low | `float` | 最低 |
-| vol | `float` | 总成交量(手) |
-| amount | `float` | 成交额(元) |
-| bid1~bid5 | `float` | 买一到买五价 |
-| bid_vol1~bid_vol5 | `float` | 买一到买五量 |
-| ask1~ask5 | `float` | 卖一到卖五价 |
-| ask_vol1~ask_vol5 | `float` | 卖一到卖五量 |
-| s_vol | `float` | 内盘(主动卖) |
-| b_vol | `float` | 外盘(主动买) |
-| rise_speed | `float` | 涨速 |
-| server_time | `str` | 服务器时间 |
-
-### SecurityBar
-
-K 线数据。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| open | `float` | 开盘价 |
-| close | `float` | 收盘价 |
-| high | `float` | 最高价 |
-| low | `float` | 最低价 |
-| vol | `float` | 成交量(股) |
-| amount | `float` | 成交额(元) |
-| year | `int` | 年 |
-| month | `int` | 月 |
-| day | `int` | 日 |
-| hour | `int` | 时 |
-| minute | `int` | 分 |
-| datetime_str | `str` | 属性,格式化时间字符串 |
-
-### MinuteBar
-
-分时数据。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| price | `float` | 价格 |
-| vol | `int` | 成交量 |
-
-### TransactionRecord
-
-逐笔成交。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| hour | `int` | 时 |
-| minute | `int` | 分 |
-| price | `float` | 成交价 |
-| vol | `int` | 成交量 |
-| buyorsell | `int` | 方向(0=买, 1=卖, 2=中性, 8=集合竞价) |
-
-### XdxrRecord
-
-除权除息记录。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| market | `Market` | 市场 |
-| code | `str` | 代码 |
-| year/month/day | `int` | 日期 |
-| category | `int` | 事件类型(见 XDXR_CATEGORY_NAMES) |
-| fenhong | `float \| None` | 每股分红(元) |
-| peigujia | `float \| None` | 配股价 |
-| songzhuangu | `float \| None` | 每股送转股比例 |
-| peigu | `float \| None` | 每股配股比例 |
-
-### FinanceInfo
-
-最新财务数据。包含股本结构(流通股本、总股本、国家股等)、资产负债(总资产、净资产等)、利润指标(主营收入、净利润等)和每股指标。字段名使用拼音,完整列表见源码 `models/finance.py`。
-
-### CompanyInfoCategory
-
-公司信息文件目录。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| name | `str` | 目录名 |
-| filename | `str` | 文件名 |
-| start | `int` | 起始偏移 |
-| length | `int` | 内容长度 |
-
-### TdxBlock
-
-板块信息。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| name | `str` | 板块名称 |
-| category | `int` | 分类(0=行业, 1=地域, 2=概念, 3=风格) |
-| count | `int` | 成分股数量 |
-| codes | `list[str]` | 成分股代码列表 |
-
-### MarketStat
-
-市场统计。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| up_count | `int` | 上涨家数 |
-| down_count | `int` | 下跌家数 |
-| neutral_count | `int` | 平盘家数 |
-| suspended_count | `int` | 停牌估算 |
-| total_count | `int` | 总计 |
-| total_amount | `float` | 总成交额 |
-| total_volume | `float` | 总成交量 |
-| total_market_cap | `float` | 总市值(元),来自 880001 收盘价 |
-| limit_up_count | `int` | 涨停家数,来自 880006 close |
-| limit_down_count | `int` | 跌停家数,来自 880006 open |
-
-### FundFlow
-
-资金流向。
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| super_in / super_out | `float` | 超大单流入/流出 |
-| large_in / large_out | `float` | 大单流入/流出 |
-| medium_in / medium_out | `float` | 中单流入/流出 |
-| small_in / small_out | `float` | 小单流入/流出 |
-| main_net_inflow | `float` | 属性:主力净流入(超大+大) |
-| total_net_inflow | `float` | 属性:全单净流入 |
-
-### HistoricalFundFlow
-
-历史日线资金流向。字段同 FundFlow,额外包含 `year`/`month`/`day` 日期字段。
-
----
-
-## 枚举
-
-### Market
-
-| 值 | 名称 | 说明 |
-|----|------|------|
-| 0 | SZ | 深圳 |
-| 1 | SH | 上海 |
-| 2 | BJ | 北京 |
-
-### KlineCategory
-
-| 值 | 名称 | 说明 |
-|----|------|------|
-| 0 | MIN_5 | 5 分钟 |
-| 1 | MIN_15 | 15 分钟 |
-| 2 | MIN_30 | 30 分钟 |
-| 3 | MIN_60 | 60 分钟 |
-| 4 | DAY | 日线 |
-| 5 | WEEK | 周线 |
-| 6 | MONTH | 月线 |
-| 7 | MIN_1 | 1 分钟 |
-| 8 | MIN_3 | 3 分钟(内部用) |
-| 9 | YEAR | 年线 |
-| 10 | SEASON | 季线 |
-| 11 | YEAR_ALT | 年线(备用) |
-
----
-
## 异常
所有异常继承自 `TdxError`。
@@ -640,65 +435,44 @@ compute_price_limits(market, code, name, pre_close, listed_days=None)
| `KNOWN_EX_HOSTS` | `list[str]` | 扩展行情服务器列表 |
| `XDXR_CATEGORY_NAMES` | `dict[int, str]` | 除权除息事件类型映射 |
----
+## 完整 API 列表(MAC 协议客户端)
-## WebSocket 实时行情(serve /ws/realtime/*)
+### MacClient / AsyncMacClient
-`easy-tdx serve` 后可建立 WebSocket 连接(v1.28 起联动 `RealtimeDataFeed`,此前
-该端点不推送数据):
+| 方法 | 说明 |
+|------|------|
+| `get_stock_quotes(stocks, fields)` | 批量实时报价 |
+| `get_stock_quotes_list(category, ...)` | 市场分类排序报价 |
+| `get_stock_kline(market, code, period, ...)` | K 线(支持复权) |
+| `get_stock_kline_with_indicators(market, code, indicators, ...)` | K 线 + 技术指标 |
+| `get_tick_chart(market, code, date)` | 单日分时图 |
+| `get_tick_charts(market, code, days)` | 多日分时图 |
+| `get_chart_sampling(market, code)` | 分时缩略采样 |
+| `get_transactions(market, code, ...)` | 逐笔成交 |
+| `get_symbol_info(market, code)` | 个股特征快照 |
+| `get_board_list(board_type, ..., sort_column)` | 板块列表(sort_value 列=排序键指标值) |
+| `get_board_members(board_symbol, ...)` | 板块成分股报价 |
+| `get_board_summary(board_symbol, ...)` | 板块汇总(成交额、主力净流入、涨跌家数) |
+| `get_board_ranking(board_type, top_n, sort_by, ...)` | 板块涨跌幅排行榜(行业/概念排行) |
+| `get_board_change_ranking(board_type, target_date, days, ...)` | 板块 N 日涨跌幅排行 |
+| `get_belong_board(market, code)` | 个股所属板块 |
+| `get_capital_flow(market, code)` | 资金流向 |
+| `get_auction(market, code)` | 集合竞价 |
+| `get_unusual(market, ...)` | 市场异动 |
+| `get_server_info()` | 服务器交易时段 |
+| `get_kline_offset(offset, count)` | K 线偏移信息 |
+| `get_goods_list(market, ...)` | 扩展市场商品列表 |
-```
-ws://127.0.0.1:8000/api/v1/ws/realtime/{symbol} # symbol 如 SZ000001 / SH600519
-```
+### MacExClient / AsyncMacExClient
-### 服务端推送帧(JSON)
+| 方法 | 说明 |
+|------|------|
+| `goods_count(market)` | 商品总数 |
+| `goods_list(market, start, count)` | 商品列表 |
+| `goods_quotes(stocks, fields)` | 批量报价 |
+| `goods_quotes_list(market, ...)` | 市场分类报价列表 |
+| `goods_kline(market, code, period, ...)` | K 线(支持复权) |
+| `goods_tick_chart(market, code, ...)` | 分时图 |
+| `goods_chart_sampling(market, code)` | 分时缩略采样 |
+| `goods_transaction(market, code, ...)` | 逐笔成交 |
-| type | 触发 | 字段 |
-|------|------|------|
-| `tick` | 轮询到标的的最新快照(价格/量变化才推,约 `interval` 秒一拍) | `symbol`、`market`、`code`、`price`、`volume`、`ts`(epoch 秒)、`open`、`high`、`low`、`pre_close`、`amount`、`name` |
-| `ping` | 连续 30s 未收到客户端消息的心跳 | —(客户端忽略即可,无须回包) |
-| `status` | 客户端 subscribe/unsubscribe 的确认 | `msg`(如 `subscribed SH600000`) |
-| `error` | 非法 JSON / 未知 action / 超出订阅上限 | `msg` |
-
-### 客户端控制消息(JSON 文本帧)
-
-```json
-{"action": "subscribe", "symbol": "SH600000"}
-{"action": "unsubscribe", "symbol": "SH600000"}
-```
-
-### 行为约定
-
-- **连接即订阅** path 上的 symbol;断开自动退订全部标的。
-- **按需轮询**:订阅集合为空时服务端不产生任何行情请求;去重后标的总数上限
- 80(`get_stock_quotes` 协议约束)。
-- **交易时段**:默认 A 股时段外只睡不拉(无 tick 帧,心跳照发);mock 模式
- (`EASY_TDX_E2E_MOCK=1`)不受限制。
-- **背压**:消费过慢时丢最旧快照保最新,不积压。
-- 环境变量:`EASY_TDX_WS_INTERVAL`(轮询间隔秒数,默认 3.0)。
-
-### 前端接入方式(自动重连 + 心跳容忍)
-
-```typescript
-function connectRealtime(symbol: string, onTick: (f: TickFrame) => void) {
- let retry = 0
- let ws: WebSocket | null = null
- const open = () => {
- ws = new WebSocket(`ws://${location.host}/api/v1/ws/realtime/${symbol}`)
- ws.onmessage = (e) => {
- const frame = JSON.parse(e.data)
- if (frame.type === 'tick') { retry = 0; onTick(frame) } // ping/status 忽略
- }
- ws.onclose = () => {
- retry += 1
- setTimeout(open, Math.min(1000 * 2 ** (retry - 1), 30_000)) // 指数退避
- }
- }
- open()
- return () => ws?.close()
-}
-```
-
-> 说明:看板/自选页的实时刷新已由 SSE `/stream/quotes`(全量快照、单连接共享)
-> 承担;WS 通道定位是**按需订阅单标的 tick 事件**(后续实时策略信号的接入点),
-> 两条链路按场景选用,不要求同时连接。手动冒烟见 `scripts/ws_smoke.py`。
diff --git a/docs/architecture.md b/docs/architecture.md
new file mode 100644
index 0000000..f181603
--- /dev/null
+++ b/docs/architecture.md
@@ -0,0 +1,54 @@
+# 架构
+
+
+
+七层分层,请求自上而下、数据(pandas DataFrame)自下而上:**① 用户接口层**(Web UI / CLI / Python API / 桌面 EXE)→ **② Web 服务层**(FastAPI + SSE 实时推送 + 异步任务)→ **③ 领域层**(回测 / 指标 / 缠论 / 因子 / 选股 / 组合,纯计算零网络)→ **④ 数据持久层**(DuckDB K 线仓库 + 通达信本地 vipdoc 文件)→ **⑤ 客户端网关层**(8 个客户端 + 健康分 / 故障转移)→ **⑥ 协议层**(通达信二进制协议编解码)→ **⑦ 外部数据源**(通达信服务器 / 中金所 / 新浪 / 巨潮 / LLM)。虚线为旁路直连(HTTP 数据源 / 本地文件 / CLI 与 Python API 越层直调)。
+
+🖼️ 交互版架构图(可缩放平移、悬停查看 38 个模块的职责详情、一键导出 PNG):[architecture.html](./architecture.html)
+
+## 源码树
+
+```
+src/easy_tdx/
+├── client.py # TdxClient / AsyncTdxClient(标准协议)
+├── unified.py # UnifiedTdxClient(统一入口)
+├── config.py # 服务器地址、端口、超时配置
+├── indicator.py # 技术指标计算(34 个,基于 MyTT)
+├── MyTT.py # 麦语言技术指标算法库
+├── mac/
+│ ├── client.py # MacClient / AsyncMacClient(MAC 协议)
+│ ├── enums.py # Period, Adjust, Category, ExMarket, SortType, ...
+│ ├── models.py # MacBar, MacQuoteField, MacTick, BoardInfo, ...
+│ └── commands/ # MAC 命令(build_request + parse_response,无 IO)
+├── ex/
+│ ├── client.py # ExTdxClient / AsyncExTdxClient(标准协议扩展市场)
+│ ├── mac_client.py # MacExClient / AsyncMacExClient(MAC 协议扩展市场)
+│ └── transport/ # ExTdxConnection(端口 7727)
+├── transport/
+│ ├── sync.py # TdxConnection + ping_host / ping_all
+│ └── async_.py # AsyncTdxConnection(asyncio)
+├── commands/ # 标准协议命令(无 IO)
+├── codec/ # price / volume / datetime / frame / bitmap 编解码
+├── chanlun/ # 缠论技术分析(K线合并/分型/笔/线段/中枢/买卖点/背驰)
+├── factor/ # 因子引擎(Factor ABC/19内置因子/截面计算/因子分析/预处理管道)
+├── portfolio/ # 组合管理(4优化器/风险模型/再平衡引擎)
+├── backtest/ # 回测引擎(Strategy基类/向量化引擎/多因子组合/滑点模型/执行仿真/归因分析)
+├── screen/ # 策略选股扫描(scan信号扫描/rank回测排名/并发扫描/增量缓存)
+├── realtime/ # 实时数据推送框架(EventBus/事件驱动/asyncio)
+├── web/ # Web API(FastAPI REST + WebSocket)
+├── models/ # 纯 dataclass,无业务逻辑
+├── offline/ # 离线数据读写模块(读取 + 写入同步)
+└── cli/ # easy-tdx CLI(click)
+```
+
+commands 层不依赖 transport,可独立单测。
+
+## 分层要点
+
+- **协议层无 IO**:`commands/`、`codec/`、`mac/commands/` 只做编解码,可完全离线单测(`tests/fixtures/` 的 hex dump 即其测试镜像)。
+- **领域层零网络**:`backtest/`、`chanlun/`、`factor/`、`portfolio/`、`screen/` 只吃 DataFrame,不碰网络——这是回测/扫描可在无行情连接时运行的基础。
+- **网关层统一入口**:`unified.py` 封装 8 个客户端(标准/MAC × 同步/异步 × 常规/扩展),带健康分与故障转移;上层(Web、CLI)优先走它。
+- **越层直调**:CLI 与 Python API 不经过 Web 服务层,直接调网关/领域层;HTTP 数据源(新浪/巨潮/中金所)与本地文件直读是旁路。因此同一功能常有三处入口(CLI 命令 / Python API / REST 端点),改领域逻辑三处受益;改协议/网关时注意 Web 层的替身切入点(`web/e2e_mock.py` 在 `EASY_TDX_E2E_MOCK=1` 下替换全部客户端)。
+- **CLI 薄封装**:`cli/cmd_*.py` 每个文件一个 click 命令组,业务全部在领域/网关层;领域模块内也有 CLI(`backtest/cli.py`、`screen/cli.py`),由 `cli/__init__.py` 汇总注册。入口链:`easy-tdx` 命令 → `_editable_guard:main`(可编辑安装失效时打印修复指引)→ CLI。
+- **`python -m easy_tdx` 三种形态**(`__main__.py`):开发态无参默认等价 `easy-tdx serve`;打包态双击走托盘(uvicorn 后台线程 + 主线程 pystray 托盘);multiprocessing 子进程拦截保护(Windows spawn 下防止子进程重复启动 uvicorn,一键寻优/screen 扫描等多进程功能依赖它)。
+- **离线数据平台差异**:`.day` 文件路径分隔符 / GBK 文件名 / 时区行为在 Windows 与 Linux 不同,CI 有 Windows matrix 覆盖,改 `offline/` 时留意。
diff --git a/docs/backtest-examples.md b/docs/backtest-examples.md
new file mode 100644
index 0000000..9c7ab3d
--- /dev/null
+++ b/docs/backtest-examples.md
@@ -0,0 +1,153 @@
+# 回测完整示例集
+
+本文件汇集回测引擎的完整可运行示例与注意事项,配合 [backtest_usage.md](./backtest_usage.md)(手册)与 [cli-backtest.md](./cli-backtest.md)(CLI 参考)使用。
+
+## 完整示例
+
+### 示例 1:双均线交叉策略
+
+```python
+"""双均线交叉策略:MA5 上穿 MA20 买入,下穿卖出。"""
+import pandas as pd
+from easy_tdx.backtest import BacktestEngine, Strategy, crossover
+from easy_tdx import MyTT
+
+
+class DualMACross(Strategy):
+ def init(self):
+ self.ma5 = self.I(MyTT.MA, self.data.close, 5)
+ self.ma20 = self.I(MyTT.MA, self.data.close, 20)
+ self.golden = crossover(self.ma5, self.ma20)
+ self.death = crossover(self.ma20, self.ma5)
+
+ def next(self):
+ if self.golden[self._bar_index] and self.position["size"] == 0:
+ self.buy(size=0)
+ elif self.death[self._bar_index] and self.position["size"] > 0:
+ self.sell(size=0)
+
+
+# 构造模拟数据(实际使用 TdxClient 获取)
+dates = pd.date_range("2024-01-01", periods=200, freq="D")
+import numpy as np
+rng = np.random.default_rng(42)
+close = 10.0 + np.cumsum(rng.normal(0, 0.2, 200))
+
+df = pd.DataFrame({
+ "datetime": dates,
+ "open": close + rng.uniform(-0.1, 0.1, 200),
+ "close": close,
+ "high": close + rng.uniform(0, 0.3, 200),
+ "low": close - rng.uniform(0, 0.3, 200),
+ "vol": rng.integers(10000, 100000, 200),
+})
+
+engine = BacktestEngine(DualMACross, cash=100000, commission=0.0003)
+result = engine.run(df)
+
+result.summary()
+print(f"\n年化收益: {result.performance['annual_return']:.2%}")
+print(f"夏普比率: {result.performance['sharpe']:.2f}")
+```
+
+### 示例 2:MACD 策略 + 预计算指标
+
+```python
+"""MACD 策略:DIF 上穿 DEA 买入,下穿卖出。"""
+from easy_tdx.backtest import BacktestEngine, Strategy, crossover
+from easy_tdx import MyTT
+
+
+class MACDStrategy(Strategy):
+ def init(self):
+ dif, dea, macd_hist = self.I(MyTT.MACD, self.data.close)
+ self.dif = dif
+ self.dea = dea
+ self.golden = crossover(dif, dea)
+ self.death = crossover(dea, dif)
+
+ def next(self):
+ if self.golden[self._bar_index] and self.position["size"] == 0:
+ self.buy(size=0)
+ elif self.death[self._bar_index] and self.position["size"] > 0:
+ self.sell(size=0)
+
+
+engine = BacktestEngine(MACDStrategy, cash=100000)
+result = engine.run(df) # df 包含 OHLCV 数据
+```
+
+### 示例 3:布林带突破 + 滑点模拟
+
+```python
+"""布林带策略:跌破下轨买入,突破上轨卖出,模拟滑点。"""
+from easy_tdx.backtest import BacktestEngine, Strategy
+from easy_tdx import MyTT
+
+
+class BollingerBreakout(Strategy):
+ def init(self):
+ upper, mid, lower = self.I(MyTT.BOLL, self.data.close, 20)
+ self.upper = upper
+ self.lower = lower
+
+ def next(self):
+ cur = self.data.close[0]
+ if cur <= self.lower[self._bar_index] and self.position["size"] == 0:
+ self.buy(size=0)
+ elif cur >= self.upper[self._bar_index] and self.position["size"] > 0:
+ self.sell(size=0)
+
+
+# 模拟滑点和保守成交价
+engine = BacktestEngine(
+ BollingerBreakout,
+ cash=100000,
+ slippage=0.02, # 每股 2 分钱滑点
+ execution="worst", # 保守成交价
+ reject_policy="skip", # 资金不足直接跳过
+)
+result = engine.run(df)
+```
+
+### 示例 4:从文件运行 CLI
+
+```python
+# save as rsi_strategy.py
+from easy_tdx.backtest import Strategy
+from easy_tdx import MyTT
+
+
+class RSIStrategy(Strategy):
+ """RSI 超卖超买策略。"""
+ def init(self):
+ self.rsi = self.I(MyTT.RSI, self.data.close, 14)
+
+ def next(self):
+ cur_rsi = self.rsi[self._bar_index]
+ if cur_rsi < 30 and self.position["size"] == 0:
+ self.buy(size=0)
+ elif cur_rsi > 70 and self.position["size"] > 0:
+ self.sell(size=0)
+```
+
+```bash
+easy-tdx backtest SZ 000001 \
+ --strategy-file rsi_strategy.py \
+ --cash 200000 \
+ --execution next_open \
+ --count 1000 \
+ --adjust QFQ \
+ --table
+```
+
+---
+
+## 注意事项
+
+1. **DataFrame 格式要求**:必须包含 `datetime`, `open`, `close`, `high`, `low` 列。`vol`/`amount` 为可选但推荐。
+2. **成交时机**:默认 `next_open` 模式下,信号产生后需等待下一根 K 线才能成交。如果信号在最后一根 K 线产生,则无法成交。
+3. **整手交易**:A 股按 100 股整手交易。全仓模式会自动向下取整到 100 的倍数。
+4. **做空限制**:v1 不支持做空,卖出数量不能超过当前持仓。
+5. **未来函数警告**:使用 `this_close` 模式时,结果中的 `config.future_leak_warning` 会标记为 `True`。
+6. **多笔同 bar 交易**:引擎支持同一根 K 线上产生多笔交易(如分批建仓),按顺序依次撮合。
diff --git a/docs/backtest_usage.md b/docs/backtest_usage.md
index dca7046..5a05ed6 100644
--- a/docs/backtest_usage.md
+++ b/docs/backtest_usage.md
@@ -21,15 +21,12 @@
- [资金曲线](#资金曲线)
- [交易记录](#交易记录)
- [序列化输出](#序列化输出)
-- [CLI 命令行](#cli-命令行)
- - [内置策略列表(strategies)](#内置策略列表strategies)
- - [参数网格寻优(optimize)](#参数网格寻优optimize)
- - [组合级分析(portfolio)](#组合级分析portfolio)
+- [CLI 命令行](#cli-命令行) → 见 [cli-backtest.md](./cli-backtest.md)
- [进阶用法](#进阶用法)
- [预计算指标列](#预计算指标列)
- [缠论结果注入](#缠论结果注入)
- [自定义策略文件](#自定义策略文件)
-- [完整示例](#完整示例)
+- [完整示例](#完整示例) → 见 [backtest-examples.md](./backtest-examples.md)
---
@@ -392,115 +389,10 @@ config = result.config
---
+
## CLI 命令行
-```bash
-# 基本用法
-easy-tdx backtest SZ 000001 --strategy-file my_strategy.py
-
-# 查看帮助
-easy-tdx backtest --help
-
-# 指定参数
-easy-tdx backtest SH 600519 \
- --strategy-file ma_cross.py \
- --cash 50000 \
- --commission 0.0003 \
- --execution next_open \
- --period DAILY \
- --count 500 \
- --table
-
-# 预计算指标(MACD, KDJ 会作为额外列注入 DataFrame)
-easy-tdx backtest SZ 000001 \
- --strategy-file macd_strategy.py \
- --indicators MACD,KDJ
-
-# 输出 JSON(默认)
-easy-tdx backtest SZ 000001 --strategy-file my_strategy.py
-
-# 输出表格
-easy-tdx backtest SZ 000001 --strategy-file my_strategy.py --table
-```
-
-**CLI 参数**:
-
-| 参数 | 默认值 | 说明 |
-|------|--------|------|
-| `MARKET` | — | 市场代码:SZ / SH |
-| `CODE` | — | 股票代码:如 000001 |
-| `--strategy-file` | — | Python 策略文件路径 |
-| `--strategy` | — | DSL 表达式(P1,尚未实现) |
-| `--cash` | 100000 | 初始资金 |
-| `--commission` | 0.0003 | 佣金率 |
-| `--execution` | next_open | 成交价规则 |
-| `--period` | DAILY | K 线周期 |
-| `--adjust` | NONE | 复权方式:NONE / QFQ / HFQ |
-| `--count` | 500 | K 线数量 |
-| `--indicators` | — | 预计算指标(逗号分隔) |
-| `--table` | False | 表格输出 |
-| `--output` | json | 输出格式:json / table / csv |
-| `--wf` | False | 附加 Walk-Forward 样本外验证 |
-| `--wf-windows` | 7 | Walk-Forward 窗口数 |
-| `--evaluate` | False | 一条龙评估(回测+WF+适配性+评分+评级+基准对比) |
-| `--auto-fees` | False | 按标的品种自动解析费率 |
-
-### 内置策略列表(strategies)
-
-```bash
-# 表格列出全部内置策略(名称/参数/预设寻优网格)
-easy-tdx strategies
-
-# JSON 输出(含完整参数 schema,与 Web API GET /backtest/strategies 同构)
-easy-tdx strategies --output json
-```
-
-### 参数网格寻优(optimize)
-
-对注册表内置策略的 1-2 个参数做网格搜索,按总收益率排名:
-
-```bash
-# 单策略:用该策略的预设寻优网格(见 strategies 命令)
-easy-tdx optimize SZ 000001 --strategy ma_cross
-
-# 单策略:自定义网格(--param 参数名=值1,值2,可多次指定)
-easy-tdx optimize SZ 000001 --strategy ma_cross --param fast=5,10,15 --param slow=20,60
-
-# 一键寻优所有内置策略:逐策略按预设网格寻优后全局排名
-easy-tdx optimize SZ 000001 --all
-
-# 并行加速(2+ 进程级并行;1 = 串行 + 指标缓存复用)
-easy-tdx optimize SZ 000001 --all --workers 4
-```
-
-**optimize 参数**:
-
-| 参数 | 默认值 | 说明 |
-|------|--------|------|
-| `--strategy` | — | 注册表策略名(与 `--all` 二选一) |
-| `--all` | False | 一键寻优所有内置策略(STRATEGY_PRESETS 预设网格) |
-| `--param` | 预设网格 | 自定义参数网格,如 `fast=5,10,15`(最多 2 个参数,笛卡尔积 ≤ 200) |
-| `--cash` | 1000000 | 初始资金 |
-| `--commission` | 0.0003 | 佣金率 |
-| `--slippage` | 0.0 | 滑点 |
-| `--workers` | 1 | 并行进程数 |
-| `--top` | 15 | 表格输出显示前 N 行 |
-
-Python API 同名能力:`easy_tdx.backtest.optimizer.ParamGridOptimizer`(单策略)与
-`easy_tdx.backtest.optimizer.optimize_all_strategies`(一键全策略)。
-
-### 组合级分析(portfolio)
-
-```bash
-# 组合级 Walk-Forward 样本外验证(全部标的日期并集切窗,每窗独立开仓)
-easy-tdx portfolio --stocks SZ:000001,SH:600519 --strategy-file strategies/ma_cross.py --wf --wf-windows 7
-
-# 组合级一条龙评估:组合回测 + 组合WF + 跨标的适配性 + 综合评分
-# + 组合评级 + 等权买入持有基准对比(与 Web UI /portfolio 页同构)
-easy-tdx portfolio --stocks SZ:000001,SH:600519 --strategy-file strategies/ma_cross.py --evaluate
-```
-
----
+CLI 用法见 [cli-backtest.md](./cli-backtest.md)(回测/寻优/组合/run-all 命令与参数)。
## 进阶用法
@@ -591,152 +483,3 @@ easy-tdx backtest SZ 000001 --strategy-file my_strategy.py --table
---
-## 完整示例
-
-### 示例 1:双均线交叉策略
-
-```python
-"""双均线交叉策略:MA5 上穿 MA20 买入,下穿卖出。"""
-import pandas as pd
-from easy_tdx.backtest import BacktestEngine, Strategy, crossover
-from easy_tdx import MyTT
-
-
-class DualMACross(Strategy):
- def init(self):
- self.ma5 = self.I(MyTT.MA, self.data.close, 5)
- self.ma20 = self.I(MyTT.MA, self.data.close, 20)
- self.golden = crossover(self.ma5, self.ma20)
- self.death = crossover(self.ma20, self.ma5)
-
- def next(self):
- if self.golden[self._bar_index] and self.position["size"] == 0:
- self.buy(size=0)
- elif self.death[self._bar_index] and self.position["size"] > 0:
- self.sell(size=0)
-
-
-# 构造模拟数据(实际使用 TdxClient 获取)
-dates = pd.date_range("2024-01-01", periods=200, freq="D")
-import numpy as np
-rng = np.random.default_rng(42)
-close = 10.0 + np.cumsum(rng.normal(0, 0.2, 200))
-
-df = pd.DataFrame({
- "datetime": dates,
- "open": close + rng.uniform(-0.1, 0.1, 200),
- "close": close,
- "high": close + rng.uniform(0, 0.3, 200),
- "low": close - rng.uniform(0, 0.3, 200),
- "vol": rng.integers(10000, 100000, 200),
-})
-
-engine = BacktestEngine(DualMACross, cash=100000, commission=0.0003)
-result = engine.run(df)
-
-result.summary()
-print(f"\n年化收益: {result.performance['annual_return']:.2%}")
-print(f"夏普比率: {result.performance['sharpe']:.2f}")
-```
-
-### 示例 2:MACD 策略 + 预计算指标
-
-```python
-"""MACD 策略:DIF 上穿 DEA 买入,下穿卖出。"""
-from easy_tdx.backtest import BacktestEngine, Strategy, crossover
-from easy_tdx import MyTT
-
-
-class MACDStrategy(Strategy):
- def init(self):
- dif, dea, macd_hist = self.I(MyTT.MACD, self.data.close)
- self.dif = dif
- self.dea = dea
- self.golden = crossover(dif, dea)
- self.death = crossover(dea, dif)
-
- def next(self):
- if self.golden[self._bar_index] and self.position["size"] == 0:
- self.buy(size=0)
- elif self.death[self._bar_index] and self.position["size"] > 0:
- self.sell(size=0)
-
-
-engine = BacktestEngine(MACDStrategy, cash=100000)
-result = engine.run(df) # df 包含 OHLCV 数据
-```
-
-### 示例 3:布林带突破 + 滑点模拟
-
-```python
-"""布林带策略:跌破下轨买入,突破上轨卖出,模拟滑点。"""
-from easy_tdx.backtest import BacktestEngine, Strategy
-from easy_tdx import MyTT
-
-
-class BollingerBreakout(Strategy):
- def init(self):
- upper, mid, lower = self.I(MyTT.BOLL, self.data.close, 20)
- self.upper = upper
- self.lower = lower
-
- def next(self):
- cur = self.data.close[0]
- if cur <= self.lower[self._bar_index] and self.position["size"] == 0:
- self.buy(size=0)
- elif cur >= self.upper[self._bar_index] and self.position["size"] > 0:
- self.sell(size=0)
-
-
-# 模拟滑点和保守成交价
-engine = BacktestEngine(
- BollingerBreakout,
- cash=100000,
- slippage=0.02, # 每股 2 分钱滑点
- execution="worst", # 保守成交价
- reject_policy="skip", # 资金不足直接跳过
-)
-result = engine.run(df)
-```
-
-### 示例 4:从文件运行 CLI
-
-```python
-# save as rsi_strategy.py
-from easy_tdx.backtest import Strategy
-from easy_tdx import MyTT
-
-
-class RSIStrategy(Strategy):
- """RSI 超卖超买策略。"""
- def init(self):
- self.rsi = self.I(MyTT.RSI, self.data.close, 14)
-
- def next(self):
- cur_rsi = self.rsi[self._bar_index]
- if cur_rsi < 30 and self.position["size"] == 0:
- self.buy(size=0)
- elif cur_rsi > 70 and self.position["size"] > 0:
- self.sell(size=0)
-```
-
-```bash
-easy-tdx backtest SZ 000001 \
- --strategy-file rsi_strategy.py \
- --cash 200000 \
- --execution next_open \
- --count 1000 \
- --adjust QFQ \
- --table
-```
-
----
-
-## 注意事项
-
-1. **DataFrame 格式要求**:必须包含 `datetime`, `open`, `close`, `high`, `low` 列。`vol`/`amount` 为可选但推荐。
-2. **成交时机**:默认 `next_open` 模式下,信号产生后需等待下一根 K 线才能成交。如果信号在最后一根 K 线产生,则无法成交。
-3. **整手交易**:A 股按 100 股整手交易。全仓模式会自动向下取整到 100 的倍数。
-4. **做空限制**:v1 不支持做空,卖出数量不能超过当前持仓。
-5. **未来函数警告**:使用 `this_close` 模式时,结果中的 `config.future_leak_warning` 会标记为 `True`。
-6. **多笔同 bar 交易**:引擎支持同一根 K 线上产生多笔交易(如分批建仓),按顺序依次撮合。
diff --git a/docs/chanlun.md b/docs/chanlun.md
new file mode 100644
index 0000000..6ee3af2
--- /dev/null
+++ b/docs/chanlun.md
@@ -0,0 +1,148 @@
+# 缠论分析
+
+## CLI 用法
+
+基于缠论理论的技术分析,计算管道:`K 线合并 → 分型识别 → 笔 → 中枢 → 线段 → 买卖点 → 背驰`。默认输出 JSON,加 `--table` 输出可读表格。:`K 线合并 → 分型识别 → 笔 → 中枢 → 线段 → 买卖点 → 背驰`。默认输出 JSON,加 `--table` 输出可读表格。
+
+```bash
+easy-tdx chanlun SZ 000001 --table
+easy-tdx chanlun SH 600519 --adjust QFQ --table
+easy-tdx chanlun SZ 000001 --period 30MIN
+
+# 多级别联立:分析日线最后一笔在 30 分钟级别中的走势结构
+easy-tdx chanlun SZ 000001 --multi-level 30MIN --table
+easy-tdx chanlun SH 600519 --multi-level 5MIN
+```
+
+### 输出示例
+
+以 `easy-tdx chanlun SH 601088 --table` 为例,输出分五个部分:
+
+**概要统计**
+
+```
+标的: 601088 周期: DAILY
+原始K线: 800 缠论K线: 589
+分型: 275 笔: 131 中枢: 21 线段: 40
+买卖点: 125 背驰: 73
+```
+
+| 字段 | 含义 |
+|------|------|
+| 原始 K 线 | 从服务端获取的原始 K 线条数 |
+| 缠论 K 线 | 经过包含处理(合并)后的 K 线条数,数量一定 ≤ 原始 K 线 |
+| 分型 | 识别出的顶分型 + 底分型总数 |
+| 笔 | 相邻两个异向分型之间的连线(涨跌方向交替) |
+| 中枢 | 至少 3 笔重叠区域形成的密集成交区间 |
+| 线段 | 由笔构成的更大级别走势单位 |
+| 买卖点 | 一二三类买卖点信号总数 |
+| 背驰 | 力度衰减信号总数(笔背驰 / 盘整背驰 / 趋势背驰) |
+
+**笔**
+
+```
+[0] ↑ 2023-02-17 → 2023-02-23 h=28.46 l=26.76 ✓
+[1] ↓ 2023-02-23 → 2023-02-28 h=28.46 l=27.8 ✓
+[2] ↑ 2023-02-28 → 2023-03-09 h=29.77 l=27.8 ✓
+```
+
+笔是缠论的基本走势单位。每条笔连接一个顶分型和一个底分型,方向严格交替(↑↓↑↓…)。`✓` 表示已确认(后续出现了反向笔),`…` 表示仍在进行中。
+
+- `↑`:向上笔,起点是底分型(低点),终点是顶分型(高点)
+- `↓`:向下笔,起点是顶分型(高点),终点是底分型(低点)
+- `h`/`l`:该笔范围内的最高价 / 最低价
+
+**中枢**
+
+```
+[0] zg=28.46 zd=28.11 gg=32.56 dd=26.76 lines=11 ✓
+[1] zg=31.2 zd=30.45 gg=32.56 dd=27.9 lines=3 ✓
+```
+
+中枢是至少 3 笔重叠形成的密集成交区间,代表多空博弈的平衡区域。`✓` 表示已脱离,`…` 表示价格仍在中枢区间内震荡。
+
+| 字段 | 含义 |
+|------|------|
+| `zg` | 中枢上沿(区间内最高的低点)— 支撑/压力的关键分界 |
+| `zd` | 中枢下沿(区间内最低的高点) |
+| `gg` | 中枢区间内的最高价 |
+| `dd` | 中枢区间内的最低价 |
+| `lines` | 构成该中枢的笔数,笔数越多代表震荡越充分 |
+
+中枢的意义:价格在中枢内震荡 → 突破中枢上沿看涨,跌破下沿看跌。`zg`/`zd` 是实战中最常用的参考价位。
+
+**线段**
+
+```
+[0] ↑ 2023-02-17 → 2023-03-09 h=29.77 l=26.76
+[1] ↓ 2023-02-28 → 2023-03-29 h=29.77 l=27.18
+```
+
+线段是比笔更大的走势单位,由多笔重叠组合而成。线段的方向不严格交替,可能出现连续同向(如连续多段向上),代表更高一级的趋势方向。实战中通常在线段级别判断大方向,在笔级别找买卖点。
+
+**买卖点**
+
+```
+1buy: 中枢下方力度衰减,一类买点 (l=27.30 < zd=46.72)
+2buy: 回调不创新低,二类买点 (l=27.33)
+3buy: 回调不破中枢上沿,三类买点 (l=27.80 > zg=27.58)
+1sell: 中枢上方力度衰减,一类卖点 (h=50.38 > zg=46.97)
+2sell: 反弹不创新高,二类卖点 (h=29.32)
+3sell: 反弹不破中枢下沿,三类卖点 (h=28.46 < zd=46.72)
+```
+
+缠论定义三类买点和三类卖点:
+
+| 类型 | 买点含义 | 卖点含义 |
+|------|----------|----------|
+| 一类 | 下跌趋势末端,力度衰减后的第一个低点(抄底) | 上涨趋势末端,力度衰减后的第一个高点(逃顶) |
+| 二类 | 一类买点后的回调不创新低(确认反转) | 一类卖点后的反弹不创新高(确认反转) |
+| 三类 | 回调不进入中枢上沿(趋势确认,中枢上方买) | 反弹不进入中枢下沿(趋势确认,中枢下方卖) |
+
+括号内的条件是该信号的触发依据,如 `l=27.80 > zg=27.58` 表示回调低点 27.80 高于中枢上沿 27.58,所以是三类买点。
+
+**背驰**
+
+```
+[✓] bi: 笔背驰: 笔[4] 力度=1.32 < 笔[2] 力度=1.97
+[✓] pz: 盘整背驰: 中枢[11] 内末笔力度=2.49 < 首笔力度=6.64
+[✓] qs: 趋势背驰(上): 中枢[1] 离开力度=3.32 < 中枢[0] 离开力度=4.45
+```
+
+背驰是力度衰减信号,表明当前走势动力正在减弱,可能即将反转。力度通过 MACD 面积计算,数值越小力度越弱。
+
+| 类型 | 含义 |
+|------|------|
+| `bi`(笔背驰) | 同向相邻两笔比较,后一笔力度 < 前一笔 → 该方向动力减弱 |
+| `pz`(盘整背驰) | 同一中枢内,末笔力度 < 首笔 → 中枢内动力衰减,即将突破 |
+| `qs`(趋势背驰) | 两个同向中枢之间比较,后一中枢离开力度 < 前一中枢 → 趋势可能终结 |
+
+`[✓]` 表示确认背驰。趋势背驰(上)代表上涨趋势可能结束,趋势背驰(下)代表下跌趋势可能结束。
+
+
+## Python 用法
+
+基于缠论理论的技术分析模块,接收 easy_tdx 的 K 线 DataFrame,输出笔、中枢、线段、买卖点、背驰等分析结果:
+
+```python
+from easy_tdx.chanlun import ChanlunAnalyser, ChanlunConfig
+
+# 使用 easy_tdx 获取 K 线数据
+with TdxClient() as client:
+ df = client.get_security_bars(Market.SH, "600519", KlineCategory.DAY, 0, 800)
+
+# 缠论分析
+analyser = ChanlunAnalyser("SH600519", "DAILY")
+result = analyser.process_klines(df)
+
+# 获取结果
+print(f"笔数: {len(result.bis)}")
+print(f"中枢数: {len(result.zss)}")
+print(f"线段数: {len(result.xds)}")
+print(f"买卖点: {[m.msg for m in result.mmds]}")
+print(f"背驰: {[b.msg for b in result.bcs]}")
+
+# JSON 兼容字典输出
+print(result.to_dict())
+```
+
diff --git a/docs/cli-backtest.md b/docs/cli-backtest.md
new file mode 100644
index 0000000..dac2e33
--- /dev/null
+++ b/docs/cli-backtest.md
@@ -0,0 +1,371 @@
+# CLI 参考 — 回测与寻优
+
+## 回测引擎
+
+> 📖 **完整使用手册**:[backtest_usage.md](./backtest_usage.md) ——
+> 涵盖策略编写(`init()`/`next()`)、行情数据访问、指标注册、订单模拟、
+> 绩效指标、组合回测、调仓引擎与完整示例。回测相关用法以该手册为准。
+
+内置向量回测引擎,加载 Python 策略文件即可跑回测。策略继承 `Strategy` 基类,在 `init()` 注册指标,在 `next()` 逐 bar 生成买卖信号,引擎完成订单模拟、持仓跟踪和绩效分析。
+
+**单策略回测:**
+
+```bash
+easy-tdx backtest SZ 300308 --strategy-file strategies/expma_cross.py --count 2000 --cash 1000000 --adjust QFQ --table
+# 推荐加上 --slippage 0.01 模拟真实滑点(元/股),使回测更贴近实盘
+
+# 缠论自动桥接:引擎自动计算缠论分析并注入策略 self.chanlun
+easy-tdx backtest SZ 000001 --strategy-file strategies/chanlun_strategy.py --chanlun-level DAILY --table
+
+# 预计算指标(MACD, KDJ 会作为额外列注入 DataFrame)
+easy-tdx backtest SZ 000001 \
+ --strategy-file strategies/macd_strategy.py \
+ --indicators MACD,KDJ
+```
+
+`backtest` 命令 CLI 参数:
+
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `MARKET` | — | 市场代码:SZ / SH |
+| `CODE` | — | 股票代码:如 000001 |
+| `--strategy-file` | — | Python 策略文件路径 |
+| `--cash` | 100000 | 初始资金 |
+| `--commission` | 0.0003 | 佣金率 |
+| `--execution` | next_open | 成交价规则 |
+| `--period` | DAILY | K 线周期 |
+| `--adjust` | NONE | 复权方式:NONE / QFQ / HFQ |
+| `--count` | 500 | K 线数量 |
+| `--indicators` | — | 预计算指标(逗号分隔) |
+| `--table` | False | 表格输出 |
+| `--output` | json | 输出格式:json / table / csv |
+| `--wf` | False | 附加 Walk-Forward 样本外验证 |
+| `--wf-windows` | 7 | Walk-Forward 窗口数 |
+| `--evaluate` | False | 一条龙评估(回测+WF+适配性+评分+评级+基准对比) |
+| `--auto-fees` | False | 按标的品种自动解析费率 |
+
+**样本外验证(v1.25):**
+
+```bash
+# 附加 Walk-Forward 七窗样本外验证(每窗独立开仓,窗口数可调)
+easy-tdx backtest SZ 300308 --strategy-file strategies/expma_cross.py --wf --wf-windows 7
+
+# 一条龙评估:回测 + WF + 适配性体检 + 综合评分 + S-D 评级 + 买入持有基准对比
+easy-tdx backtest SZ 300308 --strategy-file strategies/expma_cross.py --evaluate
+```
+
+输出示例:
+
+```
+=== 回测绩效概要 ===
+总收益率: 1413.51%
+年化收益: 40.85%
+最大回撤: 76.75%
+夏普比率: 0.88
+胜率: 20.8%
+交易次数: 24
+```
+
+> ⚠️ **回测 ≠ 实盘**。以上收益率为历史数据回测结果,包含幸存者偏差和过拟合风险,
+> 不构成投资建议。实际交易需考虑滑点、流动性、涨跌停无法成交等因素。
+> 请在充分理解策略逻辑后谨慎使用。
+
+**参数网格寻优(optimize)与内置策略列表(strategies):**
+
+```bash
+# 列出全部内置策略(名称/参数默认值/预设寻优网格)
+easy-tdx strategies
+
+# 单策略网格寻优(预设网格或 --param 自定义,--workers 4 进程并行)
+easy-tdx optimize SZ 000001 --strategy ma_cross
+easy-tdx optimize SZ 000001 --strategy ma_cross --param fast=5,10,15 --param slow=20,60
+
+# 一键寻优所有内置策略:逐策略按预设网格寻优后全局排名(对应 Web UI /optimize 页)
+easy-tdx optimize SZ 000001 --all --workers 4 --table
+
+# strategies 也支持 JSON 输出(含完整参数 schema,与 Web API GET /backtest/strategies 同构)
+easy-tdx strategies --output json
+```
+
+`optimize` 参数:
+
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `--strategy` | — | 注册表策略名(与 `--all` 二选一) |
+| `--all` | False | 一键寻优所有内置策略(STRATEGY_PRESETS 预设网格) |
+| `--param` | 预设网格 | 自定义参数网格,如 `fast=5,10,15`(最多 2 个参数,笛卡尔积 ≤ 200) |
+| `--cash` | 1000000 | 初始资金 |
+| `--commission` | 0.0003 | 佣金率 |
+| `--slippage` | 0.0 | 滑点 |
+| `--workers` | 1 | 并行进程数(2+ 进程级并行;1 = 串行 + 指标缓存复用) |
+| `--top` | 15 | 表格输出显示前 N 行 |
+
+Python API 同名能力:`easy_tdx.backtest.optimizer.ParamGridOptimizer`(单策略)与
+`easy_tdx.backtest.optimizer.optimize_all_strategies`(一键全策略)。
+
+**全策略批量对比(CLI):**
+
+`easy-tdx run-all` 一行命令跑完 `strategies/` 下所有策略并排名:
+
+```bash
+easy-tdx run-all SZ 300308 --count 2000 --cash 1000000 --adjust QFQ
+
+# 多因子组合回测
+easy-tdx run-all SZ 300308 --combo 2 --combo-mode MAJORITY
+
+# 加 --show 自动弹出最佳策略的资金曲线 vs 股价对比图
+easy-tdx run-all SZ 300308 --count 2000 --cash 1000000 --adjust QFQ --show
+
+# 自定义策略目录
+easy-tdx run-all SZ 300308 --strategies-dir my_strategies/
+```
+
+也可使用项目自带的 `run_all_strategies.py` 脚本(功能相同):
+
+```bash
+python -X utf8 run_all_strategies.py SZ 300308 --count 2000 --cash 1000000 --adjust QFQ
+
+# 加 --show 自动弹出最佳策略的资金曲线 vs 股价对比图
+python -X utf8 run_all_strategies.py SZ 300308 --count 2000 --cash 1000000 --adjust QFQ --show
+```
+
+**多因子组合回测:**
+
+自动遍历所有 2 因子 / 3 因子组合,找到最优搭配:
+
+```bash
+# 自动寻找最佳 2 因子和 3 因子组合(MAJORITY 模式)
+python -X utf8 run_all_strategies.py SZ 300308 --combo 2 --combo 3 --combo-mode majority
+
+# CLI 方式
+easy-tdx run-all SZ 300308 --combo 2 --combo 3 --combo-mode majority
+```
+
+CLI 指定策略文件组合:
+
+```bash
+easy-tdx backtest SZ 000001 \
+ --combo-strategies strategies/macd_cross.py,strategies/rsi_reversal.py,strategies/bollinger_breakout.py \
+ --combo-mode majority --table
+```
+
+Python API:
+
+```python
+from easy_tdx.backtest import CombinationRunner
+
+runner = CombinationRunner(
+ strategy_classes=[MACDStrategy, RSIStrategy, BollingerStrategy],
+ df=df, cash=100000,
+)
+results = runner.screen(combo_sizes=(2, 3), mode="MAJORITY")
+for r in results[:5]:
+ print(f"{r.name}: 收益={r.result.performance['total_return']:.2%}")
+```
+
+信号合并模式:
+
+| 模式 | 买入条件 | 卖出条件 | 特点 |
+|------|---------|---------|------|
+| `AND` | 所有因子都看多 | 所有因子都看空 | 极保守,交易少但精确 |
+| `MAJORITY` | 过半因子看多 | 过半因子看空 | 平衡,推荐默认 |
+| `OR` | 任一因子看多 | 任一因子看空 | 激进,信号多噪声大 |
+
+`--show` 会用 matplotlib 弹出一个双轴对比窗口:左轴蓝色线是归一化股价,右轴红色线是最佳策略的资金曲线,绿三角=买入、黄三角=卖出,标题显示股票名称和关键绩效指标。需要 `pip install matplotlib`。
+
+**多标的组合回测(portfolio):**
+
+`easy-tdx portfolio` 对多只股票同时回测,共享资金池,按均等比例分配,汇总组合整体绩效:
+
+```bash
+# 两只股票组合回测
+easy-tdx portfolio --stocks SZ:000001,SH:600519 --strategy-file strategies/ma_cross.py --table
+
+# 自定义资金和周期
+easy-tdx portfolio --stocks SZ:000001,SH:600519,SH:600036 \
+ --strategy-file strategies/expma_cross.py --cash 500000 --period DAILY --count 1000 --table
+
+# 搭配缠论桥接
+easy-tdx portfolio --stocks SZ:000001,SH:600519 \
+ --strategy-file strategies/chanlun_strategy.py --chanlun-level DAILY --table
+
+# 组合级 Walk-Forward / 一条龙评估(与 Web UI /portfolio 页同构)
+easy-tdx portfolio --stocks SZ:000001,SH:600519 \
+ --strategy-file strategies/ma_cross.py --wf --wf-windows 7
+easy-tdx portfolio --stocks SZ:000001,SH:600519 \
+ --strategy-file strategies/ma_cross.py --evaluate
+```
+
+输出示例:
+
+```
+=== 组合回测绩效概要 ===
+标的数量: 3
+总资金: 200,000
+组合收益率: 28.50%
+组合年化: 28.50%
+
+── 各标的详情 ──
+ SZ000001: 收益=35.20% 夏普=0.92 回撤=15.30% 分配=33% 交易=12
+ SH600519: 收益=18.40% 夏普=0.68 回撤=8.50% 分配=33% 交易=8
+ SH600036: 收益=31.90% 夏普=0.85 回撤=12.10% 分配=33% 交易=15
+```
+
+| 参数 | 说明 |
+|------|------|
+| `--stocks` | 股票列表:逗号分隔的 `市场:代码`(如 `SZ:000001,SH:600519`) |
+| `--cash` | 总资金(默认 20 万) |
+| `--allocation` | 资金分配方式(目前支持 `equal` 均等分配) |
+| `--chanlun-level` | 自动计算缠论分析并注入策略(如 DAILY/30MIN) |
+
+
+## 批量运行全部策略(run-all)
+
+
+```
+发现 9 个策略文件
+标的: SZ 300308 | K线: 2000 | 资金: 1,000,000 | 复权: QFQ
+================================================================================
+
+>> 运行策略: bias_reversal ... 完成 (2.4s)
+>> 运行策略: bollinger_breakout ... 完成 (0.6s)
+>> 运行策略: expma_cross ... 完成 (0.6s)
+>> 运行策略: kdj_golden ... 完成 (0.1s)
+>> 运行策略: ma_cross ... 完成 (1.4s)
+>> 运行策略: macd_cross ... 完成 (2.1s)
+>> 运行策略: rsi_reversal ... 完成 (0.2s)
+>> 运行策略: turtle_breakout ... 完成 (0.1s)
+>> 运行策略: volume_price ... 完成 (6.3s)
+
+================================================================================
+[*] 策略绩效排名 (按总收益率降序)
+================================================================================
+ 排名 策略 总收益率 年化收益 最大回撤 夏普 胜率 交易次数 盈亏比
+----------------------------------------------------------------------------------------------------
+ *1* 1 expma_cross 1413.51% 40.85% 76.75% 0.88 20.8% 24 6.45
+ *2* 2 ma_cross 1258.07% 38.94% 58.01% 0.87 38.2% 55 2.21
+ *3* 3 turtle_breakout 905.07% 33.76% 48.30% 0.83 75.0% 4 10.14
+ 4 bias_reversal 504.94% 25.47% 42.25% 0.70 66.3% 95 2.08
+ 5 macd_cross 387.67% 22.11% 61.08% 0.60 40.0% 85 2.20
+ 6 volume_price 247.72% 17.01% 65.73% 0.50 43.3% 254 1.40
+ 7 bollinger_breakout 169.65% 13.32% 49.71% 0.44 66.7% 24 1.93
+ 8 rsi_reversal 95.89% 8.85% 56.51% 0.33 57.1% 7 2.48
+ 9 kdj_golden 89.10% 8.36% 61.86% 0.32 66.7% 3 10.49
+```
+
+综合评分(夏普 × 0.4 + 收益/回撤 × 0.3 + 胜率 × 0.3):
+
+```
+ *1* 1 turtle_breakout 23.04 0.83 0.70 75.0%
+ *2* 2 bias_reversal 20.35 0.70 0.60 66.3%
+ *3* 3 bollinger_breakout 20.26 0.44 0.27 66.7%
+```
+
+换一个标的再跑:
+
+```bash
+# 贵州茅台
+python -X utf8 run_all_strategies.py SH 600519 --count 2000 --cash 1000000 --adjust QFQ
+```
+
+### `--show` 可视化效果
+
+
+ 
+ SH601088 中国神华 — bollinger_breakout 策略 | 收益 1281.8%
+
+
+
+ 
+ SH600522 中天科技 — kdj_golden 策略 | 收益 568.6%
+
+
+
+ 
+ SH601179 中国西电 — expma_cross 策略 | 收益 168.0%
+
+
+
+ 
+ SH600519 贵州茅台 — bollinger_breakout 策略 | 收益 187.0%
+
+
+> **⚠️ Demo 展示,不作为操作依据。** 历史回测收益不代表未来表现,策略参数未经过样本外验证。
+
+### 自带策略示例
+
+`strategies/` 目录下有 16 个开箱即用的策略文件,可直接用于 `--strategy-file`:
+
+| 文件 | 策略 | 类型 | 适合行情 |
+|------|------|------|----------|
+| `ma_cross.py` | 双均线交叉(MA5/MA20) | 趋势跟踪 | 单边趋势 |
+| `expma_cross.py` | EMA12/EMA50 交叉 | 趋势跟踪 | 单边趋势(比 MA 更灵敏) |
+| `macd_cross.py` | MACD 金叉死叉 | 趋势跟踪 | 中长线趋势 |
+| `bollinger_breakout.py` | 布林带突破 | 震荡反转 | 横盘震荡 |
+| `rsi_reversal.py` | RSI 超买超卖 | 反转 | 震荡市 |
+| `kdj_golden.py` | KDJ 低位金叉/高位死叉 | 反转 | 短线震荡 |
+| `turtle_breakout.py` | 海龟交易法(唐安奇通道) | 趋势突破 | 牛市启动 |
+| `bias_reversal.py` | 乖离率反转 | 反转 | 震荡回归 |
+| `volume_price.py` | 量价配合 | 综合判断 | 放量突破 |
+| `zhuoyao_momentum.py` | 捉妖大师多周期共振 | 趋势跟踪 | 多周期共振强势股 |
+| `dmi_trend.py` | DMI/ADX 趋势强度跟踪 | 趋势跟踪 | 单边趋势(过滤震荡) |
+| `cci_breakout.py` | CCI ±100 区间突破 | 区间突破 | 震荡转趋势 |
+| `mfi_volume.py` | MFI 量价反转 | 量价反转 | 震荡市(带量能确认) |
+| `trix_cross.py` | TRIX 三重平滑趋势交叉 | 趋势跟踪 | 中长线(抗噪音) |
+| `mtm_momentum.py` | MTM 动量零线穿越 | 动量 | 趋势拐点 |
+| `obv_trend.py` | OBV 能量潮趋势 | 量价趋势 | 资金持续流入的上升趋势 |
+
+编写自定义策略只需继承 `Strategy` 基类:
+
+```python
+from easy_tdx.backtest import Strategy
+from easy_tdx import MyTT
+
+
+class MyStrategy(Strategy):
+ def init(self):
+ self.ma = self.I(MyTT.MA, self.data.close, 10)
+
+ def next(self):
+ if self.data.close[0] > self.ma[self._bar_index]:
+ self.buy(size=0) # size=0 表示全仓
+ elif self.position["size"] > 0:
+ self.sell(size=0) # size=0 表示清仓
+```
+
+完整 API 参考:[backtest_usage.md](./backtest_usage.md)
+## 量化因子与组合管理
+
+新增三大模块:**因子引擎**(19 个内置因子 + 自定义扩展)、**因子分析**(IC/分层/衰减)、**组合管理**(4 种优化器 + 再平衡引擎)。加上**高级回测增强**:可插拔滑点模型(方根冲击/成交量比例)、执行仿真(TWAP/VWAP/限价单)、归因分析(Brinson + 因子归因)。
+
+```python
+from easy_tdx.factor import FactorEngine, FactorAnalyzer, preprocess
+from easy_tdx.portfolio import RebalanceEngine, FactorWeightedOptimizer
+from easy_tdx.backtest import BacktestEngine
+from easy_tdx.backtest.slippage import SquareRootSlippage
+from easy_tdx.backtest.execution import TWAPExecution
+
+# 因子研究
+engine = FactorEngine()
+factor_data = engine.compute_cross_section(data, ["momentum_20d", "rsi_14"])
+clean = preprocess(factor_data, ["momentum_20d", "rsi_14"])
+forward_returns = engine.compute_forward_returns(data, period=5)
+report = FactorAnalyzer(clean, forward_returns).full_report("momentum_20d")
+print(f"IC均值={report.mean_ic:.4f} ICIR={report.icir:.4f}")
+
+# 组合回测
+result = RebalanceEngine(
+ FactorWeightedOptimizer(), factor_name="momentum_20d", n_stocks=50, cash=1_000_000,
+).run(data, start_date=20230101, end_date=20240101)
+print(f"年化={result.performance['annual_return']:.2%}")
+
+# 高级回测(滑点 + 执行仿真)
+engine = BacktestEngine(
+ MyStrategy, cash=1_000_000,
+ slippage_model=SquareRootSlippage(impact_coeff=0.1),
+ execution_model=TWAPExecution(n_bars=3),
+)
+```
+
+详细用法和完整工作流示例:**[quantitative-guide.md](./quantitative-guide.md)**
+
diff --git a/docs/cli-finance.md b/docs/cli-finance.md
new file mode 100644
index 0000000..4758664
--- /dev/null
+++ b/docs/cli-finance.md
@@ -0,0 +1,41 @@
+# CLI 参考 — 财务与公告
+
+## 公告检索(巨潮资讯网)
+
+```bash
+easy-tdx announcement 688017 # 默认 30 条,JSON 输出
+easy-tdx announcement 601088 --count 10 --page 2 # 翻页
+easy-tdx announcement 000001 --table # 表格输出(不截断 url)
+
+# 下载最新 5 条公告的 PDF 到 ./pdfs 目录
+easy-tdx announcement 601088 --count 5 --download 5 --download-dir ./pdfs
+```
+
+> 独立数据源(巨潮资讯网),无需连接 TDX 行情服务器即可使用。
+> 返回的 ``url`` 含 4 参数可直接打开,``pdf_url`` 为 PDF 直链。
+
+## 财务
+
+```bash
+easy-tdx f10 600519 # 茅台利润表,最近 8 期(默认 lrb)
+easy-tdx f10 600519 --type fzb --num 4 # 资产负债表,最近 4 期
+easy-tdx f10 000001 --type llb --table # 平安现金流量表,表格输出
+```
+
+> 新浪财经数据源,``--type`` 支持 ``lrb``(利润表)/``fzb``(资产负债表)/``llb``(现金流量表)。
+> 独立于 TDX 行情服务器,``item_value`` 已转 float 可直接数值计算,同比附 ``{科目}_同比`` 列。
+
+## 通达信原生 F10 与最新财务快照
+
+走通达信协议(与 Web 层 ``/finance`` ``/company/*`` 端点同源),覆盖 ``f10``(新浪三表)之外的 F10 全文板块。完整示例见 [examples/06_finance/](../examples/06_finance/README.md)。
+
+```bash
+easy-tdx finance-info SH 600519 --table # 最新财务快照(30+ 项单期指标)
+easy-tdx company-info SH 600519 # F10 板块目录(最新提示/公司概况/...)
+easy-tdx company-info SH 600519 "公司概况" # 读板块完整正文(自动解析+读全,无需 offset/length)
+easy-tdx company-info SH 600519 600519.txt # 也可直接传文件名(此时用 --offset/--length)
+```
+
+- ``finance-info``:最新一期财务快照,含股本结构、资产负债、利润、现金流、每股指标(37 字段)。与 ``f10`` 互补——前者是单期快照,后者是多期三表。
+- ``company-info``:**一个命令两种用法**——无板块名参数列 F10 板块目录,有板块名参数读正文。目录含 16 个板块(最新提示、公司概况、财务分析、股东研究、股本结构、资本运作、业内点评、行业分析、公司大事、研究报告、经营分析、主力追踪、分红扩股、高层治理、龙虎榜单、关联个股)。
+- 读正文时传板块名即可自动读取完整内容(按目录 length 分块循环,大板块如「公司大事」也能一次读全);``--offset``/``--length`` 仅在传文件名时生效。通达信多服务器目录版本不一致时自动重试命中。
diff --git a/docs/cli-indicators.md b/docs/cli-indicators.md
new file mode 100644
index 0000000..b9e4390
--- /dev/null
+++ b/docs/cli-indicators.md
@@ -0,0 +1,127 @@
+# CLI 参考 — 技术指标与公式
+
+## 技术指标
+
+```bash
+easy-tdx indicator-list --table # 列出所有可用指标
+easy-tdx indicator MACD -m SH -c 600519 --table # MACD
+easy-tdx indicator KDJ -m SZ -c 000001 --table # KDJ
+easy-tdx indicator RSI -m SH -c 600519 --table # RSI
+easy-tdx indicator BOLL -m SH -c 600519 --table # BOLL 布林带
+easy-tdx indicator DMI -m SH -c 600519 --table # DMI 动向指标
+easy-tdx indicator ATR -m SH -c 600519 --table # ATR 真实波幅
+easy-tdx indicator WR -m SH -c 600519 --table # WR 威廉指标
+easy-tdx indicator CCI -m SH -c 600519 --table # CCI 顺势指标
+easy-tdx indicator BIAS -m SZ -c 000001 --table # BIAS 乖离率
+easy-tdx indicator BIAS_SIGNAL -m SH -c 600519 --table # 30日乖离率信号
+easy-tdx indicator OBV -m SZ -c 000001 --table # OBV 能量潮
+
+# 多指标同时计算
+easy-tdx indicator MACD,KDJ,RSI,BOLL -m SH -c 600519 --count 10 --table
+
+# 自定义参数
+easy-tdx indicator MACD -m SH -c 600519 --params SHORT=10,LONG=22
+
+# 分钟线指标
+easy-tdx indicator MACD -m SH -c 600519 --period 5MIN --count 50
+
+# 仅输出指标值(不含 OHLCV)
+easy-tdx indicator RSI -m SZ -c 000001 --no-ohlcv
+```
+
+## 通达信公式(v1.27)
+
+粘贴通达信公式即可计算 / 选股 / 回测——命名布尔输出自动成为买卖信号(名字含「买/卖」或 BUY/SELL 优先),30+ 白名单函数(MA/EMA/SMA/HHV/LLV/REF/CROSS/LONGCROSS/MACD/KDJ/RSI/BOLL/ATR…)向量化求值,无未来数据:
+
+```bash
+# 公式计算(最后一根各列值 + 最近信号明细)
+easy-tdx formula compute SH 600519 --formula "金叉: CROSS(MA(C,5), MA(C,20));"
+
+# 批量选股:信号在最后一根 = 1 的标的(--symbols 支持逗号分隔或 @文件)
+easy-tdx formula screen --symbols SH:600519,SZ:000001 --formula "金叉: CROSS(MA(C,5), MA(C,20));"
+
+# 公式回测:买/卖列自动挑选,信号下一根开盘成交,输出绩效 + 评级 + 评分
+easy-tdx formula backtest SH 600519 --file my_formula.txt
+```
+
+## 捉妖大师(重点)
+
+捉妖大师是多周期涨幅共振指标,通过 20/60/120 日涨幅及指数平滑判断短中长线趋势是否同向,用于筛选趋势刚启动的强势股。
+
+```bash
+easy-tdx indicator ZHUOYAO -m SH -c 600519 --count 30 --table
+
+# 自定义周期参数
+easy-tdx indicator ZHUOYAO -m SZ -c 000001 --params N1=90,N2=45,N3=15
+
+# 结合其他指标一起看
+easy-tdx indicator ZHUOYAO,MACD,KDJ -m SH -c 600519 --count 20 --table
+```
+
+输出列说明:
+
+| 列名 | 含义 |
+|------|------|
+| `ZY_LONG` | 长线 — 120 日涨幅的 10 日指数平滑 |
+| `ZY_MID` | 中线 — 60 日涨幅(%) |
+| `ZY_SHORT` | 短线 — 20 日涨幅(%) |
+| `ZY_TREND` | 趋势 — 中线的 10 日指数平滑 |
+
+**核心信号:** 四线全部 > 0 且短线 > 中线 > 长线 = 短中长趋势完全一致向上,是强势股特征。详见 [捉妖大师指标详解](./indicator-zhuoyao.md)。
+
+## 30日乖离率信号(重点)
+
+30日乖离率信号指标,在标准乖离率(BIAS)基础上叠加短/长信号线,通过三者位置关系判断趋势方向和转折点。源自通达信经典指标。
+
+```bash
+easy-tdx indicator BIAS_SIGNAL -m SH -c 600519 --count 60 --table
+
+# 自定义周期参数
+easy-tdx indicator BIAS_SIGNAL -m SZ -c 000001 --params P=5,M=20
+
+# 结合其他指标一起看
+easy-tdx indicator BIAS_SIGNAL,MACD,KDJ -m SH -c 600519 --count 30 --table
+```
+
+输出列说明:
+
+| 列名 | 含义 |
+|------|------|
+| `BS_X` | M日乖离率 — 当前价格偏离30日均线的百分比 |
+| `BS_SMA` | 短周期信号线 — 乖离率的 P 日均线,过滤短期噪音 |
+| `BS_LMA` | 长周期信号线 — 乖离率的 M 日均线,捕捉中期趋势方向 |
+
+**核心信号:** X > S_SMA 且 X_LMA 上升 = 多头确认(通达信红色);S_SMA > X 或 X_LMA 下降 = 空头预警(通达信绿色)。多空判断非对称设计——多头需两个条件同时满足,空头只需其一,偏向保守预警。详见 [30日乖离率信号指标详解](./indicator-bias-signal.md)。
+
+```python
+# Python API 用法
+from easy_tdx import MacClient, Market
+
+with MacClient.from_best_host() as c:
+ df = c.get_stock_kline_with_indicators(
+ Market.SH, "600519",
+ indicators=["BIAS_SIGNAL"],
+ count=60,
+ )
+ # df 包含: datetime, open, close, high, low, vol, amount
+ # + BS_X, BS_SMA, BS_LMA
+```
+
+支持 34 个指标:MACD, KDJ, RSI, BOLL, DMI, ATR, WR, CCI, BIAS, BIAS_SIGNAL, OBV, VR, EMV, MFI, BRAR, ASI, TRIX, DPO, MTM, ROC, EXPMA, BBI, PSY, DFMA, CR, KTN, XSII, MASS, TAQ, ZHUOYAO, SAR, VWAP, AROON, FK。
+
+```python
+# Python API 用法
+from easy_tdx import MacClient, Market
+
+with MacClient.from_best_host() as c:
+ df = c.get_stock_kline_with_indicators(
+ Market.SH, "600519",
+ indicators=["ZHUOYAO"],
+ count=30,
+ )
+ # df 包含: datetime, open, close, high, low, vol, amount
+ # + ZY_LONG, ZY_MID, ZY_SHORT, ZY_TREND
+```
+
+支持 34 个指标:MACD, KDJ, RSI, BOLL, DMI, ATR, WR, CCI, BIAS, BIAS_SIGNAL, OBV, VR, EMV, MFI, BRAR, ASI, TRIX, DPO, MTM, ROC, EXPMA, BBI, PSY, DFMA, CR, KTN, XSII, MASS, TAQ, ZHUOYAO, SAR, VWAP, AROON, FK。
+
diff --git a/docs/cli-market.md b/docs/cli-market.md
new file mode 100644
index 0000000..6d8372a
--- /dev/null
+++ b/docs/cli-market.md
@@ -0,0 +1,95 @@
+# CLI 参考 — 行情数据
+
+## 输出格式
+
+`easy-tdx` 默认输出 JSON(一行一条记录),`--table` 切换表格,`--output csv` 输出 CSV。
+
+## 基础
+
+```bash
+easy-tdx ping # 服务器测速
+easy-tdx version # 版本号
+```
+
+## 行情
+
+```bash
+# K 线
+easy-tdx kline SZ 000001 --count 30 --table
+easy-tdx kline SH 600519 --period 5MIN --adjust QFQ
+
+# 实时报价
+easy-tdx quote "SZ 000001,SH 600519" --table
+
+# 市场分类报价(按涨幅排序)
+easy-tdx quote-list A --count 20 --table
+easy-tdx quote-list KCB --sort TOTAL_AMOUNT --order ASC
+easy-tdx quote-list CYB --count 50
+```
+
+## 分时 / 成交
+
+```bash
+easy-tdx tick SZ 000001 --table
+easy-tdx tick SH 600519 --days 5
+easy-tdx tick SZ 000001 --date 20250115
+
+easy-tdx transaction SZ 000001 --count 100 --table
+easy-tdx transaction SH 600519 --date 20250115
+```
+
+## 板块
+
+```bash
+easy-tdx board-list --type GN --table
+easy-tdx board-list --type HY --count 200
+easy-tdx board-members 881001 --table
+easy-tdx belong-board SZ 000001 --table
+easy-tdx board-summary 881001 --table # 板块汇总(成交额/主力净流入/涨跌家数)
+easy-tdx board-summary 881001 --members --table # 含成分股明细
+easy-tdx board-ranking --type HY --top 10 --table # 行业板块排行
+easy-tdx board-ranking --type GN --sort-by amount # 概念板块按成交额排行
+
+# 板块 N 日涨跌幅排行(默认全部,支持指定日期)
+easy-tdx board-change-ranking --table # 行业 20 日涨跌幅排行
+easy-tdx board-change-ranking --type GN --days 10 --table # 概念 10 日涨跌幅排行
+easy-tdx board-change-ranking --type HY --date 20250530 --days 20 --table
+easy-tdx board-change-ranking --type HY --top 10 --asc # 行业跌幅前10
+```
+
+## 资金 / 监控
+
+```bash
+easy-tdx capital-flow SH 600519 --table
+easy-tdx auction SZ 000001 --table
+easy-tdx unusual SH --count 100 --table
+easy-tdx market-stat --table
+easy-tdx server-info --table
+easy-tdx symbol-info SZ 000001 --table
+```
+
+## 中金所成交持仓排名(v1.29.1)
+
+```bash
+easy-tdx ccpm IF --table # 最近有数据的交易日(缺省自动回溯)
+easy-tdx ccpm IF --date 2026-09-02 # 指定交易日
+easy-tdx ccpm all --date 2026-08-28 --table # 全部 8 个品种一次抓取
+easy-tdx ccpm TL --refresh # 忽略本地缓存,强制重新抓取
+```
+
+> 独立数据源(中金所官网),无需连接 TDX 行情服务器。品种:IF 沪深300 / IH 上证50 / IC 中证500 / IM 中证1000 股指期货,TS/TF/T/TL 为 2/5/10/30 年期国债期货。
+> 每个交易日收盘后约 16:15 发布,含该品种**全部合约 × 三类排名(成交量 / 持买单量·多单 / 持卖单量·空单)× 各前 20 名会员**;
+> 数据发布后不可变,按日缓存到 `~/.easy_tdx/cache/ccpm/`,历史二次查询零网络。
+> JSON 输出为英文列名(vol/long_pos/short_pos 等,机器友好),`--table` 自动切换中文表头。
+> WebUI 对应「期货持仓排名」页(含新手科普),API 为 `GET /api/v1/ccpm/rank`。
+
+## 扩展市场(港股/美股/期货)
+
+```bash
+easy-tdx ex markets # 列出可用市场
+easy-tdx ex kline HK_MAIN_BOARD 00700 --count 30 --table # 港股 K 线
+easy-tdx ex kline US_STOCK AAPL --table # 美股 K 线
+easy-tdx ex quote US_STOCK TSLA --table # 美股报价
+easy-tdx ex quote-list HK_MAIN_BOARD --table # 港股商品列表
+easy-tdx ex tick HK_MAIN_BOARD 00700 --table # 港股分时
+```
diff --git a/docs/cli-screen.md b/docs/cli-screen.md
new file mode 100644
index 0000000..0c54d0d
--- /dev/null
+++ b/docs/cli-screen.md
@@ -0,0 +1,160 @@
+# CLI 参考 — 策略选股扫描
+
+## 策略选股扫描(screen)
+
+把策略翻转成选股器:给定一个策略,扫描全市场找出今天触发买入信号的股票,再对这些信号做历史回测排名。**纯离线数据**,读取本地通达信 `.day` 文件,全市场约 30-60 秒。
+
+两步走工作流:
+
+**第一步:信号扫描(scan)**
+
+```bash
+# 扫描沪深全 A,找出 RSI 超卖触发的股票
+easy-tdx screen scan --strategy strategies/rsi_reversal.py --output signals.json
+
+# 缩小范围
+easy-tdx screen scan --strategy strategies/macd_cross.py --universe sz --output signals.json
+
+# 从自定义股票列表扫描
+easy-tdx screen scan --strategy strategies/bollinger_breakout.py --universe my_stocks.txt --output signals.json
+
+# 并发扫描(推荐 4-8 进程,速度提升 4-8 倍)
+easy-tdx screen scan --strategy strategies/rsi_reversal.py --workers 4 --output signals.json
+
+# 增量扫描(缓存未修改的 .day 文件,跳过重复计算)
+easy-tdx screen scan --strategy strategies/rsi_reversal.py --cache scan_cache.json --output signals.json
+```
+
+输出示例(JSON):
+
+```json
+{
+ "scan_time": "2026-06-10T18:30:00",
+ "strategy": "RSIStrategy",
+ "total_scanned": 4832,
+ "total_signals": 37,
+ "signals": [
+ {"code": "000001", "market": "SZ", "signal_date": 20260610, "last_close": 12.35},
+ {"code": "600519", "market": "SH", "signal_date": 20260610, "last_close": 1800.0}
+ ]
+}
+```
+
+**第二步:回测排名(rank)**
+
+```bash
+# 按夏普比率排名(默认)
+easy-tdx screen rank --from signals.json --sort sharpe --top 20 --table
+
+# 按最大回撤排名(越小越好,用 --sort-reverse)
+easy-tdx screen rank --from signals.json --sort max_drawdown --sort-reverse --table
+
+# 管道模式:一步到位
+easy-tdx screen scan --strategy strategies/rsi_reversal.py | easy-tdx screen rank --from - --table
+
+# 补齐股票名称(需要网络)
+easy-tdx screen rank --from signals.json --sort sharpe --top 10 --table --names
+```
+
+输出示例(`--table`):
+
+```
+[*] 信号排名 (按 sharpe 降序, 共 37 只)
+══════════════════════════════════════════════════════════════════════════
+排名 代码 名称 总收益率 年化收益 最大回撤 夏普 胜率 交易
+ *1 SZ300308 中际旭创 45.23% 18.72% 12.35% 1.85 62.5% 16
+ *2 SH600519 贵州茅台 38.10% 15.90% 8.21% 1.62 58.3% 12
+```
+
+| 参数 | 说明 |
+|------|------|
+| `--universe` | `all`(默认,沪深全 A)/ `sh` / `sz` / 文件路径(每行 "市场 代码") |
+| `--vipdoc` | 离线数据目录(默认自动检测通达信安装路径) |
+| `--workers` | 并发进程数:`0` 串行(默认)/ `2+` ProcessPoolExecutor 并发(推荐 4-8) |
+| `--cache` | 增量扫描缓存文件路径(JSON,mtime 未变的文件自动跳过) |
+| `--sort` | 排序指标:`sharpe`(默认)/ `total_return` / `max_drawdown` / `win_rate` 等 |
+| `--sort-reverse` | 升序(用于回撤等越小越好的指标) |
+| `--names` | 在线补齐股票名称(默认关闭,只查排名中的几十只) |
+| `--count` | rank 使用最近 N 条 K 线(0=全部,默认 0) |
+
+### 强势股排名(strength)
+
+按 **5 / 20 / 60 日涨幅加权**合成强势分,从全市场选出"最近最强"的股票。**纯离线数据**,读取本地通达信 `.day` 文件,全市场约 30-60 秒(并发可压到 10 秒内)。
+
+**三种预设模式:**
+
+| 模式 | 性格 | 权重 (w5/w20/w60) | 波动率惩罚 | 适合 |
+|------|------|-------------------|-----------|------|
+| `steady`(默认) | 中长期稳健 | 0.2 / 0.3 / 0.5 | ✅ 除以 vol_20 | 选"稳着涨"的票,妖股被高波动压低 |
+| `breakout` | 近期妖股爆发 | 0.6 / 0.3 / 0.1 | ❌ 纯加权涨幅 | 选"短期最猛"的票,妖股本身就是高波动 |
+| `balanced` | 三周期均衡 | 等权 + vol 调整 | ✅ 除以 vol_20 | 不确定时的安全默认 |
+
+> 💡 **为什么 breakout 不除波动率?** 妖股本质高波动,除以 vol 会把它压下去,与"找妖股"目标矛盾。steady 除以 vol 是为了奖励"稳着涨"的票(vol 小,score 放大)。
+
+```bash
+# 中长期稳健强势 Top 50(默认 steady 模式)
+easy-tdx screen strength --preset steady --top 50 --table
+
+# 近期妖股爆发 Top 20(补齐股票名称)
+easy-tdx screen strength --preset breakout --top 20 --names --table
+
+# 三周期均衡
+easy-tdx screen strength --preset balanced --top 30 --table
+
+# 自定义权重(自动归一化,5:3:2 = 0.5:0.3:0.2)
+easy-tdx screen strength --w5 0.5 --w20 0.3 --w60 0.2 --top 30 --table
+
+# 并发扫描(推荐 4-8 进程)
+easy-tdx screen strength --preset steady --top 100 --workers 4 --table
+
+# 过滤低流动性(最近 5 日日均成交额 ≥ 5000 万)
+easy-tdx screen strength --preset breakout --top 30 --min-amount 50000000 --table
+
+# 缩小范围 + 输出到文件
+easy-tdx screen strength --universe sz --top 30 --output sz_strength.json
+```
+
+输出示例(`--table`):
+
+```
+[*] 强势股排名 [steady] 共 50 只
+ 数据截止: 2026-06-24 | 中长期稳健强势:权重偏 60 日,波动率惩罚,选出稳着涨的票
+════════════════════════════════════════════════════════════════════════════════
+排名 代码 名称 现价 5日 20日 60日 波动率 强势分
+ *1 SZ300308 中际旭创 85.20 8.12% 15.34% 30.21% 0.0180 9.52
+ *2 SH600519 贵州茅台 1800.00 3.25% 5.10% 10.05% 0.0120 6.21
+```
+
+输出示例(JSON):
+
+```json
+{
+ "scan_time": "2026-06-25T10:30:00",
+ "preset": "steady",
+ "preset_desc": "中长期稳健强势:权重偏 60 日,波动率惩罚...",
+ "data_date": 20260624,
+ "total_ranked": 50,
+ "ranking": [
+ {"rank": 1, "code": "300308", "market": "SZ", "name": "中际旭创",
+ "last_close": 85.20, "last_date": 20260624,
+ "ret_5": 0.0812, "ret_20": 0.1534, "ret_60": 0.3021,
+ "vol_20": 0.0180, "strength": 9.52}
+ ]
+}
+```
+
+| 参数 | 说明 |
+|------|------|
+| `--preset` | 预设模式:`steady`(默认)/ `breakout` / `balanced` |
+| `--w5` `--w20` `--w60` | 自定义三周期权重(覆盖预设,自动归一化) |
+| `--vol-adjusted` / `--no-vol-adjusted` | 波动率惩罚开关(覆盖预设) |
+| `--top` | 返回前 N 名(默认 50) |
+| `--universe` | `all`(默认)/ `sh` / `sz` / 文件路径 |
+| `--min-listed-days` | 最小上市天数(默认 65,保证能算 60 日涨幅) |
+| `--min-amount` | 最近 5 日日均成交额下限(元,默认 0 不过滤) |
+| `--workers` | 并发进程数:`0` 串行 / `4+` 并发(推荐 4-8) |
+| `--names` | 在线补齐股票名称(默认关闭) |
+| `--output` | 输出 JSON 文件(默认 stdout) |
+
+> ⚠️ **数据时效**:strength 依赖本地 `.day` 文件。输出中的 `data_date` / `last_date` 字段标注数据截止日,请先用 `easy-tdx offline sync` 同步最新数据。
+
diff --git a/docs/cli.md b/docs/cli.md
new file mode 100644
index 0000000..0d55d23
--- /dev/null
+++ b/docs/cli.md
@@ -0,0 +1,83 @@
+# CLI 命令总览
+
+`easy-tdx` 全部命令速查表。按域的详细用法与示例见分域文档:
+
+| 域 | 文档 |
+|------|------|
+| 行情 / 分时 / 板块 / 资金 / 中金所 / 扩展市场 | [cli-market.md](./cli-market.md) |
+| 公告 / 财务 / F10 | [cli-finance.md](./cli-finance.md) |
+| 技术指标 / 通达信公式 | [cli-indicators.md](./cli-indicators.md) |
+| 缠论分析 | [chanlun.md](./chanlun.md) |
+| 回测 / 寻优 / 组合 / run-all | [cli-backtest.md](./cli-backtest.md) |
+| 选股扫描 / 强势股排名 | [cli-screen.md](./cli-screen.md) |
+| K 线仓库 / 离线数据 | [data-local.md](./data-local.md) |
+| Web 服务(serve) | [web-api.md](./web-api.md) |
+
+## 命令汇总
+
+| 命令 | 说明 |
+|------|------|
+| `ping` | 服务器延迟测速 |
+| `version` | 版本号 |
+| `kline` | K 线(日/周/月/分钟,支持复权) |
+| `quote` | 实时报价(单只/批量) |
+| `quote-list` | 市场分类排序报价(A/SH/SZ/KCB/CYB) |
+| `tick` | 分时图(单日/多日/历史) |
+| `transaction` | 逐笔成交 |
+| `board-list` | 板块列表(行业/概念/风格) |
+| `board-members` | 板块成分股报价 |
+| `board-summary` | 板块汇总(成交额、主力净流入、涨跌家数) |
+| `board-ranking` | 板块涨跌幅排行榜(行业/概念排行) |
+| `board-change-ranking` | 板块 N 日涨跌幅排行(支持指定截止日期) |
+| `belong-board` | 个股所属板块 |
+| `capital-flow` | 资金流向 |
+| `auction` | 集合竞价 |
+| `unusual` | 市场异动 |
+| `market-stat` | 全市场涨跌统计 |
+| `server-info` | 服务器交易时段 |
+| `symbol-info` | 个股特征快照 |
+| `indicator` | 技术指标计算(34 个:MACD/KDJ/RSI/BOLL/DMI/ATR...) |
+| `indicator-list` | 列出可用技术指标 |
+| `chanlun` | 缠论分析(笔/中枢/线段/买卖点/背驰,支持多级别联立) |
+| `indicator ZHUOYAO` | 捉妖大师信号(多周期 ROC 共振),详解见 [indicator-zhuoyao.md](./indicator-zhuoyao.md) |
+| `indicator BIAS_SIGNAL` | 30 日乖离率信号,详解见 [indicator-bias-signal.md](./indicator-bias-signal.md) |
+| `backtest` | 回测引擎(加载策略文件,输出绩效报告) |
+| `portfolio` | 多标的组合回测(共享资金池,均等分配,汇总绩效) |
+| `factor list` | 列出所有内置因子 |
+| `factor analyze` | 因子分析(IC/分层/衰减) |
+| `pfactor backtest` | 组合因子选股回测 |
+| `run-all` | 批量运行所有策略并排名(绩效排名 + 综合评分 + 可选图表) |
+| `optimize` | 参数网格寻优(单策略网格搜索,或 `--all` 一键寻优所有内置策略并排名) |
+| `strategies` | 列出内置策略注册表(名称/中文标签/参数默认值/预设寻优网格) |
+| `formula compute` | 通达信公式计算(命名布尔输出即买卖信号) |
+| `formula screen` | 公式批量选股(信号在最后一根 = 1 的标的) |
+| `formula backtest` | 公式回测(买/卖列自动挑选,输出绩效 + 评级 + 评分) |
+| `warehouse sync` | 本地 K 线仓库增量同步(DuckDB,需 `easy-tdx[warehouse]`) |
+| `warehouse query` | 仓库查询(默认忽略未收盘的临时 bar) |
+| `warehouse stats` | 仓库统计(各标的行数/数据范围) |
+| `warehouse check` | 仓库健康自检(缺口/除权跳变/新鲜度) |
+| `ccpm` | 中金所成交持仓排名(官网每日发布,按日落盘缓存) |
+| `announcement` | 公告检索(巨潮资讯网,独立数据源,支持下载 PDF) |
+| `screen scan` | 策略选股扫描(纯离线,全市场信号扫描) |
+| `screen rank` | 扫描结果回测排名(按夏普/回撤等指标排序) |
+| `screen strength` | 强势股排名(5/20/60 日涨幅加权,steady/breakout/balanced 三预设) |
+| `serve` | 启动 Web API 服务器(REST + WebSocket,需 `easy-tdx[web]`) |
+| `f10` | 财报三表(新浪:利润表/资产负债表/现金流量表) |
+| `finance-info` | 最新财务快照(通达信协议,30+ 项单期指标) |
+| `company-info` | F10 公司信息(无板块名列目录 / 有板块名读正文) |
+| `fund-flow` | 历史资金流向(CLI 暂未实现,Web API `/fund-flow/history` 可用) |
+| `ex kline` | 扩展市场 K 线 |
+| `ex quote` | 扩展市场报价 |
+| `ex quote-list` | 扩展市场商品列表 |
+| `ex tick` | 扩展市场分时 |
+| `ex markets` | 列出可用扩展市场 |
+| `offline home` | 检测通达信安装目录 |
+| `offline daily` | A 股日线(本地 .day 文件) |
+| `offline sync-daily` | 从服务端同步单只股票日线到本地 .day 文件 |
+| `offline sync-all` | 一键同步沪深全市场日线(扫描本地 .day 文件) |
+| `offline min` | 分钟线(本地 .5/.lc1/.lc5 文件) |
+| `offline ex-files` | 列出扩展市场可用文件 |
+| `offline ex-daily` | 扩展市场日线(期货/港股/外盘) |
+| `offline gbbq` | 股本变迁数据 |
+| `offline financial` | 历史财务数据 |
+| `offline blocks` | 自定义板块数据 |
diff --git a/docs/data-local.md b/docs/data-local.md
new file mode 100644
index 0000000..b83b118
--- /dev/null
+++ b/docs/data-local.md
@@ -0,0 +1,88 @@
+# 本地数据:K 线仓库与离线文件
+
+## 本地 K 线仓库(v1.26)
+
+行情沉淀为 DuckDB 单文件列存(可选依赖:`pip install easy-tdx[warehouse]`),增量同步 + 临时收盘价状态机 + 健康自检:
+
+```bash
+easy-tdx warehouse sync --symbols SH:600519,SZ:000001 # 首次全量,此后只补尾部
+easy-tdx warehouse query SH 600519 --count 30 # 默认忽略未收盘的临时 bar
+easy-tdx warehouse stats # 各标的行数 / 数据范围
+easy-tdx warehouse check # 缺口 / 除权跳变 / 新鲜度体检
+```
+
+## 离线数据 CLI
+
+从本地通达信安装目录直接读取数据文件,无需网络连接:
+
+```bash
+easy-tdx offline home # 检测通达信安装目录
+easy-tdx offline daily SH 600000 --count 10 --table # A 股日线
+easy-tdx offline min SZ 000001 --type lc5 --table # 分钟线(5min/lc1/lc5)
+easy-tdx offline ex-files --table # 列出扩展市场可用文件
+easy-tdx offline ex-daily 38#2_CPI --count 5 --table # 扩展市场日线(期货/港股/外盘)
+easy-tdx offline gbbq C:\new_jyplug\T0002\hq_cache\gbbq --table # 股本变迁
+easy-tdx offline financial C:\new_jyplug\vipdoc\fin\gpcw20260331.dat # 历史财务
+easy-tdx offline blocks C:\new_jyplug\T0002\blocknew --table # 自定义板块
+```
+
+从服务端获取最新日线并写入本地 .day 文件,替代通达信内置下载功能:
+
+```bash
+# 同步单只股票日线(自动增量/全量)
+easy-tdx offline sync-daily SZ 000001
+easy-tdx offline sync-daily SH 600519 --vipdoc C:\new_jyplug\vipdoc
+
+# 一键同步沪深全市场(每天一条命令)
+easy-tdx offline sync-all
+```
+
+> 建议在通达信关闭时执行 sync 命令,避免文件被锁定。空文件自动全量下载,已有数据只做增量追加。
+
+
+## 离线数据读取(Python)
+
+无需网络,从本地通达信安装目录直接读取:
+
+```python
+from easy_tdx.offline import detect_tdx_home, read_daily_bars, find_daily_bar_file
+from easy_tdx import Market
+
+home = detect_tdx_home()
+filepath = find_daily_bar_file(Market.SH, "600000")
+bars = read_daily_bars(filepath)
+```
+
+支持:日线、分钟线、扩展市场日线、板块、股本变迁、历史财务数据。
+
+## 离线数据写入同步(Python)
+
+从服务端获取最新数据并追加写入本地通达信数据文件:
+
+```python
+from easy_tdx.offline import (
+ encode_daily_bar, append_daily_bars, get_last_bar_date,
+ encode_5min_bar, append_5min_bars,
+ encode_lc_min_bar, append_lc_min_bars,
+)
+from easy_tdx import Market
+from easy_tdx.client import TdxClient
+
+# 追加日线到 .day 文件(自动跳过重复日期)
+from easy_tdx.offline import sync_daily_bars_from_security_bars
+
+# 手动编码单条记录
+bar_bytes = encode_daily_bar(bar, price_coeff=0.01, vol_coeff=0.01)
+
+# 获取文件末尾日期
+last_date = get_last_bar_date("C:/new_jyplug/vipdoc/sh/lday/sh600000.day")
+```
+
+v1.5.0 起可通过 CLI 直接使用:
+
+```bash
+easy-tdx offline daily SH 600000 --count 10 --table
+easy-tdx offline ex-files --table
+easy-tdx offline ex-daily 29#A1801 --table
+```
+
diff --git a/docs/development.md b/docs/development.md
new file mode 100644
index 0000000..f7e97a9
--- /dev/null
+++ b/docs/development.md
@@ -0,0 +1,87 @@
+# 开发环境与流程
+
+本文档是开发者的完整工作流参考。命令速查亦见 [CLAUDE.md](../CLAUDE.md)。
+
+## 环境初始化
+
+```bash
+git clone git@github.com:awayings/easy_tdx.git && cd easy_tdx
+uv sync --all-extras # 建 .venv 并装全部 extras(普通 uv sync 只装基础依赖)
+```
+
+CI 不用 uv,走 `pip install -e ".[dev]"` + `pip install -r requirements-dev.txt`。改依赖时两套流程都要考虑:pyproject.toml 只写下界+上界,`uv.lock` 与 `requirements-dev.txt` 才是可复现锁(dev 工具链锁定版本必须兼容 Python 3.10,CI 矩阵跑 3.10/3.12/3.13)。
+
+前端:`cd web-ui && npm ci && npm run build`(`build` = vue-tsc 类型检查 + vite build)。**`pip install -e .` 要求 `web-ui/dist` 存在**(hatchling `force-include` 把它打进 wheel 的 `easy_tdx/web/dist/`),所以改前端后、跑 Python 测试/安装前必须先构建。
+
+## 测试
+
+```bash
+python -m pytest tests/unit/ -v # 单元测试(无需网络,全部 mock)
+XMTDX_LIVE=1 python -m pytest tests/integration/ -v # 集成测试(连真实通达信服务器,默认 skip)
+python -m pytest tests/unit/ --cov src/easy_tdx --cov-fail-under=60 # 覆盖率门槛 60
+```
+
+三层测试分布:
+
+| 层 | 位置 | 跑在哪 | 说明 |
+|---|---|---|---|
+| 单元 | `tests/unit/` | CI(6 格矩阵)+ 本地 | 全 mock:`tests/fixtures/` 真实协议 hex dump + JSON 对照,`tests/golden/` 期望输出 |
+| 集成 | `tests/integration/` | **仅本地** | `XMTDX_LIVE=1` 才执行,连真实 TDX 服务器 smoke test |
+| 前端 E2E | `web-ui/e2e/*.spec.ts` | CI frontend job + 本地 | Playwright,`EASY_TDX_E2E_MOCK=1` 后端合成行情,不连真实服务器 |
+
+- `tests/conftest.py` 默认设 `EASY_TDX_NO_TASK_DB=1`,防单测污染 `~/.easy_tdx/tasks.db`;需要测试存储的用例用 `EASY_TDX_CONFIG_DIR` 指向 `tmp_path` 显式重开。
+- `tests/unit/test_ai_llm.py` 依赖 LLM API key 轮询,CI 用 `--ignore` 跳过,本地有 mock 可跑。
+- `asyncio_mode = "auto"`:async 测试无需 `@pytest.mark.asyncio`。
+
+## 静态检查
+
+```bash
+mypy src/ # strict 模式(pyproject 配置)
+ruff check src/ tests/ # E/F/I/UP 规则
+ruff format --check src/ tests/
+```
+
+mypy/ruff 均排除 `src/easy_tdx/exchange_margin.py`;`MyTT.py` 有手写 `MyTT.pyi` stub 保持 strict 检查。
+
+本地一键门禁(等价 CI 三 job 的本地版):
+
+```bash
+bash scripts/verify_ci.sh # ruff → format → mypy → pytest(排除 integration)→ 前端 build + E2E
+bash scripts/verify_ci.sh --fast # 只跑静态检查
+# 可选:ln -s ../../scripts/verify_ci.sh .git/hooks/pre-push
+```
+
+## 开发流程
+
+### a. 需求(Issue)
+
+- 功能/缺陷先在 GitHub Issues 提出;代码注释与提交说明中引用编号(如 `#58`、`审计 #9`)。
+- 复杂功能先写设计文档再动手(历史范本:`docs/board-overview-design.md`、`docs/hotspot-rolling-design.md`,以及 `docs/superpowers/` 下的 specs)。
+- 功能变更时同步评估文档更新(见「文档规范」)。
+
+### b. 开发与测试
+
+- 新功能/修复按 TDD 习惯先写红测试再实现;单元测试必须零网络、零真实服务器依赖。
+- 命令形态变更时 `easy-tdx --help` 自检;Web 路由变更时 `/docs` Swagger 自检。
+
+### c. 提交与 CI
+
+- 提交信息带前缀(`feat:` / `fix:` / `test:` / `docs:` / `refactor:`,可带作用域如 `feat(web):`),中文描述。push/PR 到 `main` 触发 `ci.yml`:
+ - test job:ubuntu/windows × py3.10/3.12/3.13 六格矩阵跑单测(覆盖率 ≥60)+ ruff + format
+ - mypy job:strict 模式(py3.13)
+ - frontend job:vue-tsc + Playwright mock E2E
+- **集成测试不进 CI**(依赖真实 TDX 服务器),发布前本地 `XMTDX_LIVE=1` 手动跑一遍。
+
+### d. 发布版本
+
+1. 收敛时打一个聚合提交 `release: vX.Y.Z — 中文一句话摘要`,同一提交内包含:代码与测试改动 + `pyproject.toml` 版本号 bump + `CHANGELOG.md` 新增版本小节。
+2. CHANGELOG 遵循 Keep a Changelog(zh-CN):`## [X.Y.Z] — 日期` 倒序最新在前,先一段加粗导语再按主题分 `###` 小节,条目带文件链接,测试小节报数字验收(如「全量 1820 通过,ruff / mypy / vue-tsc 全绿」)。**无 Unreleased 区,CHANGELOG 在 release 提交时写入**。
+3. 打 tag 推送即自动发布:`git tag vX.Y.Z && git push origin vX.Y.Z`,触发两个独立 workflow——`publish.yml`(PyPI trusted publishing,OIDC 无 token)与 `release.yml`(Windows EXE via PyInstaller + GitHub Release,正文含 SHA256/SmartScreen 说明;GitHub release notes 自动生成,**不读取 CHANGELOG.md**)。
+4. 版本单一来源是 `pyproject.toml`(前端品牌区版本来自后端 `GET /api/v1/meta`);文档一律不写死版本号。
+
+## 文档规范
+
+- **大小限制**:每份文档约 500 行为上限,超限必须拆分,通过 [index.md](./index.md) 与 README 文档导航串联。过大文件不可新增。
+- **类型两分**:教程(how-to,代码示例)与参考(速查/字段/命令表)原则上分开成文。
+- **可达性标准**:任何文档变更必须以「[README.md](../README.md) + [docs/index.md](./index.md) 可达的文件」为标准——新文件必须同时进 README 文档导航与 index.md;删除/改名必须同步修复全部链接。
+- **禁止硬编码版本横幅**:版本信息以 `pyproject.toml` 与 `CHANGELOG.md` 为准;功能引入说明里的版本标注(如「v1.29.1」)除外。
diff --git a/docs/field_mapping.md b/docs/field_mapping.md
index 42aa4c3..a180efa 100644
--- a/docs/field_mapping.md
+++ b/docs/field_mapping.md
@@ -1,6 +1,6 @@
# easy_tdx 字段映射表
-> 模型字段名 ↔ 中文含义 ↔ 数据类型对照
+> 模型字段名 ↔ 中文含义 ↔ 数据类型对照。方法速查见 [api_reference.md](./api_reference.md),上手教程见 [python-api.md](./python-api.md)。
---
@@ -313,3 +313,76 @@
| 9 | YEAR | 年线 |
| 10 | SEASON | 季线 |
| 11 | YEAR_ALT | 年线(备用) |
+
+## 枚举参考
+
+### Period(K 线周期)
+
+| 值 | 名称 | 说明 |
+|----|------|------|
+| 7 | `MIN_1` | 1 分钟 |
+| 0 | `MIN_5` | 5 分钟 |
+| 1 | `MIN_15` | 15 分钟 |
+| 2 | `MIN_30` | 30 分钟 |
+| 3 | `MIN_60` | 60 分钟 |
+| 4 | `DAILY` | 日线 |
+| 5 | `WEEKLY` | 周线 |
+| 6 | `MONTHLY` | 月线 |
+| 10 | `QUARTERLY` | 季线 |
+| 11 | `YEARLY` | 年线 |
+
+### Adjust(复权类型)
+
+| 值 | 名称 | 说明 |
+|----|------|------|
+| 0 | `NONE` | 不复权 |
+| 1 | `QFQ` | 前复权 |
+| 2 | `HFQ` | 后复权 |
+
+### Category(市场分类)
+
+| 值 | 名称 | 说明 |
+|----|------|------|
+| 0 | `SH` | 上证 A 股 |
+| 2 | `SZ` | 深证 A 股 |
+| 6 | `A` | 全部 A 股 |
+| 7 | `B` | B 股 |
+| 8 | `KCB` | 科创板 |
+| 12 | `BJ` | 北证 A 股 |
+| 14 | `CYB` | 创业板 |
+
+### BoardType(板块类型)
+
+| 值 | 名称 | 说明 |
+|----|------|------|
+| 0 | `HY` | 行业一级 |
+| 1 | `HY2` | 行业二级 |
+| 3 | `GN` | 概念 |
+| 4 | `FG` | 风格 |
+| 5 | `DQ` | 地区 |
+| 255 | `ALL` | 全部 |
+
+### SortType(排序字段)
+
+| 名称 | 说明 |
+|------|------|
+| `CODE` | 代码 |
+| `PRICE` | 现价 |
+| `CHANGE_PCT` | 涨幅% |
+| `VOLUME` | 成交量 |
+| `TOTAL_AMOUNT` | 成交额 |
+| `TURNOVER_RATE` | 换手% |
+| `MAIN_NET_AMOUNT` | 主力净额 |
+
+### ExMarket(扩展市场)
+
+| 值 | 名称 | 说明 |
+|----|------|------|
+| 28 | `ZZ_FUTURES` | 郑州商品 |
+| 29 | `DL_FUTURES` | 大连商品 |
+| 30 | `SH_FUTURES` | 上海期货 |
+| 31 | `HK_MAIN_BOARD` | 香港主板 |
+| 47 | `CFFEX_FUTURES` | 中金所期货 |
+| 48 | `HK_GEM` | 香港创业板 |
+| 74 | `US_STOCK` | 美国股票 |
+
diff --git a/docs/images/demo/1.png b/docs/images/demo/1.png
new file mode 100644
index 0000000..807a97f
Binary files /dev/null and b/docs/images/demo/1.png differ
diff --git a/docs/images/demo/2.png b/docs/images/demo/2.png
new file mode 100644
index 0000000..ebb1c89
Binary files /dev/null and b/docs/images/demo/2.png differ
diff --git a/docs/images/demo/3.png b/docs/images/demo/3.png
new file mode 100644
index 0000000..93c41f4
Binary files /dev/null and b/docs/images/demo/3.png differ
diff --git a/docs/images/demo/4.png b/docs/images/demo/4.png
new file mode 100644
index 0000000..3c46f40
Binary files /dev/null and b/docs/images/demo/4.png differ
diff --git a/docs/index.md b/docs/index.md
index c85d9ac..2d622e1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,16 +1,114 @@
-# easy-tdx 文档
+# easy-tdx 文档索引
+
+本索引是文档的目录目录:**新增或删除文档必须同步更新本文件与 README 文档导航**(见 [development.md](./development.md) 的文档规范)。每份文档 ≤500 行,超限拆分;教程(how-to)与参考(速查)分开成文。
+
+## 开始
+
+- [README](../README.md) — 项目门面:功能总览、30 秒上手、安装、文档导航(ReadTheDocs 落地页即其包含)
+
+## CLI 参考
+
+- [cli.md](./cli.md) — 全部命令速查表 + 按域导航
+- [cli-market.md](./cli-market.md) — 行情数据:报价 / K线 / 分时 / 板块 / 资金 / 中金所 / 扩展市场
+- [cli-finance.md](./cli-finance.md) — 财务与公告:巨潮公告检索 / 财报三表 / 通达信 F10
+- [cli-indicators.md](./cli-indicators.md) — 技术指标与公式:34 指标 / 通达信公式 / 捉妖 / 乖离率
+- [cli-backtest.md](./cli-backtest.md) — 回测与寻优:backtest / optimize / portfolio / run-all(含参数表)
+- [cli-screen.md](./cli-screen.md) — 选股扫描:全市场信号扫描 / 强势股排名
+- [chanlun.md](./chanlun.md) — 缠论分析(CLI + Python,含完整输出示例)
+
+## 本地数据
+
+- [data-local.md](./data-local.md) — K 线仓库(DuckDB)与 vipdoc 离线读写(CLI + Python 合一操作手册)
+
+## Web
+
+- [web-api.md](./web-api.md) — REST + WebSocket + SSE 端点与示例、帧规范
+- [web-ui.md](./web-ui.md) — 行情终端与回测工作台零代码操作手册
+- [packaging.md](./packaging.md) — Windows EXE 打包(PyInstaller)与分发
+
+## Python API
+
+- [python-api.md](./python-api.md) — 教程:连接管理 / MAC 协议 / 统一客户端 / 离线 / 缠论 / 公告 / 财报 / 实时轮询
+- [api_reference.md](./api_reference.md) — 参考:TdxClient 标准协议方法速查 + MAC 客户端方法表
+- [field_mapping.md](./field_mapping.md) — 参考:数据模型字段 ↔ 中文含义 ↔ 类型 + 枚举(标准 + MAC)
+
+## 回测与量化
+
+- [backtest_usage.md](./backtest_usage.md) — 回测引擎使用手册(策略 / 配置 / 结果)
+- [backtest-examples.md](./backtest-examples.md) — 完整示例集 + 注意事项
+- [quantitative-guide.md](./quantitative-guide.md) — 因子引擎与组合管理(基础)
+- [quantitative-advanced.md](./quantitative-advanced.md) — 滑点模型 / 执行仿真 / 归因分析 / 完整工作流
+
+## 指标深度
+
+- [indicator-zhuoyao.md](./indicator-zhuoyao.md) — 捉妖大师(ZHUOYAO)多周期 ROC 共振详解
+- [indicator-bias-signal.md](./indicator-bias-signal.md) — 30 日乖离率信号(BIAS_SIGNAL)详解
+
+## 开发者
+
+- [architecture.md](./architecture.md) — 七层架构图 / 源码树 / 分层要点
+- [development.md](./development.md) — 环境初始化 / 测试 / CI / 发布流程 / 文档规范
+
+## 协议与逆向
+
+- [protocol-reverse-engineering.md](./protocol-reverse-engineering.md) — 通达信二进制协议逆向过程
+- [protocol-unknown-fields.md](./protocol-unknown-fields.md) — 未知字段研究日志(活文档)
+
+## 历史归档(已实施 / 规划完成,供追溯)
+
+- [board-overview-design.md](./board-overview-design.md) — 行业/概念总览页设计稿(已上线)
+- [hotspot-rolling-design.md](./hotspot-rolling-design.md) — 市场热点滚动页设计稿(已上线)
+- [market-insights-roadmap.md](./market-insights-roadmap.md) — 盘面洞察功能路线图(已收尾)
+- [upgrade-plan-2026H2.md](./upgrade-plan-2026H2.md) — 2026 H2 升级计划(全部阶段完成)
+- [superpowers/](superpowers/) — 回测/因子/组合引擎的计划与设计存档(v1.11–v1.15 时代,非现行文档)
+
+## HTML 资产(仅 GitHub 可交互,ReadTheDocs 不发布)
+
+- [architecture.html](./architecture.html) — 38 模块交互式架构图(可缩放平移、导出 PNG)
+- [回测系统完全上手手册.html](./回测系统完全上手手册.html) — 零基础图文回测手册(13 章)
+
+---
```{toctree}
-:maxdepth: 2
-:caption: 目录
+:maxdepth: 1
+:caption: 文档目录
readme
+cli
+cli-market
+cli-finance
+cli-indicators
+cli-backtest
+cli-screen
+chanlun
+data-local
+web-api
+web-ui
+python-api
api_reference
field_mapping
backtest_usage
+backtest-examples
quantitative-guide
-protocol-reverse-engineering
-protocol-unknown-fields
+quantitative-advanced
indicator-zhuoyao
indicator-bias-signal
+architecture
+development
+packaging
+protocol-reverse-engineering
+protocol-unknown-fields
+board-overview-design
+hotspot-rolling-design
+market-insights-roadmap
+upgrade-plan-2026H2
+superpowers/plans/2026-06-09-backtest-engine
+superpowers/plans/2026-06-12-v1.11.0-factor-engine
+superpowers/plans/2026-06-12-v1.12.0-factor-analysis
+superpowers/plans/2026-06-12-v1.13.0-portfolio
+superpowers/plans/2026-06-12-v1.14.0-slippage-execution
+superpowers/plans/2026-06-12-v1.15.0-attribution
+superpowers/specs/2026-06-09-backtest-engine-design
+superpowers/specs/2026-06-12-advanced-backtest-design
+superpowers/specs/2026-06-12-quantitative-factor-engine-design
```
diff --git a/docs/python-api.md b/docs/python-api.md
new file mode 100644
index 0000000..205ce45
--- /dev/null
+++ b/docs/python-api.md
@@ -0,0 +1,421 @@
+# Python API 使用指南
+
+## 连接管理
+
+所有客户端支持 `from_best_host()` 自动选最低延迟服务器:
+
+```python
+from easy_tdx import MacClient
+
+with MacClient.from_best_host() as c:
+ df = c.get_stock_kline(...)
+```
+
+| 客户端 | 端口 | 覆盖范围 |
+|--------|------|----------|
+| `MacClient` / `AsyncMacClient` | 7709 | A 股行情(MAC 协议,推荐) |
+| `MacExClient` / `AsyncMacExClient` | 7727 | 港股/美股/期货(MAC 协议) |
+| `UnifiedTdxClient` / `AsyncUnifiedTdxClient` | 自动 | A 股 + 扩展市场统一入口 |
+| `TdxClient` / `AsyncTdxClient` | 7709 | A 股行情(标准协议) |
+
+## MAC 协议(推荐)
+
+### 报价
+
+```python
+from easy_tdx import MacClient, Market, Category, SortType, SortOrder
+
+with MacClient.from_best_host() as c:
+ # 批量报价(最多 80 只/次)
+ df = c.get_stock_quotes([(Market.SH, "600519"), (Market.SZ, "000858")])
+
+ # 市场分类排序报价
+ df = c.get_stock_quotes_list(
+ Category.A, count=20,
+ sort_type=SortType.CHANGE_PCT,
+ sort_order=SortOrder.DESC,
+ )
+```
+
+返回列:`market, code, name` + 动态字段(`pre_close, open, high, low, close, vol, amount, turnover, vol_ratio` 等)。
+
+### K 线(支持复权)
+
+```python
+from easy_tdx import MacClient, Market, Period, Adjust
+
+with MacClient.from_best_host() as c:
+ # 日K前复权
+ df = c.get_stock_kline(Market.SH, "600519", Period.DAILY, count=10, adjust=Adjust.QFQ)
+ # 5分钟线
+ df = c.get_stock_kline(Market.SZ, "000001", Period.MIN_5, count=100)
+```
+
+返回列:`datetime, open, close, high, low, vol, amount`。
+
+### 技术指标
+
+自动获取 200+ 条历史数据预热 EMA,返回最后 `count` 条带指标的结果:
+
+```python
+from easy_tdx import MacClient, Market, Period, Adjust
+from easy_tdx.indicator import compute_indicators, list_indicators
+
+with MacClient.from_best_host() as c:
+ # 便捷方法:获取 K 线 + 计算指标一步完成(默认前复权)
+ df = c.get_stock_kline_with_indicators(
+ Market.SH, "600519",
+ indicators=["MACD", "KDJ", "RSI", "BOLL"],
+ count=30,
+ )
+ # df 包含: datetime, open, close, high, low, vol, amount
+ # + MACD_DIF, MACD_DEA, MACD_HIST, KDJ_K, KDJ_D, KDJ_J, RSI,
+ # BOLL_UPPER, BOLL_MID, BOLL_LOWER
+
+ # 自定义指标参数
+ df = c.get_stock_kline_with_indicators(
+ Market.SH, "600519",
+ indicators=["MACD"],
+ params={"MACD": {"SHORT": 10, "LONG": 22}},
+ )
+
+ # 独立使用:对已有 DataFrame 计算指标
+ raw = c.get_stock_kline(Market.SH, "600519", Period.DAILY, count=200, adjust=Adjust.QFQ)
+ result = compute_indicators(raw, ["ATR", "CCI", "WR"], tail=30)
+
+ # 查看所有可用指标
+ for info in list_indicators():
+ print(info["name"], info["description"], info["outputs"])
+```
+
+支持 34 个技术指标:
+
+| 指标 | 输入 | 输出列 |
+|------|------|--------|
+| MACD | close | MACD_DIF, MACD_DEA, MACD_HIST |
+| KDJ | close, high, low | KDJ_K, KDJ_D, KDJ_J |
+| RSI | close | RSI |
+| BOLL | close | BOLL_UPPER, BOLL_MID, BOLL_LOWER |
+| DMI | close, high, low | DMI_PDI, DMI_MDI, DMI_ADX, DMI_ADXR |
+| ATR | close, high, low | ATR |
+| WR | close, high, low | WR1, WR2 |
+| CCI | close, high, low | CCI |
+| BIAS | close | BIAS1, BIAS2, BIAS3 |
+| OBV | close, vol | OBV |
+| VR | close, vol | VR |
+| EMV | high, low, vol | EMV, EMV_MA |
+| MFI | close, high, low, vol | MFI |
+| BRAR | open, close, high, low | AR, BR |
+| ASI | open, close, high, low | ASI, ASI_MA |
+| TRIX | close | TRIX, TRIX_MA |
+| DPO | close | DPO, DPO_MA |
+| MTM | close | MTM, MTM_MA |
+| ROC | close | ROC, ROC_MA |
+| EXPMA | close | EXPMA_12, EXPMA_50 |
+| BBI | close | BBI |
+| PSY | close | PSY, PSY_MA |
+| DFMA | close | DFMA_DIF, DFMA_DMA |
+| CR | close, high, low | CR |
+| KTN | close, high, low | KTN_UPPER, KTN_MID, KTN_LOWER |
+| XSII | close, high, low | XSII_TD1, XSII_TD2, XSII_TD3, XSII_TD4 |
+| MASS | high, low | MASS, MASS_MA |
+| TAQ | high, low | TAQ_UP, TAQ_MID, TAQ_DOWN |
+| ZHUOYAO | close | ZY_LONG, ZY_MID, ZY_SHORT, ZY_TREND |
+| BIAS_SIGNAL | close | BS_X, BS_SMA, BS_LMA |
+| SAR | high, low | SAR(抛物线转向/动态止损位) |
+| VWAP | close, high, low, vol | VWAP(N日滚动成交量加权均价) |
+| AROON | high, low | AROON_UP, AROON_DOWN, AROON_OSC |
+| FK | close | FK(EMA(2) 突破斜率外推 EMA(42)) |
+
+### 分时
+
+```python
+with MacClient.from_best_host() as c:
+ df = c.get_tick_chart(Market.SH, "600519") # 单日分时
+ df = c.get_tick_charts(Market.SH, "600519", days=3) # 多日分时(最多5天)
+ df = c.get_chart_sampling(Market.SH, "600519") # 240点缩略采样
+```
+
+### 逐笔成交
+
+```python
+with MacClient.from_best_host() as c:
+ df = c.get_transactions(Market.SH, "600519", count=100)
+ df = c.get_transactions(Market.SH, "600519", count=100, date=20250115)
+```
+
+### 板块
+
+```python
+from easy_tdx import BoardSortColumn, BoardType
+
+with MacClient.from_best_host() as c:
+ df = c.get_board_list(BoardType.GN) # 概念板块
+ df = c.get_board_list(sort_column=BoardSortColumn.SPEED) # 按涨速排序取涨速%
+ df = c.get_board_members("881001", sort_type=SortType.CHANGE_PCT)
+ df = c.get_belong_board(Market.SZ, "000001") # 个股所属板块
+
+ # 板块汇总:成交额、主力净流入、涨跌家数
+ summary = c.get_board_summary("881001")
+ # summary = {
+ # "member_count": 82,
+ # "amount": 5823456000.0, # 板块总成交额(元)
+ # "vol": 412356789, # 板块总成交量(股)
+ # "main_net_amount": -123456.0, # 当日主力净流入
+ # "main_net_3d": -567890.0, # 近3日主力净流入
+ # "main_net_5d": -234567.0, # 近5日主力净流入
+ # "up_count": 45,
+ # "down_count": 37,
+ # "members": DataFrame(...), # 成分股明细
+ # }
+
+ # 板块涨跌幅排行榜
+ df = c.get_board_ranking(BoardType.HY, top_n=10, sort_by="change_pct")
+ df = c.get_board_ranking(BoardType.GN, top_n=20, sort_by="main_net_amount")
+ # 返回列:code, name, change_pct, amount, vol, main_net_amount, up_count, down_count, member_count
+
+ # 板块 N 日涨跌幅排行(支持指定截止日期,默认全部)
+ df = c.get_board_change_ranking(BoardType.HY, days=20)
+ df = c.get_board_change_ranking(BoardType.GN, target_date=20250530, days=10, top_n=15)
+ # 返回列:code, name, close_end, close_start, change_pct
+```
+
+### 资金流向
+
+```python
+with MacClient.from_best_host() as c:
+ df = c.get_capital_flow(Market.SH, "600519")
+```
+
+返回列:`date, main_in, main_out, main_net, small_in/out/net, mid_in/out/net, large_in/out/net`。
+
+### 监控
+
+```python
+with MacClient.from_best_host() as c:
+ df = c.get_auction(Market.SH, "600519") # 集合竞价
+ df = c.get_unusual(Market.SH) # 市场异动
+ df = c.get_symbol_info(Market.SZ, "000001") # 个股特征快照
+ df = c.get_server_info() # 服务器交易时段
+```
+
+`get_unusual` 返回列含 `unusual_type`(类型码)与 `desc`(中文描述),共 19 种类型
+(主力买卖/加速拉升/急速拉升/盘中强弱/竞价异动/涨跌停/大单盘口等)。类型码→名称
+可用顶层常量映射:
+
+```python
+from easy_tdx import UNUSUAL_TYPE_NAMES
+
+df["type_name"] = df["unusual_type"].map(UNUSUAL_TYPE_NAMES)
+```
+
+## 扩展市场
+
+```python
+from datetime import date
+
+from easy_tdx import MacExClient, ExMarket, Period
+
+with MacExClient.from_best_host() as c:
+ count = c.goods_count(ExMarket.HK_MAIN_BOARD)
+ df = c.goods_list(ExMarket.HK_MAIN_BOARD, start=0, count=50)
+ df = c.goods_kline(ExMarket.US_STOCK, "AAPL", Period.DAILY, count=10)
+ df = c.goods_quotes([(ExMarket.HK_MAIN_BOARD, "00700")])
+ df = c.goods_tick_chart(ExMarket.HK_MAIN_BOARD, "00700")
+ df = c.goods_transaction(ExMarket.HK_MAIN_BOARD, "00700", count=100)
+ df = c.goods_transaction_all(ExMarket.HK_MAIN_BOARD, "00700", date(2026, 7, 3)) # 港股当日全部逐笔
+```
+
+> **逐笔成交排序**:通达信协议为**倒序**——`start=0` 指向最新一笔(收盘方向),`count=2000` 默认只取最近 2000 笔。港股单日成交常达数万笔(如 02715 约 1.3 万笔/日),若需当日全部成交,用 `goods_transaction_all`(仅港股股票类市场,自动按 1800/页翻页取全天,安全上限 9 万条;返回协议原生倒序,需正序展示自行 `df.iloc[::-1]`)。
+
+## 统一客户端
+
+```python
+from easy_tdx import UnifiedTdxClient, ExMarket, Market, Period
+
+with UnifiedTdxClient() as client:
+ # A 股 -- 自动路由到 MacClient
+ df = client.get_stock_kline(Market.SH, "600519", Period.DAILY, count=5)
+ df = client.get_stock_quotes([(Market.SH, "600519")])
+ df = client.get_board_list()
+
+ # 扩展市场 -- 自动路由到 MacExClient
+ df = client.goods_kline(ExMarket.HK_MAIN_BOARD, "00700", Period.DAILY, count=5)
+```
+
+## 标准协议
+
+```python
+from easy_tdx import TdxClient, Market, KlineCategory
+
+with TdxClient.from_best_host() as c:
+ count = c.get_security_count(Market.SH)
+ stocks = c.get_security_list(Market.SH, start=0)
+ quotes = c.get_security_quotes([(Market.SH, "600000"), (Market.SZ, "000001")])
+ bars = c.get_security_bars(Market.SZ, "002176", KlineCategory.DAY, 0, 100)
+ minute = c.get_minute_time_data(Market.SH, "600000")
+ trades = c.get_transaction_data(Market.SH, "600000", 0, 20)
+ flow = c.get_fund_flow(Market.SH, "600519")
+ blocks = c.get_block_info("block_gn.dat")
+ xdxr = c.get_xdxr_info(Market.SH, "600519")
+ stat = c.get_market_stat()
+```
+
+> **资金流口径注意**(Issue #55):`get_fund_flow` / `get_history_fund_flow` 按 0x0fb5 逐笔接口的"单笔成交额"分档,而该接口返回的记录是交易所真实逐笔**聚合**后的(实测 000001.SZ 单日约 17:1),分档看的也不是挂单额。结果:高价股小单档可不足成交额 1%、主力档常占 95%+,`main_net_inflow` 实质更接近"当日主动买卖总失衡"。东财/同花顺的"主力净流入"基于 L2 逐笔委托、按挂单额分档——两套口径**不可比**(实证同规则选股信号重合度仅约 14%),勿混用于同一张表或同一个因子。
+
+`AsyncTdxClient` 提供对应的 `async def` 方法,接口一一对应。
+
+## SecurityQuote 字段说明
+
+`get_security_quotes()` 返回的 DataFrame 包含以下特殊字段:
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `trading_status` | int | 交易状态标志。`0x8020`(32800) = 停牌,其余值表示正常交易或集合竞价 |
+| `open_amount` | float | 集合竞价成交金额(元)。仅个股有效,指数该字段无意义 |
+| `server_time` | str | 服务器时间,格式 `HH:MM:SS.mmm` |
+| `unknown_2` | int | 指数: 集合竞价成交金额/100;个股: 舍入残差≈0 |
+| `unknown_3` | int | 个股: 集合竞价成交金额/100;指数: 负值/无意义 |
+| `unknown_5-8` | int | 保留字段,恒为 0 |
+
+检测停牌:
+
+```python
+df = c.get_security_quotes([(Market.SH, "600000")])
+is_suspended = df.iloc[0]["trading_status"] == 0x8020
+```
+
+
+## 公告检索(巨潮资讯网)
+
+独立数据源(巨潮资讯网 cninfo),无需连接 TDX 行情服务器即可检索公司公告。
+标准库 urllib 实现,零额外依赖。
+
+```python
+from easy_tdx.cninfo import CninfoClient
+
+client = CninfoClient()
+
+# 检索公告(默认 30 条,最新在前)
+df = client.get_announcements("688017")
+# → DataFrame[title, type, date, url, code, org_id, announcement_id, announcement_time, pdf_url]
+
+# 翻页 + 自定义数量
+df = client.get_announcements("601088", count=10, page=2)
+
+# 返回示例(url 含 4 参数可直点打开,pdf_url 为 PDF 直链):
+# title type date url pdf_url
+# 0 关于召开2025年年度股东大会... 股东大会 2025-06-14 .../detail?stockCode=688017&announcementId=... http://static.cninfo.com.cn/.../xxx.PDF
+# 1 2024年年度报告 PDF 2025-03-28 .../detail?stockCode=688017&announcementId=... http://static.cninfo.com.cn/.../yyy.PDF
+```
+
+> - ``type`` 优先取 cninfo 的 ``announcementTypeName``;该字段对很多公告为 null
+> (数据源限制),此时回退到 ``adjunctType``(如 "PDF"),再为空给空字符串。
+> - ``url`` 必须含 4 参数(``stockCode``/``announcementId``/``orgId``/``announcementTime``)
+> 才能打开,少参数会 404。
+> - orgId 解析沿用 #19 修复:动态拉取官方映射表,查不到回退硬编码规则,
+> 保证 601xxx 等非标 orgId 段也能正常查询。
+
+### 下载公告 PDF
+
+```python
+# 下载最新一条公告的 PDF 到当前目录
+df = client.get_announcements("601088", count=5)
+path = client.download_pdf(df.iloc[0]) # 接受 Announcement 或 DataFrame 的一行
+print(path) # /abs/path/20260605_1225351400.PDF
+
+# 批量下载
+for _, row in df.iterrows():
+ try:
+ path = client.download_pdf(row, dest_dir="./pdfs")
+ except Exception as e:
+ print(f"跳过(无附件或失败): {e}")
+```
+
+## 财报三表(新浪财经)
+
+独立数据源(新浪财经),无需连接 TDX 行情服务器即可获取利润表/资产负债表/现金流量表。
+标准库 urllib 实现,零额外依赖。
+
+```python
+from easy_tdx.sina import SinaClient
+
+client = SinaClient()
+
+# 利润表(默认 8 期,最新在前)
+df = client.get_financial_report("600519", report_type="lrb")
+# → DataFrame,每行一期,列 = [报告期, 营业总收入, 营业总收入_同比, ...]
+
+# 资产负债表 / 现金流量表(report_type 也接受中文别名:利润表/资产负债表/现金流量表)
+df = client.get_financial_report("600519", report_type="fzb", num=4)
+df = client.get_financial_report("600519", report_type="llb", num=4)
+
+# 返回示例(item_value 已转 float,可直接数值计算):
+# 报告期 营业总收入 营业总收入_同比 营业收入 营业收入_同比
+# 0 2026-03-31 54702912385.23 0.06336 53909252220.51 0.06538
+# 1 2025-12-31 174000000000.00 0.10000 NaN NaN
+```
+
+> - ``item_value`` 是字符串(新浪原始格式),本实现转 float;空/非数值转 None
+> - 有同比的科目附加 ``{科目}_同比`` 列(float 比例,如 0.06336 = +6.3%)
+> - 大类标题行(如 ``流动资产``,原 ``item_value=""``)保留为 None,反映报表结构
+
+## 实时行情轮询(RealtimeDataFeed)
+
+> ⚠️ 通达信协议**没有服务端推送**,只有请求/响应。本模块的「实时」是 **轮询五档快照近似**
+> (默认约 3 秒延迟),适合盘中信号提醒、轻量监控;**不适合高频 / 逐笔撮合**。
+
+`EventBus` 自身是纯发布/订阅管道,不会产生数据。要让 `RealtimeStrategy` 跑起来,
+需要配合 `RealtimeDataFeed`:它自动完成 `get_stock_quotes → MarketEvent → bus.publish`。
+
+```python
+import asyncio
+from easy_tdx.mac.client import AsyncMacClient
+from easy_tdx.realtime import (
+ EventBus,
+ RealtimeStrategy,
+ MarketEvent,
+ RealtimeDataFeed,
+)
+
+
+class MyStrategy(RealtimeStrategy):
+ def on_tick(self, event: MarketEvent) -> None:
+ print(f"{event.market}{event.code} price={event.price} vol={event.volume}")
+
+
+async def main():
+ bus = EventBus()
+ strategy = MyStrategy()
+ bus.subscribe("SZ000001", strategy.on_tick) # 注意:key 必须带市场前缀
+
+ feed = RealtimeDataFeed(
+ bus=bus,
+ symbols=[(0, "000001"), (1, "600519")], # [(Market.SZ, code), ...],单批 ≤80 只
+ interval=3.0, # 轮询间隔(秒),下限 0.1
+ dedup=True, # (price, volume) 未变的标的跳过发布
+ # sessions=(), # 传空 tuple 表示全天轮询;默认仅 9:15-11:30 / 13:00-15:00
+ )
+ async with AsyncMacClient.from_best_host() as client:
+ await feed.run_async(client) # Ctrl+C 或 feed.stop() 退出
+
+
+asyncio.run(main())
+```
+
+同步客户端(`MacClient`)用 `run_sync`,feed 会把阻塞调用丢到线程池,不卡事件循环:
+
+```python
+from easy_tdx.mac.client import MacClient
+
+with MacClient.from_best_host() as client:
+ feed.run_sync(client)
+```
+
+> **关键坑(issue #34)**:
+> - 订阅 key 必须与 `publish` 内部拼的 `f"{market}{code}"` 一致,即 `"SZ000001"`
+> 而不是 `"000001"`;否则事件分发匹配不到。
+> - 传给 `subscribe` 的必须是**实例的绑定方法** `strategy.on_tick`,
+> 不是未绑定的类方法 `MyStrategy.on_tick`。
+> - 整个流程跑在 `asyncio.run()` 里,否则协程不会被调度。
+
diff --git a/docs/quantitative-advanced.md b/docs/quantitative-advanced.md
new file mode 100644
index 0000000..95fcbe6
--- /dev/null
+++ b/docs/quantitative-advanced.md
@@ -0,0 +1,308 @@
+# 量化进阶:执行仿真与归因
+
+滑点建模、执行仿真(TWAP/VWAP/限价单)、归因分析与完整工作流。因子/组合基础见 [quantitative-guide.md](./quantitative-guide.md)。
+
+## 1. 高级回测
+
+### 1.1 滑点模型
+
+4 种可插拔滑点模型,替代原有固定滑点:
+
+```python
+from easy_tdx.backtest import BacktestEngine
+from easy_tdx.backtest.slippage import (
+ FixedSlippage,
+ PercentSlippage,
+ SquareRootSlippage,
+ VolumeSlippage,
+)
+
+# 1. 固定每股滑点(与旧行为一致)
+model1 = FixedSlippage(per_share=0.01)
+
+# 2. 按金额百分比
+model2 = PercentSlippage(rate=0.001)
+
+# 3. 方根市场冲击模型(Almgren-Chriss 简化版)
+# impact = sigma * sqrt(participation_rate) * price * size * coeff
+# A 股量化主流:参与率 >5% 时冲击显著
+model3 = SquareRootSlippage(impact_coeff=0.1)
+
+# 4. 成交量比例滑点
+model4 = VolumeSlippage(base_bps=10.0)
+
+# 在 BacktestEngine 中使用
+engine = BacktestEngine(
+ MyStrategy,
+ cash=1_000_000,
+ slippage_model=SquareRootSlippage(impact_coeff=0.1),
+)
+result = engine.run(df)
+```
+
+**模型选择建议**:
+
+| 场景 | 推荐模型 | 参数 |
+|------|---------|------|
+| 快速原型 | `FixedSlippage` | `per_share=0.01` |
+| 中频策略 | `PercentSlippage` | `rate=0.001` |
+| 大额订单 | `SquareRootSlippage` | `impact_coeff=0.1` |
+| 低流动性股票 | `VolumeSlippage` | `base_bps=10.0` |
+
+### 1.2 执行仿真
+
+4 种执行模型,将单笔信号拆分为多笔子交易:
+
+```python
+from easy_tdx.backtest.execution import (
+ ImmediateExecution,
+ TWAPExecution,
+ VWAPExecution,
+ LimitExecution,
+)
+
+# 1. 即时成交(默认,与旧行为一致)
+exec1 = ImmediateExecution()
+
+# 2. TWAP:时间加权平均价格,N 根 K 线均匀拆单
+exec2 = TWAPExecution(n_bars=5)
+
+# 3. VWAP:成交量加权平均价格,按历史量分布拆单
+exec3 = VWAPExecution(n_bars=5, volume_lookback=20)
+
+# 4. 限价单:目标价挂单,TTL 内未触发则放弃
+exec4 = LimitExecution(ttl_bars=5)
+
+# 在 BacktestEngine 中使用
+engine = BacktestEngine(
+ MyStrategy,
+ cash=1_000_000,
+ execution_model=TWAPExecution(n_bars=3),
+ slippage_model=SquareRootSlippage(),
+)
+result = engine.run(df)
+```
+
+**执行模型选择**:
+
+| 场景 | 推荐模型 | 参数 |
+|------|---------|------|
+| 小额/快速验证 | `ImmediateExecution` | 默认 |
+| 大额建仓/平仓 | `TWAPExecution` | `n_bars=3~5` |
+| 追踪 VWAP 基准 | `VWAPExecution` | `n_bars=5` |
+| 精确入场价位 | `LimitExecution` | `ttl_bars=5` |
+
+**TWAP vs VWAP 示例**:
+
+```python
+# TWAP: 300 股拆成 3 笔 100 股,在 bar 1/2/3 以 close 执行
+engine = BacktestEngine(
+ MyStrategy, cash=100_000,
+ execution_model=TWAPExecution(n_bars=3),
+)
+
+# VWAP: 按成交量分布拆 300 股 — 成交量大的 bar 分配更多
+engine = BacktestEngine(
+ MyStrategy, cash=100_000,
+ execution_model=VWAPExecution(n_bars=3, volume_lookback=20),
+)
+
+# 限价单:在 50 元挂买入,5 根 K 线内 low <= 50 才成交
+class LimitBuyStrategy(Strategy):
+ def init(self): pass
+ def next(self):
+ if self._bar_index == 0:
+ self.buy(size=100, price=50.0) # 指定限价
+
+engine = BacktestEngine(
+ LimitBuyStrategy, cash=100_000,
+ execution_model=LimitExecution(ttl_bars=5),
+)
+```
+
+### 1.3 归因分析
+
+从回测结果生成归因报告:
+
+```python
+from easy_tdx.backtest import BacktestEngine
+from easy_tdx.backtest.attribution import AttributionAnalyzer
+
+# 运行回测
+engine = BacktestEngine(MyStrategy, cash=1_000_000)
+result = engine.run(df)
+
+# --- 成本归因 ---
+analyzer = AttributionAnalyzer(result.trades, result.equity_curve)
+cost_report = analyzer.cost_attribution()
+print(f"总收益: {cost_report.total_return:.2%}")
+print(f"总交易成本: {cost_report.total_trade_cost:.0f} 元")
+print(f" 佣金: {cost_report.commission_cost:.0f}")
+print(f" 滑点: {cost_report.slippage_cost:.0f}")
+print(f" 印花税: {cost_report.stamp_tax_cost:.0f}")
+
+# --- Brinson 归因(需要基准)---
+import numpy as np
+import pandas as pd
+# 构造基准曲线(如沪深300)
+benchmark = pd.DataFrame({
+ "datetime": result.equity_curve["datetime"],
+ "total": np.linspace(100000, 108000, len(result.equity_curve)),
+})
+analyzer = AttributionAnalyzer(result.trades, result.equity_curve, benchmark=benchmark)
+brinson_report = analyzer.brinson_attribution()
+print(f"配置贡献: {brinson_report.allocation_return:.2%}")
+print(f"选股贡献: {brinson_report.selection_return:.2%}")
+print(f"交叉效应: {brinson_report.interaction_return:.2%}")
+
+# --- 因子归因(需要因子数据)---
+exposures = pd.DataFrame({"momentum": [0.5, 0.3, 0.2], "quality": [0.1, -0.1, 0.0]})
+returns = pd.DataFrame({"momentum": [0.05, 0.03, 0.02], "quality": [0.01, -0.02, 0.0]})
+analyzer = AttributionAnalyzer(
+ result.trades, result.equity_curve,
+ factor_exposures=exposures, factor_returns=returns,
+)
+factor_report = analyzer.factor_attribution()
+for name, ret in factor_report.factor_returns.items():
+ print(f" {name}: {ret:.4f}")
+print(f"特质收益: {factor_report.specific_return:.4f}")
+
+# --- 完整报告(自动选择最佳归因模式)---
+full_report = analyzer.full_report()
+```
+
+**归因模式优先级**:因子归因 > Brinson 归因 > 成本归因。`full_report()` 自动选择数据最完整的模式。
+
+---
+
+## 2. CLI 命令
+
+```bash
+# 列出所有内置因子
+easy-tdx factor list --table
+
+# 因子分析(需要数据,输出示例代码)
+easy-tdx factor analyze momentum_20d
+
+# 组合因子回测(需要数据,输出示例代码)
+easy-tdx pfactor backtest momentum_20d --n-stocks 10 --optimizer factor_weighted
+```
+
+CLI 命令输出 Python API 示例代码,方便复制使用。完整的因子计算和组合回测建议通过 Python API 完成。
+
+---
+
+## 3. 完整工作流示例
+
+从数据获取到组合回测再到归因分析的完整管道:
+
+```python
+"""
+easy-tdx 量化研究完整工作流示例。
+
+依赖: pip install easy-tdx
+"""
+
+from easy_tdx import TdxClient, Market, KlineCategory
+from easy_tdx.factor import FactorEngine, FactorAnalyzer, preprocess
+from easy_tdx.portfolio import RebalanceEngine, FactorWeightedOptimizer
+from easy_tdx.backtest import BacktestEngine
+from easy_tdx.backtest.slippage import SquareRootSlippage
+from easy_tdx.backtest.execution import TWAPExecution
+from easy_tdx.backtest.attribution import AttributionAnalyzer
+
+# ── 1. 数据获取 ──────────────────────────────────────
+client = TdxClient()
+stock_pool = ["000001", "000858", "600519", "600036", "601318",
+ "000333", "002415", "601012", "600276", "000568"]
+
+data = {}
+for code in stock_pool:
+ market = Market.SH if code.startswith("6") else Market.SZ
+ data[code] = client.get_security_bars(
+ market, code, KlineCategory.DAY, 0, 500
+ )
+print(f"获取 {len(data)} 只股票数据")
+
+# ── 2. 因子计算 ──────────────────────────────────────
+engine = FactorEngine()
+factor_data = engine.compute_cross_section(
+ data, ["momentum_20d", "volatility_20d", "rsi_14"]
+)
+print(f"截面因子数据: {len(factor_data)} 行")
+
+# ── 3. 因子预处理 ─────────────────────────────────────
+clean = preprocess(
+ factor_data,
+ factor_names=["momentum_20d", "volatility_20d", "rsi_14"],
+ steps=["winsorize", "zscore", "fill_missing"],
+)
+
+# ── 4. 因子分析 ──────────────────────────────────────
+forward_returns = engine.compute_forward_returns(data, period=5)
+
+for factor_name in ["momentum_20d", "volatility_20d", "rsi_14"]:
+ analyzer = FactorAnalyzer(clean, forward_returns)
+ report = analyzer.full_report(factor_name)
+ print(f"\n── {factor_name} ──")
+ print(f" IC均值: {report.mean_ic:.4f} ICIR: {report.icir:.4f}")
+ print(f" 多头年化: {report.long_only_annual:.2%}")
+ print(f" 多空夏普: {report.long_short_sharpe:.4f}")
+
+# ── 5. 组合回测 ──────────────────────────────────────
+rebalancer = RebalanceEngine(
+ optimizer=FactorWeightedOptimizer(),
+ factor_name="momentum_20d",
+ n_stocks=5,
+ rebalance_freq="M",
+ cash=1_000_000,
+)
+result = rebalancer.run(data, start_date=20230101, end_date=20240101)
+print(f"\n── 组合回测 ──")
+print(f" 总收益: {result.performance['total_return']:.2%}")
+print(f" 年化: {result.performance['annual_return']:.2%}")
+print(f" 最大回撤: {result.performance['max_drawdown']:.2%}")
+print(f" 夏普: {result.performance['sharpe']:.4f}")
+
+# ── 6. 高级单策略回测(滑点 + 执行仿真)──────
+from easy_tdx.backtest import Strategy
+
+class MomentumStrategy(Strategy):
+ def init(self):
+ pass
+ def next(self):
+ if self._bar_index < 20:
+ return
+ ret = (self.data.close[0] - self.data.close[-20]) / self.data.close[-20]
+ if ret > 0.05 and self.position["size"] == 0:
+ self.buy(size=0)
+ elif ret < -0.03 and self.position["size"] > 0:
+ self.sell(size=0)
+
+bt_engine = BacktestEngine(
+ MomentumStrategy,
+ cash=500_000,
+ slippage_model=SquareRootSlippage(impact_coeff=0.1),
+ execution_model=TWAPExecution(n_bars=3),
+)
+# 选一只股票做回测
+bt_result = bt_engine.run(data["600519"])
+print(f"\n── 高级回测(600519)──")
+print(f" 总收益: {bt_result.performance['total_return']:.2%}")
+print(f" 夏普: {bt_result.performance['sharpe']:.4f}")
+
+# ── 7. 归因分析 ──────────────────────────────────────
+att_analyzer = AttributionAnalyzer(bt_result.trades, bt_result.equity_curve)
+cost_report = att_analyzer.cost_attribution()
+print(f"\n── 成本归因 ──")
+print(f" 总交易成本: {cost_report.total_trade_cost:.0f} 元")
+print(f" 佣金: {cost_report.commission_cost:.0f}")
+print(f" 滑点: {cost_report.slippage_cost:.0f}")
+print(f" 印花税: {cost_report.stamp_tax_cost:.0f}")
+
+print("\n完成。")
+client.close()
+```
+
+---
+
diff --git a/docs/quantitative-guide.md b/docs/quantitative-guide.md
index ad54f3e..3f00db2 100644
--- a/docs/quantitative-guide.md
+++ b/docs/quantitative-guide.md
@@ -18,12 +18,7 @@
- [4.1 权重优化器](#41-权重优化器)
- [4.2 风险模型](#42-风险模型)
- [4.3 再平衡引擎](#43-再平衡引擎)
-- [5. 高级回测](#5-高级回测)
- - [5.1 滑点模型](#51-滑点模型)
- - [5.2 执行仿真](#52-执行仿真)
- - [5.3 归因分析](#53-归因分析)
-- [6. CLI 命令](#6-cli-命令)
-- [7. 完整工作流示例](#7-完整工作流示例)
+- [高级回测(滑点/执行仿真/归因)、CLI 与完整工作流](#高级回测滑点执行仿真归因cli-与完整工作流) → 见 [quantitative-advanced.md](./quantitative-advanced.md)
---
@@ -309,309 +304,6 @@ for state in result.states[-5:]:
---
-## 5. 高级回测
-
-### 5.1 滑点模型
-
-4 种可插拔滑点模型,替代原有固定滑点:
-
-```python
-from easy_tdx.backtest import BacktestEngine
-from easy_tdx.backtest.slippage import (
- FixedSlippage,
- PercentSlippage,
- SquareRootSlippage,
- VolumeSlippage,
-)
-
-# 1. 固定每股滑点(与旧行为一致)
-model1 = FixedSlippage(per_share=0.01)
-
-# 2. 按金额百分比
-model2 = PercentSlippage(rate=0.001)
-
-# 3. 方根市场冲击模型(Almgren-Chriss 简化版)
-# impact = sigma * sqrt(participation_rate) * price * size * coeff
-# A 股量化主流:参与率 >5% 时冲击显著
-model3 = SquareRootSlippage(impact_coeff=0.1)
-
-# 4. 成交量比例滑点
-model4 = VolumeSlippage(base_bps=10.0)
-
-# 在 BacktestEngine 中使用
-engine = BacktestEngine(
- MyStrategy,
- cash=1_000_000,
- slippage_model=SquareRootSlippage(impact_coeff=0.1),
-)
-result = engine.run(df)
-```
-
-**模型选择建议**:
-
-| 场景 | 推荐模型 | 参数 |
-|------|---------|------|
-| 快速原型 | `FixedSlippage` | `per_share=0.01` |
-| 中频策略 | `PercentSlippage` | `rate=0.001` |
-| 大额订单 | `SquareRootSlippage` | `impact_coeff=0.1` |
-| 低流动性股票 | `VolumeSlippage` | `base_bps=10.0` |
-
-### 5.2 执行仿真
-
-4 种执行模型,将单笔信号拆分为多笔子交易:
-
-```python
-from easy_tdx.backtest.execution import (
- ImmediateExecution,
- TWAPExecution,
- VWAPExecution,
- LimitExecution,
-)
-
-# 1. 即时成交(默认,与旧行为一致)
-exec1 = ImmediateExecution()
-
-# 2. TWAP:时间加权平均价格,N 根 K 线均匀拆单
-exec2 = TWAPExecution(n_bars=5)
-
-# 3. VWAP:成交量加权平均价格,按历史量分布拆单
-exec3 = VWAPExecution(n_bars=5, volume_lookback=20)
-
-# 4. 限价单:目标价挂单,TTL 内未触发则放弃
-exec4 = LimitExecution(ttl_bars=5)
-
-# 在 BacktestEngine 中使用
-engine = BacktestEngine(
- MyStrategy,
- cash=1_000_000,
- execution_model=TWAPExecution(n_bars=3),
- slippage_model=SquareRootSlippage(),
-)
-result = engine.run(df)
-```
-
-**执行模型选择**:
-
-| 场景 | 推荐模型 | 参数 |
-|------|---------|------|
-| 小额/快速验证 | `ImmediateExecution` | 默认 |
-| 大额建仓/平仓 | `TWAPExecution` | `n_bars=3~5` |
-| 追踪 VWAP 基准 | `VWAPExecution` | `n_bars=5` |
-| 精确入场价位 | `LimitExecution` | `ttl_bars=5` |
-
-**TWAP vs VWAP 示例**:
-
-```python
-# TWAP: 300 股拆成 3 笔 100 股,在 bar 1/2/3 以 close 执行
-engine = BacktestEngine(
- MyStrategy, cash=100_000,
- execution_model=TWAPExecution(n_bars=3),
-)
-
-# VWAP: 按成交量分布拆 300 股 — 成交量大的 bar 分配更多
-engine = BacktestEngine(
- MyStrategy, cash=100_000,
- execution_model=VWAPExecution(n_bars=3, volume_lookback=20),
-)
-
-# 限价单:在 50 元挂买入,5 根 K 线内 low <= 50 才成交
-class LimitBuyStrategy(Strategy):
- def init(self): pass
- def next(self):
- if self._bar_index == 0:
- self.buy(size=100, price=50.0) # 指定限价
-
-engine = BacktestEngine(
- LimitBuyStrategy, cash=100_000,
- execution_model=LimitExecution(ttl_bars=5),
-)
-```
-
-### 5.3 归因分析
-
-从回测结果生成归因报告:
-
-```python
-from easy_tdx.backtest import BacktestEngine
-from easy_tdx.backtest.attribution import AttributionAnalyzer
-
-# 运行回测
-engine = BacktestEngine(MyStrategy, cash=1_000_000)
-result = engine.run(df)
-
-# --- 成本归因 ---
-analyzer = AttributionAnalyzer(result.trades, result.equity_curve)
-cost_report = analyzer.cost_attribution()
-print(f"总收益: {cost_report.total_return:.2%}")
-print(f"总交易成本: {cost_report.total_trade_cost:.0f} 元")
-print(f" 佣金: {cost_report.commission_cost:.0f}")
-print(f" 滑点: {cost_report.slippage_cost:.0f}")
-print(f" 印花税: {cost_report.stamp_tax_cost:.0f}")
-
-# --- Brinson 归因(需要基准)---
-import numpy as np
-import pandas as pd
-# 构造基准曲线(如沪深300)
-benchmark = pd.DataFrame({
- "datetime": result.equity_curve["datetime"],
- "total": np.linspace(100000, 108000, len(result.equity_curve)),
-})
-analyzer = AttributionAnalyzer(result.trades, result.equity_curve, benchmark=benchmark)
-brinson_report = analyzer.brinson_attribution()
-print(f"配置贡献: {brinson_report.allocation_return:.2%}")
-print(f"选股贡献: {brinson_report.selection_return:.2%}")
-print(f"交叉效应: {brinson_report.interaction_return:.2%}")
-
-# --- 因子归因(需要因子数据)---
-exposures = pd.DataFrame({"momentum": [0.5, 0.3, 0.2], "quality": [0.1, -0.1, 0.0]})
-returns = pd.DataFrame({"momentum": [0.05, 0.03, 0.02], "quality": [0.01, -0.02, 0.0]})
-analyzer = AttributionAnalyzer(
- result.trades, result.equity_curve,
- factor_exposures=exposures, factor_returns=returns,
-)
-factor_report = analyzer.factor_attribution()
-for name, ret in factor_report.factor_returns.items():
- print(f" {name}: {ret:.4f}")
-print(f"特质收益: {factor_report.specific_return:.4f}")
-
-# --- 完整报告(自动选择最佳归因模式)---
-full_report = analyzer.full_report()
-```
-
-**归因模式优先级**:因子归因 > Brinson 归因 > 成本归因。`full_report()` 自动选择数据最完整的模式。
-
----
-
-## 6. CLI 命令
-
-```bash
-# 列出所有内置因子
-easy-tdx factor list --table
-
-# 因子分析(需要数据,输出示例代码)
-easy-tdx factor analyze momentum_20d
-
-# 组合因子回测(需要数据,输出示例代码)
-easy-tdx pfactor backtest momentum_20d --n-stocks 10 --optimizer factor_weighted
-```
-
-CLI 命令输出 Python API 示例代码,方便复制使用。完整的因子计算和组合回测建议通过 Python API 完成。
-
----
-
-## 7. 完整工作流示例
-
-从数据获取到组合回测再到归因分析的完整管道:
-
-```python
-"""
-easy-tdx 量化研究完整工作流示例。
-
-依赖: pip install easy-tdx
-"""
-
-from easy_tdx import TdxClient, Market, KlineCategory
-from easy_tdx.factor import FactorEngine, FactorAnalyzer, preprocess
-from easy_tdx.portfolio import RebalanceEngine, FactorWeightedOptimizer
-from easy_tdx.backtest import BacktestEngine
-from easy_tdx.backtest.slippage import SquareRootSlippage
-from easy_tdx.backtest.execution import TWAPExecution
-from easy_tdx.backtest.attribution import AttributionAnalyzer
-
-# ── 1. 数据获取 ──────────────────────────────────────
-client = TdxClient()
-stock_pool = ["000001", "000858", "600519", "600036", "601318",
- "000333", "002415", "601012", "600276", "000568"]
-
-data = {}
-for code in stock_pool:
- market = Market.SH if code.startswith("6") else Market.SZ
- data[code] = client.get_security_bars(
- market, code, KlineCategory.DAY, 0, 500
- )
-print(f"获取 {len(data)} 只股票数据")
-
-# ── 2. 因子计算 ──────────────────────────────────────
-engine = FactorEngine()
-factor_data = engine.compute_cross_section(
- data, ["momentum_20d", "volatility_20d", "rsi_14"]
-)
-print(f"截面因子数据: {len(factor_data)} 行")
-
-# ── 3. 因子预处理 ─────────────────────────────────────
-clean = preprocess(
- factor_data,
- factor_names=["momentum_20d", "volatility_20d", "rsi_14"],
- steps=["winsorize", "zscore", "fill_missing"],
-)
-
-# ── 4. 因子分析 ──────────────────────────────────────
-forward_returns = engine.compute_forward_returns(data, period=5)
-
-for factor_name in ["momentum_20d", "volatility_20d", "rsi_14"]:
- analyzer = FactorAnalyzer(clean, forward_returns)
- report = analyzer.full_report(factor_name)
- print(f"\n── {factor_name} ──")
- print(f" IC均值: {report.mean_ic:.4f} ICIR: {report.icir:.4f}")
- print(f" 多头年化: {report.long_only_annual:.2%}")
- print(f" 多空夏普: {report.long_short_sharpe:.4f}")
-
-# ── 5. 组合回测 ──────────────────────────────────────
-rebalancer = RebalanceEngine(
- optimizer=FactorWeightedOptimizer(),
- factor_name="momentum_20d",
- n_stocks=5,
- rebalance_freq="M",
- cash=1_000_000,
-)
-result = rebalancer.run(data, start_date=20230101, end_date=20240101)
-print(f"\n── 组合回测 ──")
-print(f" 总收益: {result.performance['total_return']:.2%}")
-print(f" 年化: {result.performance['annual_return']:.2%}")
-print(f" 最大回撤: {result.performance['max_drawdown']:.2%}")
-print(f" 夏普: {result.performance['sharpe']:.4f}")
-
-# ── 6. 高级单策略回测(滑点 + 执行仿真)──────
-from easy_tdx.backtest import Strategy
-
-class MomentumStrategy(Strategy):
- def init(self):
- pass
- def next(self):
- if self._bar_index < 20:
- return
- ret = (self.data.close[0] - self.data.close[-20]) / self.data.close[-20]
- if ret > 0.05 and self.position["size"] == 0:
- self.buy(size=0)
- elif ret < -0.03 and self.position["size"] > 0:
- self.sell(size=0)
-
-bt_engine = BacktestEngine(
- MomentumStrategy,
- cash=500_000,
- slippage_model=SquareRootSlippage(impact_coeff=0.1),
- execution_model=TWAPExecution(n_bars=3),
-)
-# 选一只股票做回测
-bt_result = bt_engine.run(data["600519"])
-print(f"\n── 高级回测(600519)──")
-print(f" 总收益: {bt_result.performance['total_return']:.2%}")
-print(f" 夏普: {bt_result.performance['sharpe']:.4f}")
-
-# ── 7. 归因分析 ──────────────────────────────────────
-att_analyzer = AttributionAnalyzer(bt_result.trades, bt_result.equity_curve)
-cost_report = att_analyzer.cost_attribution()
-print(f"\n── 成本归因 ──")
-print(f" 总交易成本: {cost_report.total_trade_cost:.0f} 元")
-print(f" 佣金: {cost_report.commission_cost:.0f}")
-print(f" 滑点: {cost_report.slippage_cost:.0f}")
-print(f" 印花税: {cost_report.stamp_tax_cost:.0f}")
-
-print("\n完成。")
-client.close()
-```
-
----
## 向后兼容
diff --git a/docs/web-api.md b/docs/web-api.md
new file mode 100644
index 0000000..c19733b
--- /dev/null
+++ b/docs/web-api.md
@@ -0,0 +1,269 @@
+# Web API(REST + WebSocket)
+
+## 概述
+
+将 easy-tdx 暴露为 REST + WebSocket 服务,供前端、其他语言或远程调用。无需额外注册,零配置启动。
+
+## 安装
+
+```bash
+# 标准安装
+pip install easy-tdx[web]
+
+# 开发模式(从源码安装,支持热重载)
+pip install -e ".[web]"
+```
+
+## 快速启动
+
+```bash
+# 启动 Web API 服务器(自动连接最优 TDX 服务器)
+easy-tdx serve
+
+# 启动后浏览器打开 http://127.0.0.1:8000/docs 查看完整 API 文档(Swagger UI)
+# 也可以访问 http://127.0.0.1:8000/redoc 查看 ReDoc 格式文档
+
+# 指定端口和 TDX 服务器
+easy-tdx serve --port 8080 --tdx-host 119.147.212.81
+
+# 开发模式(代码修改后自动重载)
+easy-tdx serve --reload
+```
+
+> 💡 启动后访问 **http://127.0.0.1:8000/docs** 可以看到完整的交互式 API 文档,支持在线调试每个接口。
+
+## REST API 示例
+
+```bash
+# ── 基础行情 ──
+# 获取深圳市场证券数量
+curl "http://localhost:8000/api/v1/security/count?market=SZ"
+
+# 获取股票K线
+curl "http://localhost:8000/api/v1/bars?market=SZ&code=000001&category=DAY&count=100"
+
+# 批量获取实时行情
+curl -X POST "http://localhost:8000/api/v1/quotes" \
+ -H "Content-Type: application/json" \
+ -d '{"stocks": [{"market": "SZ", "code": "000001"}, {"market": "SH", "code": "600000"}]}'
+
+# 市场统计
+curl "http://localhost:8000/api/v1/market/stat"
+
+# 全市场强势股排名(基于本地 vipdoc 数据,扫描约 30-60 秒)
+# steady = 中长期稳健 / breakout = 近期妖股 / balanced = 均衡
+curl "http://localhost:8000/api/v1/market/strength?preset=breakout&top_n=20"
+
+# 自定义权重 + 过滤低流动性(日均成交额 ≥ 5000 万)
+curl "http://localhost:8000/api/v1/market/strength?w5=0.5&w20=0.3&w60=0.2&min_amount=50000000&top_n=30"
+
+# 板块信息(标准协议)
+curl "http://localhost:8000/api/v1/block?filename=block_gn.dat"
+
+# ── 板块分析(MAC 协议)──
+# 行业板块列表
+curl "http://localhost:8000/api/v1/board-mac/list?board_type=HY&count=50"
+
+# 板块成分股(按涨幅排序)
+curl "http://localhost:8000/api/v1/board-mac/members?board_symbol=881001&count=20"
+
+# 个股所属板块
+curl "http://localhost:8000/api/v1/board-mac/belong?market=SZ&code=000001"
+
+# 板块摘要(含主力净流入、涨跌家数)
+curl "http://localhost:8000/api/v1/board-mac/summary?board_symbol=881001"
+
+# 行业板块涨幅排名 Top 10
+curl "http://localhost:8000/api/v1/board-mac/ranking?board_type=HY&top_n=10"
+
+# 板块 20 日涨幅排行
+curl "http://localhost:8000/api/v1/board-mac/change-ranking?board_type=HY&days=20&top_n=10"
+
+# ── 资金 / 信息 ──
+# 个股资金流向(主力/散户净流入)
+curl "http://localhost:8000/api/v1/mac/capital-flow?market=SH&code=600519"
+
+# 个股基本信息快照
+curl "http://localhost:8000/api/v1/mac/symbol-info?market=SZ&code=000001"
+
+# 服务器交易时段信息
+curl "http://localhost:8000/api/v1/mac/server-info"
+
+# ── 公告检索(巨潮资讯网,独立数据源)──
+# 检索公司公告(无需 TDX 行情服务器)
+curl "http://localhost:8000/api/v1/announcements?code=688017&count=30&page=1"
+# 返回每条含 url(4 参数可直点打开)和 pdf_url(PDF 直链):
+# {"data": [{"title":"...","type":"...","date":"...","url":".../detail?stockCode=...","pdf_url":"http://static.cninfo.com.cn/.../xxx.PDF",...}], "count": 30}
+
+# ── 财报三表(新浪财经,独立数据源)──
+# 利润表(type: lrb/fzb/llb)
+curl "http://localhost:8000/api/v1/sina/financial-report?code=600519&type=lrb&num=8"
+# 返回每行一期(最新在前),列为科目名(float)+ {科目}_同比(如有):
+
+# ── 排行 / 竞价 / 异动 ──
+# 全 A 涨幅排行前 20
+curl "http://localhost:8000/api/v1/mac/quote-list?category=A&count=20&sort_type=CHANGE_PCT"
+
+# 集合竞价数据
+curl "http://localhost:8000/api/v1/mac/auction?market=SZ&code=000001"
+
+# 市场异动行情
+curl "http://localhost:8000/api/v1/mac/unusual?market=SH&count=50"
+
+# ── 扩展市场(期货/港股/美股)──
+# 港股 K 线
+curl "http://localhost:8000/api/v1/ex/bars?market=HK_MAIN_BOARD&code=00700&category=DAY&count=30"
+
+# 美股实时报价
+curl "http://localhost:8000/api/v1/ex/quote?market=US_STOCK&code=AAPL"
+
+# ── 技术指标 ──
+# 列出所有可用指标
+curl "http://localhost:8000/api/v1/indicator/list"
+
+# 计算 MACD + KDJ 指标
+curl -X POST "http://localhost:8000/api/v1/indicator/compute" \
+ -H "Content-Type: application/json" \
+ -d '{"data": [{"open":10,"close":10.5,"high":11,"low":9.5,"vol":1000}], "indicators": ["MACD", "KDJ"]}'
+
+# ── 缠论分析 ──
+curl -X POST "http://localhost:8000/api/v1/chanlun/analyze" \
+ -H "Content-Type: application/json" \
+ -d '{"market": "SZ", "code": "000001", "category": "DAY", "count": 200}'
+
+# ── 板块总览(一次取全部板块:当日涨跌幅 + 涨速 + 3/5/20日/YTD 涨幅 + 领涨股,服务端 15s 缓存)──
+# board_type: HY 行业一级 / HY2 行业二级 / GN 概念 / FG 风格 / DQ 地区
+curl "http://localhost:8000/api/v1/board-mac/overview?board_type=HY"
+curl "http://localhost:8000/api/v1/board-mac/overview?board_type=GN"
+
+# ── 回测任务(WebUI 回测工作台同款后端)──
+# 列出内置策略及参数 schema
+curl "http://localhost:8000/api/v1/backtest/strategies"
+# 提交异步回测(strategy 见 /backtest/strategies;完整字段与 portfolio/multi/optimize/wf/evaluate
+# 各端点的请求体以 /docs 的 Swagger 为准),返回 task_id
+curl -X POST "http://localhost:8000/api/v1/backtest/run/async" \
+ -H "Content-Type: application/json" \
+ -d '{"strategy": "ma_cross", "symbol": "SZ:000001", "category": "DAY", "count": 2000}'
+# 轮询任务结果(对比页/导出亦走 /backtest/tasks)
+curl "http://localhost:8000/api/v1/backtest/tasks/"
+
+# ── 策略库(保存的策略持久化 SQLite)──
+curl "http://localhost:8000/api/v1/strategies"
+
+# ── 自选股 ──
+curl "http://localhost:8000/api/v1/watchlist"
+curl -X POST "http://localhost:8000/api/v1/watchlist" \
+ -H "Content-Type: application/json" -d '{"market": "SH", "code": "600519", "name": "贵州茅台"}'
+
+# ── AI 解读(模型 Key 只存本地 ~/.easy_tdx/llm.json)──
+curl "http://localhost:8000/api/v1/llm/config" # 当前配置 + Provider 预设
+curl -X POST "http://localhost:8000/api/v1/llm/chat/async" \
+ -H "Content-Type: application/json" \
+ -d '{"prompt": "解读这份回测报告:..."}' # 后台任务,GET /llm/chat/tasks/{id} 轮询
+
+# ── 交易时段(自动刷新门控用)──
+curl "http://localhost:8000/api/v1/market/session"
+```
+
+## WebSocket 实时行情
+
+`/api/v1/ws/realtime/{symbol}`(v1.28 起接通数据源):连接即订阅指定标的,服务端
+经 `RealtimeDataFeed`(按 `interval` 秒轮询五档快照 → `EventBus`)推送 tick 帧;
+连接断开自动退订,无人订阅时完全停止轮询。盘外时段默认只睡不拉(交易时段过滤),
+本地冒烟/演示可配合 `EASY_TDX_E2E_MOCK=1` 的合成行情随时验证(见
+`scripts/ws_smoke.py`)。
+
+```javascript
+const ws = new WebSocket("ws://localhost:8000/api/v1/ws/realtime/SZ000001");
+
+ws.onmessage = (event) => {
+ const frame = JSON.parse(event.data);
+ if (frame.type === "tick") {
+ // {type:"tick", symbol:"SZ000001", market:"SZ", code:"000001",
+ // price:10.5, volume:12345, ts:1760000000.0,
+ // open, high, low, pre_close, amount, name}
+ console.log(frame.symbol, frame.price, frame.ts);
+ } else if (frame.type === "ping") {
+ // 服务端 30s 空闲心跳,忽略即可(客户端无须回包)
+ }
+};
+
+// 动态订阅更多标的(服务端回 {"type":"status","msg":"subscribed SH600000"})
+ws.send(JSON.stringify({action: "subscribe", symbol: "SH600000"}));
+// 退订
+ws.send(JSON.stringify({action: "unsubscribe", symbol: "SH600000"}));
+```
+
+### 服务端推送帧(JSON)
+
+| type | 触发 | 字段 |
+|------|------|------|
+| `tick` | 轮询到标的的最新快照(价格/量变化才推,约 `interval` 秒一拍) | `symbol`、`market`、`code`、`price`、`volume`、`ts`(epoch 秒)、`open`、`high`、`low`、`pre_close`、`amount`、`name` |
+| `ping` | 连续 30s 未收到客户端消息的心跳 | —(客户端忽略即可,无须回包) |
+| `status` | 客户端 subscribe/unsubscribe 的确认 | `msg`(如 `subscribed SH600000`) |
+| `error` | 非法 JSON / 未知 action / 超出订阅上限 | `msg` |
+
+### 客户端控制消息(JSON 文本帧)
+
+```json
+{"action": "subscribe", "symbol": "SH600000"}
+{"action": "unsubscribe", "symbol": "SH600000"}
+```
+
+### 行为约定
+
+- **连接即订阅** path 上的 symbol;断开自动退订全部标的。
+- **按需轮询**:订阅集合为空时服务端不产生任何行情请求;去重后标的总数上限
+ 80(`get_stock_quotes` 协议约束)。
+- **交易时段**:默认 A 股时段外只睡不拉(无 tick 帧,心跳照发);mock 模式
+ (`EASY_TDX_E2E_MOCK=1`)不受限制。
+- **背压**:消费过慢时丢最旧快照保最新,不积压。
+- 环境变量:`EASY_TDX_WS_INTERVAL`(轮询间隔秒数,默认 3.0)。
+
+浏览器接入建议(自动重连 + 心跳容忍):`onclose` 后指数退避重连(参考
+`web-ui/src/stores/quotes.ts` 对 SSE 的同类处理);`{"type":"ping"}` 心跳帧直接
+忽略、不回包;连续 N 秒无任何帧(含 ping)再视为僵死连接主动重连。
+
+### 前端接入方式(自动重连 + 心跳容忍)
+
+```typescript
+function connectRealtime(symbol: string, onTick: (f: TickFrame) => void) {
+ let retry = 0
+ let ws: WebSocket | null = null
+ const open = () => {
+ ws = new WebSocket(`ws://${location.host}/api/v1/ws/realtime/${symbol}`)
+ ws.onmessage = (e) => {
+ const frame = JSON.parse(e.data)
+ if (frame.type === 'tick') { retry = 0; onTick(frame) } // ping/status 忽略
+ }
+ ws.onclose = () => {
+ retry += 1
+ setTimeout(open, Math.min(1000 * 2 ** (retry - 1), 30_000)) // 指数退避
+ }
+ }
+ open()
+ return () => ws?.close()
+}
+```
+
+> 说明:看板/自选页的实时刷新已由 SSE `/stream/quotes`(全量快照、单连接共享)
+> 承担;WS 通道定位是**按需订阅单标的 tick 事件**(后续实时策略信号的接入点),
+> 两条链路按场景选用,不要求同时连接。手动冒烟见 `scripts/ws_smoke.py`。
+
+
+## API 文档
+
+启动服务后访问:
+- Swagger UI: http://localhost:8000/docs
+- ReDoc: http://localhost:8000/redoc
+
+## 编程 API
+
+```python
+from easy_tdx.web import create_app
+import uvicorn
+
+app = create_app(host="119.147.212.81", port=7709)
+uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
diff --git a/docs/web-ui.md b/docs/web-ui.md
new file mode 100644
index 0000000..b36da9a
--- /dev/null
+++ b/docs/web-ui.md
@@ -0,0 +1,101 @@
+# Web UI 使用手册
+
+## 概述
+
+行情终端 + 回测可视化 Web UI(v1.17 新增,v1.23 升级为行情终端)。不想写命令行?用浏览器。`easy-tdx serve` 一条命令启动,浏览器自动打开 `http://localhost:8000`。
+
+
+
+
+
+
+
+Web UI 包含两大模块:
+
+- **行情终端**——侧边栏专业终端布局(行情:市场看板 / 行业总览 / 概念总览 / 自选行情 / 龙头池 / 期货持仓排名):
+ - **市场看板**:五大指数实时行情(SSE 推送)、全市场涨跌统计(涨/跌/平/涨停/跌停 + 堆叠条)、行业/概念板块热度榜、涨幅榜/跌幅榜、两市异动雷达(加速拉升/封涨停板/大单托盘等),点击个股打开五档盘口 + 分时/日K 对话框;
+ - **行业总览 / 概念总览**(v1.32.1):全部行业(一级/二级可切)/概念板块一屏尽览——板块广度统计条、涨跌幅分布直方图、热力图与表格双视图、搜索过滤、涨幅/跌幅/涨速异动三榜、翻红/翻绿轮动时间线,30s 自动刷新(休市暂停);点击板块复用详情弹窗(分时/日K + 成分股涨跌榜直达个股);
+ - **自选行情**:输入 6 位代码一键加自选(SQLite 持久化),全表实时刷新(SSE),行内迷你分时图,点击行看个股详情;
+ - **龙头池**:159 只核心龙头名单一键只扫龙头(名单仅为扫描范围,不构成任何推荐);
+ - **期货持仓排名**(v1.29.1):中金所每日成交/持仓前 20 名会员一键采集(品种下拉 + 日期选择 + 自动回溯最近交易日开关),合约页签自动标注主力,前 20 名合计多单/空单/净持仓概览,三组排名并排表格;附「品种一览」「多单空单加减仓怎么看」新手科普(重点:排名看不出套保还是投机,空单多 ≠ 看空市场);
+ - **实时推送架构**:后端单条轮询循环 fan-out 到所有 SSE 连接(交易时段 ~8s 一拍,盘外降频 60s,无人订阅自动休眠),前端指数退避重连。
+- **回测工作台**——浏览器里选标的、挑策略、调参数,K 线买卖点、净值回撤、25 项绩效指标一目了然。支持组合回测、参数网格寻优、多策略结果对比、策略库(SQLite 持久化)与多策略资金分仓、信号雷达、Walk-Forward / 一条龙附加分析、**AI 解读与解读历史**(分析:单标的回测 / 组合回测 / 参数寻优 / 结果对比 / 策略库 / 信号雷达 / AI 解读历史),全程零代码。
+
+## 启动
+
+**前置条件:**
+
+```bash
+# 需安装 web 可选依赖(FastAPI + Uvicorn)
+pip install -e ".[web]"
+```
+
+**启动(一条命令):**
+
+```bash
+# 启动后端 + 自动打开浏览器(默认 http://localhost:8000)
+easy-tdx serve
+
+# 自定义端口/不自动开浏览器
+easy-tdx serve --port 8080 --no-open-browser
+```
+
+> 后端启动后约 1-2 秒会自动弹出浏览器。前端界面已编译进 `web-ui/dist/`,由后端同源托管,无需单独跑前端开发服务器。后端行情连接失败时回测路由仍可用(用内联数据),但取行情功能需要后端连通通达信服务器。
+
+## 桌面版(EXE)
+
+不想装 Python?下载 EXE 直接用(面向零基础用户):
+
+Windows 用户可以下载打包好的单一 EXE(约 80-150MB),双击即可使用,无需安装 Python/Node 或任何依赖:
+
+1. 到 [Releases 页面](../../releases) 下载最新的 `easy-tdx-<版本>-windows.exe`
+2. 双击运行(首次会被 SmartScreen 拦截,点"更多信息 → 仍要运行")
+3. 等待 2-5 秒,浏览器自动打开回测界面
+4. 右下角任务栏出现小图标,右键 → "退出" 可关闭
+
+EXE 打包方法见 [`packaging.md`](./packaging.md)。
+
+## 回测工作台页面
+
+打开浏览器后,「分析」分组下是回测工作台的核心页面:
+
+### 1. 单标的回测(首页 `/`)
+
+左侧配置面板从上到下填写,右侧自动出图:
+
+- **取行情**:选市场(深/沪/北),填 6 位代码,选周期(日线/周线/分钟线),设日期范围(默认最近 3 年),点「取行情」。超过 800 根会自动翻页拼接
+- **选策略**:下拉选 18 个内置策略之一(双均线交叉、MACD、布林带、RSI、KDJ、唐安奇通道、CCI 等),选中后参数表单自动出现,按推荐范围调参
+- **资金与成本**:初始资金、佣金率、滑点、成交模式(默认 next_open 下一根开盘成交)
+- 点「开始回测」,右侧依次出:K 线主图(红三角=买入、绿钉=卖出)、净值曲线与回撤双轴图、25 项绩效指标表(总收益/夏普/最大回撤/胜率/盈亏比/Ulcer/VaR/SQN 等)、成交记录明细
+- 结果区右上角有「💾 保存策略」按钮,把当前策略 + 标的 + 成绩快照存进策略库,下次直接载入或参与组合回测
+
+### 2. 组合回测(`/portfolio`)
+
+- 添加多只标的(如 SZ:000001、SH:600519),选策略和日期范围
+- 点「开始组合回测」,右侧出:组合整体绩效(加权收益率)、组合净值曲线(各标的按日期对齐求和)、各标的净值归一化叠加对比图、各标的绩效横向对比表
+- 同样有「保存策略」按钮,可把整个组合配置存进策略库
+
+### 3. 参数寻优(`/optimize`)
+
+- 先取行情(同单标的),选策略
+- 勾选 1-2 个想寻优的参数,填入取值列表(逗号分隔,如 fast 填 `5,10,20,30`),页面实时显示网格点数(上限 200)
+- 点「开始寻优」,右侧出:最优结果摘要、参数热力图(2 参数时,颜色映射收益率)、所有网格点排名表
+- 排名表每行有「查看」按钮,点击跳转单标的回测页,自动填充该参数组合跑完整回测
+
+### 4. 结果对比(`/compare`)
+
+- 左侧列出最近 20 个已完成的回测任务(含单标的和组合)
+- 勾选 2-4 个,右侧出:归一化净值叠加图(初始=1,看相对走势)、8 项核心指标横向对比表(总收益/夏普/最大回撤/胜率/盈亏比/交易数/年化/波动率)
+
+### 5. 策略库(`/strategies`,v1.17.11 新增)
+
+- 保存你觉得不错的策略,下次直接载入或重跑。数据存在本地 SQLite 单文件(`~/.easy_tdx/strategies.db`,重启不丢)
+- 每张卡片展示策略名、标的、保存时的成绩快照(总收益/夏普/回撤)、标签、备注、创建时间
+- **载入**:点「载入」跳转对应回测页(单标的/组合),自动回填标的、日期、策略参数,可直接重跑
+- **多策略组合回测**:勾选多个单标的策略(卡片左上角复选框),点顶部「组合回测(N)」——每个策略各拿 1/N 资金、各跑在它保存时的原标的上(取最新行情),净值曲线按日期对齐求和,看综合表现。结果区展示:组合净值曲线、25 项完整绩效指标(与单标的同口径)、各策略绩效对比表、净值叠加图、各策略当前持仓表(回测结束时谁还套着票)
+
+## 注意事项
+
+> ⚠️ **任务不持久化**:回测结果存在后端进程内存,重启 `easy-tdx serve` 后清空。对比页只能选当前运行期间产生的任务。**策略库除外**——保存到策略库的策略持久存在 SQLite,重启不丢。
+
+技术栈:Vue 3 + Vite + TypeScript + Pinia + ECharts(按需引入,构建产物约 800KB)。前端代码在 `web-ui/` 目录,独立 `package.json`,不依赖 Python 环境。
diff --git a/examples/06_finance/README.md b/examples/06_finance/README.md
index 00baf9f..81aa112 100644
--- a/examples/06_finance/README.md
+++ b/examples/06_finance/README.md
@@ -1,6 +1,6 @@
# 06. 财务数据与 F10 公司信息
-通达信原生协议(TdxClient)提供两类财务/公司数据,独立于 [新浪三表 `f10`](../../README.md#财务):
+通达信原生协议(TdxClient)提供两类财务/公司数据,独立于 [新浪三表 `f10`](../../docs/cli-finance.md#财务):
| 命令 / 接口 | 数据 | 说明 |
|-------------|------|------|