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 截图 1 + +Web UI 截图 2 + +Web UI 截图 3 + +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 环境。