# AKQuant: a Rust and Python backtesting framework with ML walk-forward built in

> AKQuant pairs a Rust engine with a Python strategy API, ships a 103-indicator TA-Lib compatibility layer, and adds walk-forward validation for machine learning strategies. It is aimed at quant researchers who want backtest speed without leaving Python.

**akfamily/akquant** — AKQuant is a high-performance quantitative research and trading framework built on Rust and Python! 开源量化回测框架

- Repository: https://github.com/akfamily/akquant
- Website: https://akquant.akfamily.xyz/
- Stars: 2,384 · Forks: 315
- Language: Python
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/akfamily-akquant

## What AKQuant is for, and who ends up using it

AKQuant is a backtesting and research framework for quantitative strategies. The repository describes it as a hybrid framework: the core engine is written in Rust for execution speed, and the strategy-facing API is Python. The stated audience is quantitative investment research, not discretionary trading and not production order routing alone, although examples/05_live_trading_ctp.py exists in the repository.

The problem it addresses is the split that shows up in most Python backtesting setups. Pure Python event loops are easy to write and slow to run once a strategy touches many bars or many symbols. Rewriting the loop in C or Rust means giving up the Python research workflow. AKQuant's answer is to keep the strategy class in Python and move the engine underneath it. Whether that trade is worth it depends on how much of your runtime sits in the engine versus in your own on_bar logic; the README is explicit that actual speed depends on strategy logic, data size, callback frequency and runtime environment.

It is aimed at people already in the AKShare ecosystem. The quickstart imports akshare to fetch A-share daily data, and the project lives under the akfamily organisation that maintains AKShare. If your data pipeline is not AKShare and not a pandas DataFrame, the integration story is less documented.

## The Rust engine, the zero-copy boundary, and where the copies come back

The architecture is visible in the repository layout. Cargo.toml declares a cdylib and rlib crate named akquant, built with pyo3 0.29.2 and abi3-py310, plus numpy 0.29. pyproject.toml uses maturin as the build backend, which is why the README can say no Rust toolchain is needed to install from PyPI. The Python package lives in python/, the Rust sources in src/, and the two are bound through PyO3.

The data path is the interesting part. The README describes add_arrays as borrowing a NumPy buffer into the engine, which is the zero-copy import. Reads on the strategy side, such as get_history, return a safe snapshot copy instead. So the zero-copy claim applies to ingestion, not to every access. A strategy that calls get_history on every bar pays for a copy each time. That is a deliberate safety choice, and it is the kind of detail that decides whether a tight loop stays fast.

Rust dependencies shape the feature set. polars 0.55.2 is compiled with the parquet and ipc features only. A comment in Cargo.toml explains that adding the lazy feature would pull the query planner and expression engine into the wheel and add roughly 12MB, so parquet loading goes through an eager ParquetReader and CSV uses a separate csv crate. rayon provides the parallelism behind parameter search and factor computation. The release profile uses thin LTO and strips symbols. These are size and build-time decisions, not correctness ones, but they explain why the wheel behaves the way it does.

## Installing AKQuant and running a first backtest

The package is on PyPI, and the README states that no Rust environment is required. Python 3.10 or newer is required according to pyproject.toml, which also classifies support up to 3.14.

```bash
pip install akquant
```

Base dependencies include pandas, numpy, pyarrow, polars, plotly, pydantic and tqdm. Optional extras are declared as quantstats, plot, ml, docs, signal-redis, full and dev. The ml extra pulls scikit-learn and torch; signal-redis pulls redis.

The quickstart needs market data. The README uses akshare for A-share daily bars, which is not a base dependency, so install it separately.

```bash
pip install akshare
```

A minimal strategy subclasses akquant.Strategy and implements on_bar. The README example buys 100 shares when the bar closes above its open and closes the position when it closes below.

```python
import akquant as aq
import akshare as ak
from akquant import Strategy

df = ak.stock_zh_a_daily(symbol="sh600000", start_date="20250212", end_date="20260212")

class MyStrategy(Strategy):
    def on_bar(self, bar):
        current_pos = self.get_position(bar.symbol)
        if current_pos == 0 and bar.close > bar.open:
            self.buy(symbol=bar.symbol, quantity=100)
        elif current_pos > 0 and bar.close < bar.open:
            self.close_position(symbol=bar.symbol)
```

Backtests run through aq.run_backtest, which takes the data, the strategy class, initial cash and the symbol list.

```python
result = aq.run_backtest(
    data=df,
    strategy=MyStrategy,
    initial_cash=100000.0,
    symbols="sh600000"
)
print(result)
```

The README shows the resulting BacktestResult as a table of roughly fifty metrics, including total_return_pct, max_drawdown_pct, sharpe_ratio, sortino_ratio, calmar_ratio, ulcer_index, VaR and CVaR at 95 and 99 percent, SQN and kelly_criterion. The sample output in the README is a losing run, which is a useful signal that the project does not ship a flattering demo. A report can be generated with result.viz.report, and passing a benchmark series adds a benchmark comparison block with tracking error, information ratio, Beta and Alpha.

## Walk-forward validation and the factor expression engine

Two features distinguish AKQuant from a plain event-driven backtester. The first is walk-forward validation. The README describes a built-in rolling training framework that integrates PyTorch and scikit-learn, with examples/10_ml_walk_forward.py and examples/12_wfo_integrated.py in the repository. The practical value is that the train and test split is handled by the framework rather than by ad hoc slicing in a notebook. The limitation is equally practical: the documentation excerpt does not specify how overlapping windows, purging or embargo between train and test are handled. Anyone using walk-forward on financial series should confirm that before trusting the output.

The second is the factor expression engine, backed by Polars. It accepts Alpha101-style formulas such as Rank(Ts_Mean(Close, 5)) and handles parallel computation and data alignment automatically. examples/19_factor_expression.py is the reference. This is a real convenience for cross-sectional factor research, where alignment bugs are common and quiet. It also means Polars is not optional: it is a base dependency, and the Rust side compiles it in.

A third area is order management. place_oco binds two orders so filling one cancels the other. place_bracket submits an entry with stop and take-profit exits, and automatically binds the two exit orders as OCO once the entry fills. examples/06_complex_orders.py covers this. For strategies with explicit exit logic, this removes a class of hand-written state bugs.

## TA-Lib compatibility, and the backend choice you have to make

AKQuant ships akquant.talib with two backends, python and rust, covering 103 indicators. The existence of two backends is the point worth pausing on. Two implementations of the same indicator can differ at the edges: warm-up periods, handling of the first N bars, NaN propagation and floating-point rounding. The README does not state that the backends are numerically identical, and it does not document a conformance test between them.

That matters because a strategy validated against one backend and run against the other is not obviously the same strategy. If you already have indicator values from another library, the safest path is to compute a few series both ways on your own data and compare, rather than assuming compatibility. The 103-indicator count is a coverage claim, not a correctness claim.

The same caution applies to the wider metrics table. BacktestResult reports dozens of ratios, but the README does not give formulas for most of them. Sharpe and Sortino conventions vary across libraries in annualisation and risk-free treatment. For a framework at version 0.3.x, that documentation gap is normal and worth naming rather than glossing over.

## Version churn, build weight, and what to check before committing

The release history is dense. v0.3.41, v0.3.51 and v0.3.55 all landed within about three weeks in August and September 2026, and pyproject.toml and Cargo.toml both carry version 0.3.65, ahead of the latest tagged release. The last push to the repository was on 2026-09-28. A fast cadence on a 0.3.x line means APIs can move between minor versions. Pin your version and read CHANGELOG.md before upgrading, particularly if you depend on the order helpers or the factor engine.

Build weight is a real constraint. The Rust crate pulls Polars, PyO3, Rayon, rust_decimal, chrono-tz and more. The Cargo.toml comments show the maintainers actively managing wheel size, which implies the wheel is not small and that feature additions are weighed against download cost. On constrained CI, installing the ml extra adds torch, which is a much larger cost than AKQuant itself.

The licence is MIT, declared in both LICENSE and the Cargo.toml package metadata. MIT is permissive: it allows commercial use and modification with the copyright notice retained. That is a statement about the licence text, not legal advice, and it says nothing about the licences of your market data or of AKShare, which are separate questions.

A fair alternative is PyBroker, which appears in the related searches for this project. PyBroker is a Python backtesting framework built around Numba-accelerated execution rather than a compiled Rust extension, and it is oriented toward rule-based strategies with a machine learning layer. The difference in approach is where the speed comes from: Numba compiles your Python functions at runtime, so the acceleration applies to the code you write, while AKQuant moves the engine into a separate compiled module and keeps your strategy interpreted. That has consequences. Numba's compilation cost is paid per function signature and can be slow on first run; a Rust engine has no warm-up but the boundary between Python and Rust is where the copy semantics described earlier start to matter.

## Conclusion

AKQuant suits Python-literate quant researchers who need walk-forward validation, factor expressions or complex order helpers in one package, and who are comfortable with a project whose release cadence is fast and whose version numbers move in small increments. It is the wrong choice if you need a framework with years of published backtest comparisons, or if your workflow is pure pandas and you do not want a compiled extension in your dependency tree. Before adopting, run examples/10_ml_walk_forward.py and examples/19_factor_expression.py against your own data, and check whether the akquant.talib backend you pick matches the indicator values your existing research already produces.

## FAQ

### Does AKQuant require a Rust toolchain to install?

No. The README states that AKQuant is published to PyPI and can be installed with pip install akquant without a Rust environment. The Rust sources are compiled into the published wheel via maturin.

### What Python versions does AKQuant support?

pyproject.toml sets requires-python to >=3.10 and classifies support for CPython 3.10 through 3.14. The PyO3 binding is built with the abi3-py310 feature.

### How does AKQuant handle zero-copy data import?

The README states that add_arrays borrows a NumPy buffer into the engine, while strategy-side reads such as get_history return a safe snapshot copy. The zero-copy behaviour applies to import, not to every read.

### Does AKQuant support machine learning strategies?

The README describes a built-in walk-forward validation framework that integrates PyTorch and scikit-learn, and the repository includes examples/10_ml_walk_forward.py and examples/12_wfo_integrated.py. The ml optional dependency extra installs scikit-learn and torch.

### What licence does AKQuant use?

MIT. Both the LICENSE file and the Cargo.toml package metadata declare MIT, and pyproject.toml carries the MIT License classifier.

## Sources

- [akfamily/akquant on GitHub](https://github.com/akfamily/akquant)
- [License: MIT](https://github.com/akfamily/akquant/blob/main/LICENSE)
- [Project website](https://akquant.akfamily.xyz/)
- [README](https://github.com/akfamily/akquant/blob/main/README.md)
- [Releases](https://github.com/akfamily/akquant/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/akfamily-akquant
