Skip to content

Latest commit

 

History

History
231 lines (188 loc) · 9.79 KB

File metadata and controls

231 lines (188 loc) · 9.79 KB

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 universeUniverseProvider 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 supportEngine(exchange_rate=...) converts equity curve to USD; reports dual quote/USD metrics
  • DeFi indicatorsbuy_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