Lightweight backtesting library built on polars
Project description
PolarBT
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
- 30+ 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
- Multi-asset — pass a dict of DataFrames for portfolio strategies
- 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)
- 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, format_results
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()
# Pretty-print results
print(format_results(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,237.10
Equity Peak [$] 433,931.04
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
Profit Factor 1.79
Expectancy [$] 6338.98
SQN 1.27
Kelly Criterion 0.2098
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 |
Documentation
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 polarbt-0.1.1.tar.gz.
File metadata
- Download URL: polarbt-0.1.1.tar.gz
- Upload date:
- Size: 130.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8aa0a6a59000422cdeb506ae5fa1338e8b7ca580a320c19f09d92c059974a9b
|
|
| MD5 |
2366d7b70284cbc03c224f03d601a871
|
|
| BLAKE2b-256 |
2ad1aa025f681d9acc4ce3e06493fba2af41447ac785f4951479b77bc72ea981
|
Provenance
The following attestation bundles were made for polarbt-0.1.1.tar.gz:
Publisher:
publish.yml on nikkisora/PolarBT
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
polarbt-0.1.1.tar.gz -
Subject digest:
f8aa0a6a59000422cdeb506ae5fa1338e8b7ca580a320c19f09d92c059974a9b - Sigstore transparency entry: 1030366473
- Sigstore integration time:
-
Permalink:
nikkisora/PolarBT@c97e1bf0858cca3b2362cf9c6bee86566e7ea0b8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/nikkisora
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c97e1bf0858cca3b2362cf9c6bee86566e7ea0b8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file polarbt-0.1.1-py3-none-any.whl.
File metadata
- Download URL: polarbt-0.1.1-py3-none-any.whl
- Upload date:
- Size: 80.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9420e7df33dec99cc5422f14d8848b845a019fede6b2bd088a8fc9f30c0f62d
|
|
| MD5 |
7b31c1bcbc9854b014694e6700a862fc
|
|
| BLAKE2b-256 |
ca3e3168ca56a39b0a5d6da36e938a72531de13d3452f03ff2815b781b1d1d86
|
Provenance
The following attestation bundles were made for polarbt-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on nikkisora/PolarBT
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
polarbt-0.1.1-py3-none-any.whl -
Subject digest:
e9420e7df33dec99cc5422f14d8848b845a019fede6b2bd088a8fc9f30c0f62d - Sigstore transparency entry: 1030366622
- Sigstore integration time:
-
Permalink:
nikkisora/PolarBT@c97e1bf0858cca3b2362cf9c6bee86566e7ea0b8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/nikkisora
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c97e1bf0858cca3b2362cf9c6bee86566e7ea0b8 -
Trigger Event:
push
-
Statement type: