Skip to main content

PolarBT

Polar BackTest

A lightweight, high-performance backtesting library for trading strategy development and optimization. Built on Polars for fast vectorized data processing with an event-driven execution loop for flexible strategy logic.

Features

  • Hybrid architecture — vectorized preprocessing (Polars) + event-driven execution loop
  • 25+ built-in indicators — SMA, EMA, RSI, MACD, Bollinger Bands, ATR, SuperTrend, ADX, and more
  • Complete order system — market, limit, stop, stop-limit, bracket orders, day/GTC orders
  • Risk management — stop-loss, take-profit, trailing stops, position size limits, drawdown stops
  • Short selling — negative positions, borrow costs, position reversals
  • Margin & leverage — configurable leverage, margin tracking, margin calls
  • Commission models — percentage, fixed, maker/taker, volume-tiered, custom
  • Position sizing — fixed, percent, fixed-risk, Kelly, volatility-based
  • Weight-based backtesting — declarative portfolio allocation with backtest_weights() or WeightStrategy, rebalance scheduling, stop-loss/take-profit, next-actions output
  • Multi-asset — pass a dict of DataFrames or a long-format DataFrame with symbol column; all OHLC data preserved
  • Dynamic universe — UniverseProvider protocol filters tradeable symbols per bar; built-in AgeFilter, VolumeFilter, TopN, CompositeFilter; token lifecycle tracking via ctx.first_seen_bar / ctx.bar_count
  • Parallel optimization — grid search, multi-objective Pareto, Bayesian optimization
  • Walk-forward analysis — rolling and anchored train/test splits
  • Advanced analysis — Monte Carlo simulation, look-ahead bias detection, permutation testing
  • Visualization — interactive Plotly charts (price, equity, drawdown, trade markers, heatmaps)
  • AMM-aware execution — pluggable SlippageModel with FlatSlippage and AMMSlippage (constant-product formula)
  • Exchange rate support — Engine(exchange_rate=...) converts equity curve to USD; reports dual quote/USD metrics
  • DeFi indicators — buy_sell_ratio, net_flow, trade_intensity, pump_detector, rug_pull_detector, AMM price_impact_estimate, liquidity_ratio, and more
  • Trade data pipeline — validate and aggregate raw DEX/AMM trades into OHLCV bars (time-based or trade-count), with buy/sell volume split, VWAP, and optional USD conversion
  • Data utilities — validation, cleaning, OHLCV resampling
  • Optional TA-Lib integration — wrap any TA-Lib function into Polars expressions

Installation

pip install polarbt

Or with optional extras:

pip install polarbt[plotting]   # Plotly charts
pip install polarbt[talib]      # TA-Lib integration

Install from source:

git clone git@github.com:nikkisora/PolarBT.git
cd PolarBT
pip install -e .

Quick Start

import polars as pl
import yfinance as yf
from polarbt import Engine, Strategy
from polarbt import indicators as ind
from polarbt.core import BacktestContext
from polarbt.plotting import plot_backtest


class SMACross(Strategy):
    def preprocess(self, df: pl.DataFrame) -> pl.DataFrame:
        return df.with_columns(
            ind.sma("close", 10).alias("sma_fast"),
            ind.sma("close", 30).alias("sma_slow"),
        ).with_columns(
            ind.crossover("sma_fast", "sma_slow").alias("buy"),
            ind.crossunder("sma_fast", "sma_slow").alias("sell"),
        )

    def next(self, ctx: BacktestContext) -> None:
        if ctx.row.get("buy"):
            ctx.portfolio.order_target_percent("asset", 1.0)
        elif ctx.row.get("sell"):
            ctx.portfolio.close_position("asset")


# Download data from Yahoo Finance
ticker = yf.download("AAPL", start="2016-01-01", end="2026-01-01", auto_adjust=True)
ticker = ticker.droplevel("Ticker", axis=1).reset_index()
data = pl.from_pandas(ticker)

# Run backtest
engine = Engine(SMACross(), data, commission=.005, initial_cash=100_000)
results = engine.run()

print(results)

# Interactive chart saved to HTML
fig = plot_backtest(engine, title="SMA Crossover — AAPL", indicators=["sma_fast", "sma_slow"])
fig.write_html("backtest.html")
Equity Final [$]                        366,236.83
Equity Peak [$]                         433,930.72
Return [%]                                  266.24
Buy & Hold Return [%]                      1044.52
Return (Ann.) [%]                            14.08
CAGR [%]                                     14.08
Volatility (Ann.) [%]                        19.78

Sharpe Ratio                                  0.76
Sortino Ratio                                 0.92
Calmar Ratio                                  0.44
Max. Drawdown [%]                           -32.16
Avg. Drawdown Duration [bars]                   38
Max. Drawdown Duration [bars]                  730

# Trades                                        42
Win Rate [%]                                 47.62
Best Trade [%]                               57.11
Worst Trade [%]                             -13.43
Avg. Trade [%]                                3.94
Max. Trade Duration [bars]                     128
Avg. Trade Duration [bars]                      39
Avg. Trade MDD [%]                           -8.78
Profit Factor                                 1.79
Expectancy [$]                             6338.97
SQN                                           1.27
Kelly Criterion                             0.2098

PolarBT

Weight-Based Backtesting

For portfolio allocation strategies, skip the event loop entirely — just supply target weights per (date, symbol):

import polars as pl
from polarbt import backtest_weights

# data: long-format DataFrame with columns date, symbol, close, weight
result = backtest_weights(
    data,
    resample="M",           # rebalance monthly
    resample_offset="2d",   # delay 2 trading days after month boundary
    fee_ratio=0.001,
    stop_loss=0.10,          # 10% per-position stop-loss
    position_limit=0.5,      # max 50% in any single name
    initial_capital=100_000,
)

print(result.metrics)        # standard BacktestMetrics
print(result.trades.head())  # per-trade log
print(result.next_actions)   # forward-looking rebalance actions

Trade Data & DeFi Backtesting

PolarBT can ingest raw DEX/AMM trade data (e.g. Pump.fun on Solana), aggregate it into OHLCV bars, apply DeFi-specific indicators, and backtest with AMM-aware slippage — all in a single pipeline.

import polars as pl
from polarbt import Engine, Strategy, indicators_defi as defi
from polarbt.core import BacktestContext
from polarbt.data.trades import aggregate_trades, validate_trades
from polarbt.slippage import AMMSlippage
from polarbt.universe import AgeFilter, CompositeFilter, VolumeFilter

# 1. Load and validate raw trades
trades = pl.read_parquet("trades.parquet")
assert validate_trades(trades.sort("symbol", "timestamp")).valid

# 2. Aggregate to 5-minute OHLCV bars
bars = aggregate_trades(trades.sort("symbol", "timestamp"), "5m", min_trades=3)

# 3. Define a strategy using DeFi indicators
class PumpMomentum(Strategy):
    def preprocess(self, df: pl.DataFrame) -> pl.DataFrame:
        return df.with_columns(
            defi.buy_sell_ratio().over("symbol").alias("bs_ratio"),
            defi.trade_intensity(window=10).over("symbol").alias("intensity"),
        )

    def next(self, ctx: BacktestContext) -> None:
        for sym in ctx.symbols:
            row = ctx.row(sym)
            if row.get("bs_ratio", 0) > 0.7 and row.get("intensity", 0) > 2.0:
                ctx.portfolio.order_target_percent(sym, 0.1)
            elif row.get("bs_ratio", 0) < 0.3:
                ctx.portfolio.close_position(sym)

# 4. Run with AMM slippage and universe filtering
engine = Engine(
    PumpMomentum(),
    bars,
    initial_cash=100.0,        # in SOL
    commission=0.01,
    slippage=AMMSlippage(),    # uses pool_reserve_last from bar data
    universe_provider=CompositeFilter(AgeFilter(min_bars=5), VolumeFilter(min_volume=1.0)),
)
results = engine.run()
print(results)

Examples

Example Description
example.py Basic SMA crossover
example_sma_crossover_stoploss.py SMA crossover with ATR stop-loss and trailing stop
example_rsi_bracket_orders.py RSI mean reversion with bracket orders
example_momentum_rotation.py Multi-asset momentum rotation
example_ml_strategy.py ML model integration
example_walk_forward.py Walk-forward analysis workflow
example_advanced_analysis.py Full workflow: optimization, heatmaps, Monte Carlo, permutation test
example_limit_orders.py Limit orders and stop-loss
example_trade_analysis.py Trade-level analysis
example_plotting.py Interactive chart generation
example_commission.py Commission model comparison
example_multi_asset.py Multi-asset dict input
example_weight_backtest.py Weight-based portfolio backtest
example_defi_trades.py DeFi trade data pipeline with AMM slippage

Documentation

License

MIT

Metadata

Release files for polarbt 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for polarbt 0.2.1
File Size Uploaded
polarbt-0.2.1.tar.gz 187.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for polarbt 0.2.1
File Interpreter ABI Platform
polarbt-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 296.5 kB

Release files / polarbt-0.2.1.tar.gz

Download URL polarbt-0.2.1.tar.gz
Size 187.1 kB
Tags Source
SHA-256 checksum
How to use checksums
a923d911d4b3f1f8edfb72987eec62ba42e6186ef0661ff6f9ba99fcc1a7e2b8
BLAKE2b-256 checksum
How to use checksums
c666e55b9ee7701544b77f3fee2a69a37512e90f1bdedc0e58631a9628e03ec6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Mar 14, 2026.

Transparency log

Release files / polarbt-0.2.1-py3-none-any.whl

Download URL polarbt-0.2.1-py3-none-any.whl
Size 109.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1e45e3cf1d37fa28dcf7ed41357b83dee74950c15360a426d22b5ef119732624
BLAKE2b-256 checksum
How to use checksums
70392e412f00ceafd443791887db300f53bcdb16e5b0833b24de53c6b08026fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Mar 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page