15 KiB
股市回测平台 — 技术选型推荐(纯回测范围)
一句话总体推荐:Python 单语言后端(FastAPI + 自研回测引擎)为"大脑与事实源",Vue 单页前端为"渲染器与控制台",PostgreSQL/TimescaleDB + Redis 承载数据,三者用 OpenAPI 契约解耦。
范围明确:本平台只做历史回测 + 回放式模拟交易,不做实盘。因此砍掉了所有实盘专属基建(券商网关、Windows broker、程序化交易报备、限速、Kill Switch、talipp 流式指标等)——这些正是最难维护、风险最高的部分。
核心判断:A 股的量化生态(数据源、回测库)几乎只以 Python 存在——"后端选 Python"是生态约束下的唯一合理解。
范围变更记录(2026-08)
原方案含实盘量化。经确认只做回测 + 回放式模拟,不做实盘后,移除:
| 移除项 | 原因 |
|---|---|
| vnpy / xtquant / xttrader 实盘网关 | 实盘下单专用,无实盘即不需要 |
| Windows broker 节点(永久运维分叉) | QMT 必须常驻 Windows;无实盘 → 纯 Linux,部署统一 |
| 程序化交易报备 / 硬限速(≤299笔/秒) | 只对实盘程序化交易生效,纯回测不受管 |
| Kill Switch / 风控闸门 / 幂等下单 / 断线重连 | 全是"防回测 bug 造成真实亏损"的护栏 |
| talipp 流式增量指标 | 实盘每根新K线增量算用;回测批量算用 TA-Lib/自研即可 |
| CTP(期货)、券商资质、投资者适当性 | 实盘门槛 |
保留并强化的核心:单一回测引擎(fast/strict)、防过拟合体检、基准归因、复权因子管道、A股交易成本建模、指标单一事实源。
澄清:最早的"对接交易所显示买卖点"——不需要真连交易所。回测信号标在历史 K 线上即是买卖点显示。
一、技术栈总表
| 层 | 选型 | 作用 | 说明 |
|---|---|---|---|
| 前端基座 | Vue 3.5 + Vite + TypeScript + Pinia | SPA、状态管理 | 用户已有 Vue 生态 |
| UI 组件 | PrimeVue 5 | 表单/参数面板/大表/筛选 | DataTable 成熟度对数据密集控制台是决定性的 |
| K 线主图 | lightweight-charts 5.x | 纯渲染器:主图 + 指标副图 + createSeriesMarkers 标买卖点 |
TradingView 出品;不用任何内置指标算法(单一事实源) |
| 分析面板 | ECharts 6.1 + vue-echarts | 净值/回撤/收益分布/热力图 | WebGL 大数据 |
| 前端指标预览 | 防抖调后端算 | 单一指标实现 | 前端不保留任何指标库 |
| 后端服务 | FastAPI + Uvicorn + Pydantic v2 | REST + 自动 OpenAPI 契约 | 契约先于业务锁定 |
| 回测引擎(单一) | 自研:Polars/Numpy 向量化内核 + 事件化规则注入 | 唯一事实源;fast/strict 两档 | 不做"快层+真层"双引擎 |
| 指标计算 | 纯 pandas/numpy 实现(MVP)→ TA-Lib(生产) | 回测/图表共享同一份结果 | Windows 上 TA-Lib C 库难装,MVP 用纯 Python,接口留好可替换 |
| 任务编排 | MVP 同步;长回测引入 Dramatiq + 进程池 | 绕 GIL,多进程并行参数扫描 | 进度落库 checkpoint |
| 元数据库 | PostgreSQL 16/17 + async SQLAlchemy 2.0 + Alembic | 用户/策略/回测元数据/回测运行注册表 | — |
| 时序主库 | TimescaleDB 2.28+(同一 PG 实例的扩展) | K 线 Hypertable + Continuous Aggregates 多周期 + 列式压缩 | 用户已有 Postgres → 直接装扩展即可;MVP 暂用 SQLite 零配置起步 |
| 缓存 | Redis(规模化后) | 热点 K 线缓存、任务队列 broker | MVP 不引入 |
| 交易日历 | exchange_calendars(XSHG)+ tushare trade_cal 兜底 |
回测/回放对齐、版本化 | XSHG 覆盖截至 2025,2026+ 需兜底 |
| A股数据源 | Tushare Pro(主)+ AKShare(校验)+ BaoStock(末位) | 历史 K 线/复权/财务/分红 | 多源冗余;2025-08 Tushare 曾停摆 |
| MVP 数据 | 合成数据种子(随机游走 OHLCV) | 零依赖即时可跑 | DataProvider 接口下可一行切到 Tushare |
| 港美股数据 | Polygon(更名 Massive)付费档 | 历史+实时(远期) | 仅开发期 mock 用免费源 |
| 鉴权 | JWT + RBAC(多用户时) | 用户/策略级权限 | MVP 单用户可暂缓 |
二、系统架构
┌──────────────────────────────────────────────────────────────────┐
│ 前端 (Vue 3.5 + Vite + TS + Pinia + PrimeVue) │
│ ┌────────────┐ ┌──────────────────┐ ┌────────────────────────┐ │
│ │ PrimeVue 5 │ │ lightweight- │ │ ECharts 6.1 │ │
│ │ 参数表单 │ │ charts 5.x │ │ 净值/回撤/归因/过拟合 │ │
│ │ 策略选择 │ │ K线+指标副图+ │ │ │ │
│ │ │ │ 买卖点markers │ │ │ │
│ └────────────┘ └──────────────────┘ └────────────────────────┘ │
│ shallowRef+markRaw; series 不入响应式; onMounted/onBeforeUnmount │
└──────────────┬───────────────────────────────────────────────────┘
│ REST(类型化客户端,由 OpenAPI 生成)
▼
┌──────────────────────────────────────────────────────────────────┐
│ 后端 (FastAPI + Uvicorn + Pydantic v2) [纯 Linux] │
│ ┌────────────┐ ┌──────────────────────┐ ┌────────────────────┐ │
│ │ REST │ │ DataProvider 适配器 │ │ 领域模型契约 │ │
│ │ OpenAPI 契约│ │ Tushare/AKShare/ │ │ Instrument/Bar/ │ │
│ │ │ │ Synthetic/复权管道 │ │ Signal/Order/Fill/ │ │
│ │ │ │ │ │ Position/Portfolio/ │ │
│ │ │ │ │ │ Strategy/Universe/ │ │
│ │ │ │ │ │ Calendar │ │
│ └────────────┘ └──────────────────────┘ └────────────────────┘ │
│ │ ┌─────────────────────────────────────────────────┐ │
│ │ │ 单一回测引擎 (Numpy/Polars + 规则注入) │ │
│ │ │ ├ fast 档: 关 T+1/费用, 交互试探 │ │
│ │ │ └ strict档: T+1/涨跌停/封板/成交量约束/全费用 │ │
│ │ │ + 防过拟合体检(walk-fwd/OOS/FDR/敏感性) │ │
│ │ │ + 基准归因(超额/信息比率/beta/alpha) │ │
│ │ │ + 回测运行注册表(run_id→策略版本+参数+数据快照) │ │
│ │ └─────────────────────────────────────────────────┘ │
└────────┼─────────────────────────────────────────────────────────┘
▼
┌───────────────────┐ ┌──────────────────────┐
│ PostgreSQL 16/17 │ │ DataProvider 数据源 │
│ + TimescaleDB │ │ Tushare(主)/AKShare │
│ K线 Hypertable │ │ BaoStock(末位) │
│ CAGG 多周期 │ │ Synthetic(MVP) │
│ + 关系/元数据 │ │ Polygon(港美股,远期) │
└───────────────────┘ └──────────────────────┘
三个必须分离的关注点
| 关注点 | 落在哪 | 为什么 |
|---|---|---|
| 信号生成(指标+策略) | Python 后端,单一实现 | 回测与图表必须用同一份结果,否则"看着赚回测亏" |
| 订单执行(撮合) | PaperBroker(虚拟成交) | 隔离策略逻辑与成交逻辑;无实盘则永远是虚拟 |
| 数据获取 | DataProvider 适配器 + 复权管道 | 上游随时失效,必须可热切换 |
先于业务落地的"领域模型契约"(MVP 第一周定稿)
Instrument / Bar(OHLCV+复权标识+周期) / Signal / Order / Fill(含费用明细) / Position / Portfolio / Strategy(+版本) / Universe(股票池+成分历史) / TradingCalendar。
三、关键取舍裁决
- 纯 Python 单语言栈。 A 股数据源与回测生态只以 Python 存在;性能瓶颈在向量化计算与多进程,不在 HTTP 层。
- 数据库:TimescaleDB 单库起步。 它是 Postgres 扩展(用户已有 Postgres 可直接装),同一库内"信号 JOIN 行情 JOIN 订单"+ ACID。分钟级全市场(≈十亿行)确定要做时,再把分钟K/Tick 下沉 ClickHouse 分层,关系层与日K 留 PG。
- K 线主图用 lightweight-charts 5.x(纯渲染器)。 不用任何内置指标算法;指标值全部后端算好喂给它。不用 klinecharts(内置指标会与回测两套算法漂移)。
- 决策级指标全在后端 Python。 前端预览一律调后端,前端不保留指标库实现。
- 单一回测引擎 + 质量档位(fast/strict),不做双引擎。同一撮合逻辑、同一代码路径,仅开关不同:
fast:关 T+1/费用/成交量约束,纯向量化,交互试探、参数网格。strict:全开 A 股规则,出可审计报告。
vectorbt 开源版基于 pandas/NumPy,不支持 Polars(Polars 属闭源付费 PRO)。向量化内核自研(Polars/Numba)。
四、A股交易成本表(已修正,可配置 + 按生效日期版本化,基准日 2026-08)
| 费用项 | 费率 | 方向 | 生效依据 |
|---|---|---|---|
| 印花税 | 0.05%(千分之零点五) | 单边卖出 | 2023-08-28 减半(原 0.1%) |
| 过户费 | 0.001%(万分之零点一) | 沪深双边均收 | 2022 年统一下调(原沪市万 0.2 单边) |
| 佣金 | 万 1 含规费(最低 5 元) | 双边 | 2026 主流;最低 5 元须建模 |
| 滑点 | 1-2 tick | 双边 | 可配置 |
费用必须是参数表 + 生效日期版本化 + 显式基准日,非硬编码常量。
五、分阶段落地路线
阶段 0:回测 MVP + 可视化(进行中)
跑通"输入 MACD/RSI/KDJ 参数 → 后端回测 → 画 K线+指标+收益+最大回撤+夏普+买卖点"。SQLite 默认库 + 合成数据零依赖可跑。不引入:Redis、Dramatiq、任何行情/交易网关、K8s。
阶段 1:完整回测 + 回放式模拟
- strict 档完整性:T+1、涨跌停(主板±10%/科创创业±20%/北交所±30%)、成交量约束(单笔 ≤ bar 成交量 10-25%)、封板建模(一字板不可买/不可卖)、停牌事件流、100 股整数手、全费用、滑点。
- 股票池 + 成分历史(生存者偏差):用"当时成分股"而非"今天成分股"。
- 防过拟合体检(回测报告一等公民):walk-forward、OOS 切分、参数敏感性、多重比较修正(Bonferroni/FDR/White's Reality Check/SPA)、样本自由度告警。
- 基准归因:超额收益、信息比率、跟踪误差、beta/alpha、up/down capture。
- 回测运行注册表:
run_id → 策略版本 + 参数快照 + 数据快照 + 环境指纹 + 结果指纹。 - 结果缓存 + 多回测对比:相同三元组命中缓存;参数微调前后 diff 视图。
- 切真实数据源(Tushare 主 / AKShare 校验),全量本地落地缓存;复权因子管道(增量 + 回溯回填)。
- 切到用户 Postgres + TimescaleDB(hypertable + CAGG)。
- 回放式模拟盘:选历史区间逐 bar 虚拟交易(PaperBroker)。
阶段 2:分钟级 + 规模化 + 工程化
- 分钟级全市场回测(≈十亿行):按需引入 ClickHouse 分层(分钟K/Tick),关系层与日K 留 PG。
- Dramatiq + 进程池跑长回测/参数扫描,进度落库 checkpoint。
- 可观测:结构化日志 + 核心 metric(回测耗时 P95、数据延迟)→ OpenTelemetry + Grafana。
- K8s + ArgoCD 部署。
六、关键风险与对策
6.1 数据正确性
- A股复权是最大隐患:复权因子是每日增量、且会回溯修正的流。维护复权因子管道,查询显式选择前/后复权,否则回测收益与图表价格不一致。
- 生存者偏差:用当时成分股回测;Tushare 为主、AKShare 校验,差异超阈值告警。
- 单点数据源风险已验证:2025-08-26 TusharePro 停运,仅依赖 Tushare 的系统当天停摆 → 强制多源 + 本地落地缓存。
- 数据治理:新鲜度监控、质量校验(OHLC 不合理/成交量为负/缺口)、数据血缘。
6.2 性能瓶颈
- 最致命陷阱:把大数据塞进 Pinia reactive。必须
shallowRef + markRaw+ 仅加载可见区间按 pan/zoom 增量拉取;series 数据不入响应式;图表实例 onMounted/onBeforeUnmount 严格绑定。 - GIL 误用:CPU 密集回测走独立进程池,FastAPI 路由只 dispatch。
- 十亿级撑爆内存:谓词下推按 symbol+区间载入;前端服务端聚合/降采样再渲染。
- TimescaleDB:chunk 对齐查询模式;CAGG 刷新滞后读防护(
materialized_only+ 时间戳护栏);并发读副本/连接池。
6.3 可维护性
- 避免停维库:backtrader 自 2023 停维、pandas-ta 停滞。指标自研隔离层,便于将来换 TA-Lib。
- 回测可复现性:每次回测绑定策略版本+参数+数据快照三元组。
6.4 合规(已大幅缩水)
- 数据源 ToS 对商业/再分发有约束;公开免费接口(新浪/东财/腾讯)盘中高并发被封,仅作降级。商用上线前须取得数据授权(Wind/Choice/聚宽/Tushare 高级档)。
6.5 版本陷阱
- lightweight-charts v5:
createSeriesMarkers(series, markers)取代 v4setMarkers()。 - TimescaleDB 2.28+ 弃 PG15,锁 PG16/17。
- exchange_calendars
XSHG覆盖截至 2025,2026+ 需 extensions/tushare 兜底。 - ECharts v6 WebGL 在低端机需回归测试。