fastbt-quant
Pandas-native backtesting library with backtest/live parity.
Distribution name on PyPI is
fastbt-quant; the import name staysfastbt.
Install
pip install fastbt-quant # core
pip install "fastbt-quant[data]" # + idata.fyi data fetching
pip install "fastbt-quant[report]" # + HTML tearsheets via quantstats
pip install "fastbt-quant[signal]" # + live signal server (aiohttp)
pip install "fastbt-quant[data,report,signal]" # everything
Requires Python 3.11+.
Design principles
- BYO data. Pandas DataFrame in,
BacktestResultout. No data providers bundled. - One strategy class, two run modes. Same code for backtest and (eventually) live — the engine swaps, the strategy doesn't.
- PaperBroker only in v0.0.1. Real broker adapters (Alpaca, CCXT, Kite) arrive in v0.2+.
- Declarative JSON strategies coming in v0.0.2. The Python subclass API stays as the escape hatch.
Quick start
from fastbt import Strategy, backtest
from fastbt.indicators import sma
class SmaCross(Strategy):
def on_bar(self, ctx):
if len(ctx.history) < 30:
return
close = ctx.history["close"]
fast = sma(close, 10).iloc[-1]
slow = sma(close, 30).iloc[-1]
prev_fast = sma(close, 10).iloc[-2]
prev_slow = sma(close, 30).iloc[-2]
if prev_fast <= prev_slow and fast > slow and ctx.position.is_flat:
ctx.buy(qty=100)
elif prev_fast >= prev_slow and fast < slow and ctx.position.is_long:
ctx.close()
# `data` is any OHLCV DataFrame — bring your own source.
result = backtest(SmaCross(), data=data, initial_cash=100_000)
print(result)
# BacktestResult(trades=7, return=12.40%, max_dd=5.20%, sharpe=1.18, win_rate=57.1%)
JSON strategies (v0.4.0)
Single-symbol and portfolio strategies can be expressed entirely in JSON. One loader handles both:
import json
from fastbt import load_strategy, portfolio_backtest
with open("examples/momentum_portfolio.json") as f:
strategy = load_strategy(json.load(f))
# `data` is a dict[str, pd.DataFrame] for portfolio mode.
result = portfolio_backtest(strategy, data=universe, initial_cash=1_000_000)
A portfolio JSON spec describes the same lifecycle (universe → rank → select → allocate → schedule) the Python PortfolioStrategy exposes. See
examples/momentum_portfolio.json for a complete momentum-rotation example.
OHLCV schema contract
Your DataFrame must have:
- Columns:
open,high,low,close,volume(case-insensitive) - Index:
pd.DatetimeIndex, monotonic increasing, no duplicates - No NaN values
high >= max(open, close),low <= min(open, close),volume >= 0
Call fastbt.validate_ohlcv(df) at your ingest boundary to fail fast.
Fill policy (important)
The single biggest source of "backtest was profitable but live loses money" is fill timing. fastbt makes this explicit:
fill_policy="next_open"(default, realistic) — order submitted on bar N fills at bar N+1's open. You only knew close after bar N ended.fill_policy="current_close"(optimistic) — fills at bar N's close. Use only when your signal is known intra-bar.
Develop
git clone https://github.com/Vbhadala/fastbt
cd fastbt
uv sync --extra dev
uv run pytest
uv run python examples/sma_crossover.py
Portfolio strategies (v0.3.0)
Built-in allocators and risk controls so portfolio strategies don't hand-code these every time.
from fastbt import PortfolioStrategy, portfolio_backtest, RebalanceSchedule
from fastbt.allocators import (
annualized_volatility, inverse_volatility, momentum_score,
)
from fastbt.indicators import roc
class MomentumTop3(PortfolioStrategy):
def rank(self, ctx, universe):
scored = []
for sym in universe:
close = ctx.history[sym]["close"]
score = momentum_score(
{"r90d": roc(close, 90).iloc[-1] if len(close) >= 90 else None},
{"r90d": 1.0},
)
scored.append((sym, score))
return sorted(scored, key=lambda x: x[1], reverse=True)
def select(self, ctx, ranked):
return [s for s, _ in ranked[:3]]
def allocate(self, ctx, selected):
vols = {s: annualized_volatility(ctx.history[s]["close"], 60) for s in selected}
return inverse_volatility(selected, vols)
result = portfolio_backtest(
MomentumTop3(), data,
schedule=RebalanceSchedule.monthly(day=1),
min_drift_pct=2.0, # skip trades under 2% drift
vol_trailing_multiplier=2.0, # vol-adaptive trailing stop
vol_trailing_fallback_pct=10.0,
risk_free_rate=6.0, # for Sharpe / Sortino
)
print(result.metrics.cagr, result.metrics.sortino)
print(len(result.stop_outs), "stop-outs recorded")
See examples/momentum_portfolio.py for a complete runnable walkthrough.
Roadmap
| Version | Scope |
|---|---|
| v0.0.1 | Single-symbol backtest, PaperBroker, 6 indicators, OHLCV validator |
| v0.0.2 | JSON declarative strategies, short positions, 15 more indicators |
| v0.1.0 | Portfolio/universe strategies (rank + select), live mode via async feed |
| v0.2.0 | Live signal engine + webhook server + idata.fyi data module |
| v0.3.0 | Allocators, vol-trailing stops, drift-aware rebalancing, CAGR/Sortino metrics |
| v0.4.0 | JSON portfolio strategy spec, vol_trailing in single-symbol JSON |
| v0.5.0 | First PyPI release as fastbt-quant. Symbol-aware fills (breaking: Bar now requires symbol). |
| v0.6.0+ | Real broker adapters (Alpaca/Kite), walk-forward validation, intrabar stop simulation |
License
MIT
Metadata
Release files for fastbt-quant 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fastbt_quant-0.6.0.tar.gz | 149.5 kB | With provenance | Details for fastbt_quant-0.6.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fastbt_quant-0.6.0-py3-none-any.whl | Python 3 | none | any | Details for fastbt_quant-0.6.0-py3-none-any.whl |
Total release size: 226.9 kB
Release files / fastbt_quant-0.6.0.tar.gz
| Download URL | fastbt_quant-0.6.0.tar.gz |
|---|---|
| Size | 149.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a6b130b780a186a13fdd3faadc17a4fe7e46e2af3ea1ad545679ba3a25ab5a64
|
|
BLAKE2b-256 checksum How to use checksums |
5d1e8a20309a5b8a67bf92dc7847004c4dedb94e1fbbd315ecbc4334d07a0f5f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 8, 2026.
Transparency logRelease files / fastbt_quant-0.6.0-py3-none-any.whl
| Download URL | fastbt_quant-0.6.0-py3-none-any.whl |
|---|---|
| Size | 77.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8230de1b2cf20143a16f254fd07f078f548806c81f499e47c17df13fa13def21
|
|
BLAKE2b-256 checksum How to use checksums |
0c841f875caa87cdce0fd5727ea00371433913eaefef919fe3da7b6fcc85e6ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 8, 2026.
Transparency logSecurity for fastbt-quant 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for fastbt_quant-0.6.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 8, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.