Skip to main content

Pandas-native backtesting library with backtest/live parity

Project description

fastbt-quant

Pandas-native backtesting library with backtest/live parity.

PyPI Python License: MIT

Distribution name on PyPI is fastbt-quant; the import name stays fastbt.

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, BacktestResult out. 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

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

fastbt_quant-0.6.0.tar.gz (149.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastbt_quant-0.6.0-py3-none-any.whl (77.4 kB view details)

Uploaded Python 3

File details

Details for the file fastbt_quant-0.6.0.tar.gz.

File metadata

  • Download URL: fastbt_quant-0.6.0.tar.gz
  • Upload date:
  • Size: 149.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastbt_quant-0.6.0.tar.gz
Algorithm Hash digest
SHA256 a6b130b780a186a13fdd3faadc17a4fe7e46e2af3ea1ad545679ba3a25ab5a64
MD5 4cac46321af51aaf54bc9c4b57012b50
BLAKE2b-256 5d1e8a20309a5b8a67bf92dc7847004c4dedb94e1fbbd315ecbc4334d07a0f5f

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastbt_quant-0.6.0.tar.gz:

Publisher: release.yml on Vbhadala/fastbt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastbt_quant-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: fastbt_quant-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 77.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastbt_quant-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8230de1b2cf20143a16f254fd07f078f548806c81f499e47c17df13fa13def21
MD5 74f94a8238b27265a767a76a30af0e0a
BLAKE2b-256 0c841f875caa87cdce0fd5727ea00371433913eaefef919fe3da7b6fcc85e6ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastbt_quant-0.6.0-py3-none-any.whl:

Publisher: release.yml on Vbhadala/fastbt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page