TuAlpha
TuAlpha 是基于 Tushare 数据、面向中国 A 股股票与 ETF 的日频事件驱动回测框架。框架提供类似 Zipline 的策略 API,但资产、日历、行情、财务和指数权重均由 TuAlpha 自有 HDF5 Reader/Writer 管理。
当前版本为
1.0.0。仅支持多头现金账户、股票和 ETF;不支持期货、期权、融资融券或 ETF 申赎。
功能
- RQAlpha 风格的
apis / core / model / broker / data / cmds分层结构 - HDF5/NumPy/Pickle 固定 Bundle
- 常用横截面字段使用同一 HDF5 文件内的 packed 连续数组加速,旧 schema 7 Bundle 可兼容回退
- 股票、ETF、指数原始日线统一存入
daily.h5 - Tushare SSE
trade_cal开放日固化到trade_dates.npy - D 日收盘决策,订单最早 D+1 按开盘或收盘价成交
- 涨停禁止买入、跌停禁止卖出;停牌、无行情、零成交量禁止成交
- 主板、创业板和 ETF 按 100 股/份交易
- 科创板 200 股起,之后按 1 股递增;北交所 100 股起,之后按 1 股递增
- 所有股票和 ETF 统一 T+1
- 支持印花税、佣金、经手费和过户费
- 支持
raw、qfq、hfq,策略价格与成交原始价格分离 - 支持每日指标、资金流、历史行业、历史 ST、PIT 财务和 PIT 指数权重
- 中文 Plotly HTML 报告、每日持仓 CSV 和每日权重贡献归因
tualpha update将 Tushare 数据直接写入暂存 HDF5,合并并原子发布新 Bundle
框架结构
src/tualpha/
├── apis/ # 策略 API
├── core/ # 执行上下文和回测循环
├── model/ # Asset、Order、Portfolio、Transaction
├── broker/ # Broker、Matcher、市场规则和费用
├── data/ # BarData、DataPortal、交易日历
│ └── bundle/ # HDF5 协议、Reader、Writer、在线更新
├── cmds/ # 命令行入口
└── reporting.py # 指标与报告
顶层导入保持兼容,例如 from tualpha import run_algorithm, order_target_percent。详细职责和依赖方向见 docs/architecture.md。
安装
推荐 64 位 CPython 3.12:
uv add tualpha
源码开发:
uv sync --dev
uv run pytest
数据目录
默认根目录为 ~/.tualpha,最终 Bundle 固定为 ~/.tualpha/bundle:
~/.tualpha/
├── bundle/
│ ├── daily.h5 # 股票、ETF、指数原始日线
│ ├── adj_factor.h5 # 股票、ETF 复权因子
│ ├── daily_basic.h5 # 股票每日指标
│ ├── stk_limit.h5 # 每日涨跌停价格
│ ├── finance.h5 # 四类财务宽表及 PIT 元数据
│ ├── industry.h5 # 每日历史行业
│ ├── stock_st.h5 # 每日历史 ST 状态
│ ├── moneyflow.h5 # 每日资金流
│ ├── index_weight.h5 # PIT 指数成分与权重
│ ├── trade_dates.npy # Tushare SSE 开放交易日
│ ├── assets.pk # 资产信息、generation 和文件清单
│ └── suspend_d.h5 # 每日停牌状态
├── update-status.json # 更新、构建、验证和旧数据清理记录
├── .locks/ # 更新锁和 Bundle 发布锁
├── .staging/ # 构建临时区,成功后自动删除
└── .rollback/ # 发布中断恢复目录
bundle/ 必须且只能包含上述 12 个文件。
回测只读取最终 Bundle,不读取 staging 文件。tualpha update 不创建、读取或保留 CSV 缓存。详细协议见 docs/bundle-format.md。
更新数据
必须通过环境变量提供 Token:
export TUSHARE_TOKEN="your-token"
tualpha update
常用参数:
tualpha update --from 20260101 --to 20260821
tualpha update --repair-from 20250101
tualpha update --full --from 20000101
tualpha update --lookback 20
tualpha update --index-weight 000016.SH
tualpha update --dry-run --json
更新流程:
- 增量下载行情、复权、每日指标、资金流、行业、ST、停牌、财务和指数权重。
- 下载结果立即写入
.staging/update/<run_id>/downloads.h5中按证券代码哈希分桶的临时 HDF5;不生成 CSV 或 Parquet。 - 对分页接口检测重复页;按公告日期合并财务历史修订,并按快照替换指数权重。
- 将暂存数据与活动 Bundle 合并,整体写出带新 generation 的 12 文件 HDF5 Bundle。
- 校验固定文件集合、generation、dtype、日期、PIT 规则、文件大小和 SHA-256。
- 持发布锁原子替换固定
bundle/,并从最终路径重新打开验证。 - 原子写入
update-status.json,成功后删除 staging;失败时活动 Bundle 保持不变并保留 staging 诊断信息。
--full 通过同一在线 HDF5 管线丢弃旧数据并重建完整 generation:已有 Bundle 时默认沿用其起始日;首次全量构建必须指定 --from。项目不再提供离线 CSV 导入 API。
index_weight 默认维护 000300.SH、000852.SH、000905.SH、000906.SH 和 899050.BJ,原始权重单位为百分比。
快速开始
from tualpha import order_target_percent, record, run_algorithm, symbol
def initialize(context):
context.asset = symbol("510300.SH")
def handle_data(context, data):
closes = data.history(context.asset, "close", 20)
if len(closes) < 20:
return
target = 0.95 if closes.iloc[-1] > closes.mean() else 0.0
order_target_percent(context.asset, target)
record(close=closes.iloc[-1], ma20=closes.mean())
result = run_algorithm(
start="2020-01-01",
end="2025-12-31",
initialize=initialize,
handle_data=handle_data,
capital_base=1_000_000,
adjustment="qfq",
execution_time="open",
benchmark="000300.SH",
output_dir="outputs/demo",
strategy_name="沪深300 ETF 趋势策略",
column_cache_mib=2048,
)
print(result.summary())
策略在 D 日回调中最多读取到 D 日数据,新订单最早 D+1 成交。成交、现金、费用和涨跌停判断始终使用原始价格。
日频列缓存默认上限为 2,048 MiB,可通过 run_algorithm(column_cache_mib=...) 或环境变量 TUALPHA_COLUMN_CACHE_MIB 调整。大型固定资产池优先使用 data.current_arrays(),它返回与资产顺序一致的只读 NumPy 数组。
核心 API
symbol(code)order()、order_value()、order_percent()order_target()、order_target_value()、order_target_percent()- 对应批量形式:
order_many()、order_value_many()、order_percent_many()、order_target_many()、order_target_value_many()、order_target_percent_many() order和单笔order_target是固定数量委托,可能因现金不足拒单- value/percent 类订单在 D+1 撮合前计算组合权益,再用实际
open/close和限定金额计算数量 - 批量目标买单不足最小交易单位时取消,并记录
below_minimum_order,不记录insufficient_cash cancel_order()、get_open_orders()record(**values)data.current()、data.current_arrays()、data.raw_current()、data.history()data.fundamental()、data.fundamentals()data.index_constituents()data.available_fields()data.can_trade()
日频扩展字段
扩展字段使用 <数据集>.<字段>:
pe_ttm = data.current(context.asset, "daily_basic.pe_ttm")
net_flow = data.history(context.asset, "moneyflow.net_mf_amount", 20)
industry = data.current(context.asset, "industry.l1_name")
is_st = data.current(context.asset, "stock_st.is_st")
daily_basic:估值、换手率、股本和市值;moneyflow:大小单量和金额,量为手、金额为万元;industry:历史申万一至三级行业;stock_st:历史 ST 名称、类型和is_st;suspended:当日停牌标志。
行业和 ST 字符串在 HDF5 内使用整型字典编码,DataPortal 自动还原。
PIT 指数权重
members = data.index_constituents("000300.SH")
返回以 ts_code 为索引,包含 asset / weight / snapshot_date。可见性严格为:
max(snapshot_date) < 当前回测日
因此 D 日快照从 D+1 可见,首个快照前为空,不使用未来成分回填历史。数据位于 index_weight.h5。
PIT 财务
roe = data.fundamental(context.asset, "fina_indicator.roe")
reports = data.fundamentals(
context.asset,
["income.revenue", "balancesheet.total_assets"],
periods=4,
)
finance.h5 保存 balancesheet / income / cashflow / fina_indicator。财务记录必须满足:
effective_ann_date < 当前回测日
end_date <= 当前回测日
公告日当天不可见。同一报告期选择当时可见的最新公告、update_flag=1 优先版本和最大 source_order。利润表和现金流量表保持年初至今累计口径。
复权
- 前复权:
raw(D_i) × factor(D_i) / factor(当前回调日) - 后复权:
raw(D_i) × factor(D_i)
公司行动改变持仓数量时,仅同步仍待成交的隔夜全仓卖单;普通买单和部分卖单不会自动改写。
报告
指定 output_dir 后生成:
outputs/demo/
├── report.html
└── daily_positions.csv
报告包含收益、基准、回撤、费用、交易限制和组合归因,不生成逐笔 Trade Analysis 图。贡献收益按 Σ(日终权重 × 标的当日收益率) 逐日累计,现金贡献固定为 0。股票和 ETF 持有天数按正市值日终记录统计;CASH 仅统计组合没有正市值证券、全部为现金的交易日。
实际验证
开发机上的真实 schema 7 Bundle:
- 7,583 个股票/ETF;
- 11,648 个指数;
- 4,040 个交易日;
daily.h550,239,528 行;finance.h51,752,376 行;index_weight.h5464,246 行;- 总大小约 11.56 GiB(包含同文件 packed 加速索引);
D:/projects/quant/strategies/宽基轮动 在 2017-01-01 至 2026-08-21、每日扫描全市场、最多持有约 400 只股票、完整报告和 CSV 全部启用时,共处理 2,340 个交易日;项目固定的 CPython 3.12 环境端到端耗时约 38.7 秒。该数据仅用于说明实现量级,实际速度取决于硬件和策略。
已知边界
- 涨停不买、跌停不卖是保守流动性假设;
- 日内临时停牌在日频模型中按全天不可交易处理;
- 不模拟盘口深度、排队、流动性部分成交和冲击成本;金额/百分比订单及批量目标单只按 D+1 实际预算和有效交易单位缩量;
- Tushare 不提供指数权重历史修订发布时间,无法还原供应商后续修订前版本;
- 只有复权因子而没有现金分红明细时,公司行动使用分红再投近似。
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tualpha-1.0.0.tar.gz.
File metadata
- Download URL: tualpha-1.0.0.tar.gz
- Upload date:
- Size: 83.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a69f03ae8faffaf4d8bdcf7158942814a36dc10417d93c79fbd4a3d0127e0240
|
|
| MD5 |
08e19c788fc4f4a2cc0ed7909c09a85d
|
|
| BLAKE2b-256 |
538ddb8f4aa54e02c8727d927f61ff919fcc038b7c7dbc017c8e065198dd22fa
|
File details
Details for the file tualpha-1.0.0-py3-none-any.whl.
File metadata
- Download URL: tualpha-1.0.0-py3-none-any.whl
- Upload date:
- Size: 102.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e540fe6c2d1610a739f1022305d5b3bbc47af6591dc0e1985c4c2877aa5f9e0
|
|
| MD5 |
9badec90d4edddd37945325fc6ea92a0
|
|
| BLAKE2b-256 |
96ad396a8ebebe5b8f8e292ba489086688996ec7174df238b642e0e3c79d415e
|