Weight-based backtesting engine for quantitative trading
Project description
wbt
High-performance position-weighted backtesting engine, written in Rust with Python bindings.
Overview
wbt (Weight Back Test) is a standalone library for backtesting trading strategies based on position weights. It computes daily P&L attribution, trade pair matching (FIFO), and comprehensive performance statistics — all powered by a zero-copy, cache-friendly Rust core with rayon-based parallelism.
- Rust crate (
wbt): pure Rust library with core engine - Python package (
wbt): PyO3 bindings + pandas-friendly API via Arrow IPC
Installation
Python
# Requires: Rust toolchain, maturin, Python >= 3.9
git clone <repo-url> && cd wbt
uv venv .venv && source .venv/bin/activate
uv pip install pandas pyarrow numpy maturin
maturin develop --release
Rust
# Cargo.toml
[dependencies]
wbt = "0.1"
Quick Start
Python
import pandas as pd
from wbt import WeightBacktest
# Prepare input: DataFrame with columns [dt, symbol, weight, price]
dfw = pd.DataFrame({
"dt": ["2024-01-02 09:01:00", "2024-01-02 09:02:00", "2024-01-03 09:01:00", "2024-01-03 09:02:00"],
"symbol": ["AAPL", "AAPL", "AAPL", "AAPL"],
"weight": [0.5, 0.5, 0.0, 0.0],
"price": [185.0, 186.0, 187.0, 185.5],
})
wb = WeightBacktest(dfw, digits=2, fee_rate=0.0002, n_jobs=4, weight_type="ts")
wb.stats # dict: Sharpe, Calmar, max drawdown, win rate, etc.
wb.daily_return # DataFrame: per-symbol daily returns with 'total' column
wb.dailys # DataFrame: per-symbol daily detail (edge, return, cost, turnover, ...)
wb.alpha # DataFrame: strategy excess return vs. benchmark
wb.pairs # DataFrame: all matched trade pairs (FIFO)
Rust
use wbt::core::{WeightBacktest, WeightType};
use polars::prelude::*;
let dfw: DataFrame = /* build your DataFrame with [dt, symbol, weight, price] */;
let mut wb = WeightBacktest::new(dfw, 2, Some(0.0002))?;
wb.backtest(Some(4), WeightType::TS, 252)?;
let report = wb.report.as_ref().unwrap();
println!("Sharpe: {}", report.stats.daily_performance.sharpe_ratio);
Input Format
| Column | Type | Description |
|---|---|---|
dt |
datetime | Bar end time; must be a continuous trading time series with no gaps |
symbol |
str | Instrument code |
weight |
float | Position weight at bar end; independent across symbols; positive = long, negative = short, 0 = flat |
price |
float | Trade price (close, next-bar open, TWAP/VWAP, etc.) |
Parameters
| Parameter | Default | Description |
|---|---|---|
digits |
2 |
Decimal places for weight rounding |
fee_rate |
0.0002 |
One-way transaction cost (commission + slippage) |
n_jobs |
1 |
Number of parallel threads (rayon thread pool) |
weight_type |
"ts" |
"ts" (time-series: equal-weight average across symbols) or "cs" (cross-section: sum across symbols) |
yearly_days |
252 |
Trading days per year for annualization |
Output Properties
| Property | Type | Description |
|---|---|---|
stats |
dict | Full performance report (Sharpe, Calmar, drawdown, win rate, trade metrics, ...) |
daily_return |
DataFrame | Pivoted daily returns per symbol + total column |
dailys |
DataFrame | Per-symbol daily detail: n1b, edge, return, cost, turnover, long/short splits |
alpha |
DataFrame | Strategy vs. benchmark excess return |
alpha_stats |
dict | Performance statistics on the excess return series |
pairs |
DataFrame | All FIFO-matched trade pairs with P&L, hold bars, direction |
long_daily_return |
DataFrame | Long-only daily returns |
short_daily_return |
DataFrame | Short-only daily returns |
long_stats |
dict | Long-only performance statistics |
short_stats |
dict | Short-only performance statistics |
bench_stats |
dict | Benchmark (equal-weight n1b) performance statistics |
Architecture
wbt/
├── src/
│ ├── lib.rs # PyO3 bindings (Arrow IPC in/out)
│ └── core/ # Pure Rust engine
│ ├── mod.rs # WeightBacktest struct & public API
│ ├── native_engine.rs # Zero-copy parallel engine (rayon)
│ ├── daily_performance.rs # Sharpe, Calmar, drawdown, etc.
│ ├── evaluate_pairs.rs # Trade pair statistics
│ ├── backtest.rs # Orchestration & alpha computation
│ ├── report.rs # Report structs & JSON serialization
│ ├── trade_dir.rs # Trade direction & action enums
│ ├── errors.rs # Error types
│ └── utils.rs # WeightType, rounding, quantile
└── python/wbt/ # Python API wrapper
├── backtest.py # WeightBacktest class (pandas-friendly)
└── _df_convert.py # Arrow <-> pandas conversion
Benchmark
Tested on China A-share daily data (2017-01 to 2025-04), Apple M-series, 8 threads, release build with LTO:
| Dataset | Rows | Symbols | Time | Throughput |
|---|---|---|---|---|
| Full A-share daily | 8,440,404 | 5,351 | 0.63s | 13.4M rows/s |
Outputs produced in a single pass:
| Output | Size | Description |
|---|---|---|
dailys |
8,435,053 rows × 15 cols | Per-symbol daily attribution |
pairs |
942,679 rows × 11 cols | FIFO-matched trade pairs |
daily_return |
2,023 rows | Equal-weight portfolio daily return |
alpha |
2,023 rows × 4 cols | Strategy vs. benchmark excess return |
stats |
29 metrics | Sharpe, Calmar, drawdown, win rate, etc. |
Sample stats output (click to expand)
{
"开始日期": "2016-12-27", "结束日期": "2025-04-28",
"绝对收益": 0.4431, "年化": 0.0552,
"夏普": 0.345, "最大回撤": 0.2234,
"卡玛": 0.2471, "日胜率": 0.5136,
"日盈亏比": 1.0219, "日赢面": 0.0384,
"年化波动率": 0.16, "下行波动率": 0.1167,
"非零覆盖": 0.9802, "盈亏平衡点": 0.9975,
"新高间隔": 542.0, "新高占比": 0.0277,
"回撤风险": 1.3963, "回归年度回报率": 0.0395,
"长度调整平均最大回撤": 0.9516, "交易胜率": 0.2697,
"单笔收益": 17.51, "持仓K线数": 9.79,
"多头占比": 0.4611, "空头占比": 0.5269,
"与基准相关性": -0.2835, "与基准空头相关性": -0.374,
"波动比": 0.6665, "与基准波动相关性": 0.1974,
"品种数量": 5351
}
Performance Design
- O(N) counting sort for symbol grouping (replaces generic sort)
- Struct-of-Arrays (SoA) layout for cache-locality in hot loops
- Lazy DataFrame materialization — internal computation uses raw vectors; DataFrames built only on demand
- FIFO lot matching via stack-based SoA with dynamic resizing
- rayon data-parallelism across symbols with configurable thread pool
- Zero-copy slicing from Polars DataFrames into contiguous memory blocks
- Arrow IPC for zero-serialization-overhead Python <-> Rust data transfer
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 wbt-0.1.2.tar.gz.
File metadata
- Download URL: wbt-0.1.2.tar.gz
- Upload date:
- Size: 56.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5299e400318841fea7e3c79f91327c1d875de2a65fce38d9dc8845e6603f50f7
|
|
| MD5 |
a0f6920ffc902867d4e84ae725de6866
|
|
| BLAKE2b-256 |
8bea84922c0e4f414df87edbae06e7b0d64c0fcd8a2eb702e84d4fda8904281d
|
Provenance
The following attestation bundles were made for wbt-0.1.2.tar.gz:
Publisher:
release.yml on zengbin93/wbt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wbt-0.1.2.tar.gz -
Subject digest:
5299e400318841fea7e3c79f91327c1d875de2a65fce38d9dc8845e6603f50f7 - Sigstore transparency entry: 1212220441
- Sigstore integration time:
-
Permalink:
zengbin93/wbt@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/zengbin93
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wbt-0.1.2-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: wbt-0.1.2-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 10.1 MB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0c33e6db61cbde42bf9629eb1f73b2099338508dad6920e3ff825e5fd4a0e44
|
|
| MD5 |
28c856ad5ed3ed95fbc47eb0bffa527b
|
|
| BLAKE2b-256 |
3fd91c97d62c3a40367438aa75f5eb532d9806cf2bbd638db5bda574178badb8
|
Provenance
The following attestation bundles were made for wbt-0.1.2-cp312-cp312-win_amd64.whl:
Publisher:
release.yml on zengbin93/wbt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wbt-0.1.2-cp312-cp312-win_amd64.whl -
Subject digest:
b0c33e6db61cbde42bf9629eb1f73b2099338508dad6920e3ff825e5fd4a0e44 - Sigstore transparency entry: 1212220800
- Sigstore integration time:
-
Permalink:
zengbin93/wbt@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/zengbin93
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wbt-0.1.2-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: wbt-0.1.2-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 8.3 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
526b82d6f84d090a5a12d05418a130b9c82898b9476165eca444b1c0af67b55c
|
|
| MD5 |
b44fa444921c7bbb23f4246a857dd6f8
|
|
| BLAKE2b-256 |
bf5270eb9d00827906718d0cdca094d85ac8448d2a8f283cdd88c7316c092a0e
|
Provenance
The following attestation bundles were made for wbt-0.1.2-cp312-cp312-macosx_11_0_arm64.whl:
Publisher:
release.yml on zengbin93/wbt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wbt-0.1.2-cp312-cp312-macosx_11_0_arm64.whl -
Subject digest:
526b82d6f84d090a5a12d05418a130b9c82898b9476165eca444b1c0af67b55c - Sigstore transparency entry: 1212220552
- Sigstore integration time:
-
Permalink:
zengbin93/wbt@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/zengbin93
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wbt-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: wbt-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 9.5 MB
- Tags: CPython 3.8, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19c62f0b6da2439800b9edbf27a7b79b4a993271be9a5b1c249d3823170ac4ee
|
|
| MD5 |
ebd442ebe747804e095d05a21c8ee659
|
|
| BLAKE2b-256 |
59cde69bc4c91b546325f171353c6ba19b4135ff334c31d9f6e9ee77ab6c9beb
|
Provenance
The following attestation bundles were made for wbt-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on zengbin93/wbt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wbt-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
19c62f0b6da2439800b9edbf27a7b79b4a993271be9a5b1c249d3823170ac4ee - Sigstore transparency entry: 1212220920
- Sigstore integration time:
-
Permalink:
zengbin93/wbt@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/zengbin93
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35cff8cc27944df47313bb73c3f8de68a192bb31 -
Trigger Event:
push
-
Statement type: