Claude Code Plugins

Community-maintained marketplace

Feedback

Help users backtest trading strategies with polars-backtest library. Use when user asks about backtesting, portfolio simulation, trading strategy analysis, or working with polars-backtest.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name polars-backtest
description Help users backtest trading strategies with polars-backtest library. Use when user asks about backtesting, portfolio simulation, trading strategy analysis, or working with polars-backtest.

Polars Backtest Usage Skill

Help users use polars-backtest to backtest their trading strategies efficiently.

Installation

pip install polars-backtest
# or
uv add polars-backtest

Data Format

Long format: one row per (date, symbol) pair.

import polars as pl
import polars_backtest as pl_bt

df = pl.DataFrame({
    "date": ["2024-01-01", "2024-01-01", "2024-01-02", "2024-01-02"],
    "symbol": ["2330", "2317", "2330", "2317"],
    "close": [100.0, 50.0, 102.0, 51.0],
    "weight": [0.6, 0.4, 0.6, 0.4],
})

Basic Usage

# DataFrame namespace
result = df.bt.backtest(trade_at_price="close", position="weight")

# Function API
result = pl_bt.backtest(df, trade_at_price="close", position="weight")

# With report (includes trades, stats)
report = df.bt.backtest_with_report(position="weight", resample="M")

Complete Parameter Reference

Column Mapping Parameters

Parameter Default Type Description
trade_at_price "close" str | Expr Price column for trade execution. Use adjusted close for accurate returns.
position "weight" str | Expr Position weight column. Can be float weights or boolean signals (True=buy). Null values are filled with 0.
date "date" str | Expr Date column. Must be sortable.
symbol "symbol" str | Expr Stock symbol/ticker column.
open "open" str | Expr Open price column. Required when touched_exit=True.
high "high" str | Expr High price column. Required when touched_exit=True.
low "low" str | Expr Low price column. Required when touched_exit=True.
factor "factor" str Adjustment factor column. Used to calculate raw price: raw_price = adj_price / factor. If column doesn't exist, defaults to 1.0. Useful for dividend/split adjusted prices.

Rebalancing Parameters

Parameter Default Type Description
resample "D" str | None Rebalance frequency. Options: "D" (daily), "W" (weekly), "W-FRI" (weekly on Friday), "M" (monthly), "Q" (quarterly), "Y" (yearly), None (only when position changes).
resample_offset None str | None Delay rebalance execution. Examples: "1d" (1 day delay), "2d", "1W". Useful for simulating delayed signal execution.

Cost Parameters

Parameter Default Type Description
fee_ratio 0.001425 float Transaction fee rate (both buy and sell). Taiwan stock default is 0.1425%.
tax_ratio 0.003 float Transaction tax rate (sell only). Taiwan stock default is 0.3%.

Risk Management Parameters

Parameter Default Type Description
stop_loss 1.0 float Stop loss threshold. Exit when loss reaches this ratio. 1.0 = disabled (100% loss). Example: -0.1 exits at 10% loss.
take_profit inf float Take profit threshold. Exit when profit reaches this ratio. inf = disabled. Example: 0.2 exits at 20% profit.
trail_stop inf float Trailing stop threshold. Exit when price drops this much from peak. inf = disabled. Example: 0.05 exits when 5% below peak.
position_limit 1.0 float Maximum weight per single stock. 1.0 = no limit. Example: 0.1 caps each stock at 10% of portfolio.
touched_exit False bool Use intraday OHLC for stop detection. When True, checks if stop/take profit was touched during the day using high/low prices, not just close. Requires open/high/low columns.
stop_trading_next_period True bool When stop is triggered, skip trading in the next period. Prevents immediate re-entry after stop.

Calculation Mode Parameters

Parameter Default Description
finlab_mode False (backtest) / True (backtest_with_report) Use Finlab-compatible calculation. When True, boolean signals are converted to equal weights. Affects weight normalization behavior.
retain_cost_when_rebalance False When rebalancing, retain the cost basis instead of resetting. Affects return calculation for partially sold positions.

Benchmark Parameters (backtest_with_report only)

Parameter Default Type Description
benchmark None str | DataFrame | None Benchmark for alpha/beta calculation. str: symbol value in your data (e.g., "0050"), uses that symbol's price. DataFrame: must have date and creturn columns (cumulative return starting at 1.0).

Liquidity Metrics Parameters (backtest_with_report only)

Parameter Default Type Description
limit_up "limit_up" str Column name for limit-up price. Used to calculate buyHigh metric (ratio of entries at limit-up).
limit_down "limit_down" str Column name for limit-down price. Used to calculate sellLow metric (ratio of exits at limit-down).
trading_value "trading_value" str Column for trading value (e.g., close * volume). Used to calculate capacity metric.

BacktestReport Object

report = df.bt.backtest_with_report(position="weight")

# Properties
report.creturn      # DataFrame with date, creturn columns
report.trades       # DataFrame with trade records (entry/exit dates, prices, returns, MAE/MFE)
report.stats        # Statistics DataFrame (shortcut for get_stats())
report.fee_ratio    # Fee ratio used
report.tax_ratio    # Tax ratio used
report.stop_loss    # Stop loss threshold (None if disabled)
report.take_profit  # Take profit threshold (None if disabled)
report.trail_stop   # Trail stop threshold (None if disabled)
report.trade_at     # Trade timing (e.g., 'close')
report.resample     # Resample frequency
report.benchmark    # Benchmark DataFrame (can be set after creation)

# Set benchmark after creation
report.benchmark = benchmark_df

BacktestReport Methods

get_stats(riskfree_rate=0.02)

Get basic statistics as single-row DataFrame.

report.get_stats()  # or report.stats

Columns: start, end, rf, total_return, cagr, max_drawdown, avg_drawdown, daily_mean, daily_vol, daily_sharpe, daily_sortino, best_day, worst_day, calmar, win_ratio

get_monthly_stats(riskfree_rate=0.02)

Get monthly statistics.

report.get_monthly_stats()

Columns: monthly_mean, monthly_vol, monthly_sharpe, monthly_sortino, best_month, worst_month

get_return_table()

Get monthly return table pivoted by year x month.

report.get_return_table()

Returns DataFrame with year as rows and months (1-12) as columns.

get_metrics(sections=None, riskfree_rate=0.02)

Get structured metrics as single-row DataFrame.

metrics = report.get_metrics()  # All sections
metrics = report.get_metrics(sections=["profitability", "risk"])

current_trades()

Get active trades (positions without exit or exiting on last date).

report.current_trades()

actions()

Get trade actions for current positions.

report.actions()
# Returns: stock_id, action ('enter', 'exit', 'hold')

is_stop_triggered()

Check if any trade was triggered by stop loss or take profit.

if report.is_stop_triggered():
    print("Stop was triggered")

daily_creturn()

Get daily resampled cumulative return DataFrame.

report.daily_creturn()

get_metrics Sections

Section Metrics Description
backtest startDate, endDate, feeRatio, taxRatio, freq, tradeAt, stopLoss, takeProfit, trailStop Backtest configuration
profitability annualReturn, avgNStock, maxNStock, alpha, beta Returns and benchmark comparison
risk maxDrawdown, avgDrawdown, avgDrawdownDays, valueAtRisk, cvalueAtRisk Risk metrics
ratio sharpeRatio, sortinoRatio, calmarRatio, volatility, profitFactor, tailRatio Risk-adjusted ratios
winrate winRate, expectancy, mae, mfe, m12WinRate Win rate and trade analysis
liquidity buyHigh, sellLow, capacity Liquidity metrics (requires columns)

Note: alpha, beta, m12WinRate require benchmark to be set.

Statistics Expressions

Use these expressions for custom calculations:

from polars_backtest import daily_returns, cumulative_returns, sharpe_ratio, max_drawdown

df.with_columns(
    ret=daily_returns("close"),
    creturn=cumulative_returns("ret"),
)

df.select(
    sharpe=sharpe_ratio("ret"),
    mdd=max_drawdown("creturn"),
)

Usage Examples

Momentum Strategy with Monthly Rebalancing

df = df.with_columns(
    pl.when(pl.col("close") >= pl.col("close").rolling_max(60).over("symbol"))
    .then(1.0)
    .otherwise(0.0)
    .alias("weight")
)
report = df.bt.backtest_with_report(position="weight", resample="M")

With Risk Management

report = df.bt.backtest_with_report(
    position="weight",
    stop_loss=-0.1,        # -10% stop loss
    take_profit=0.2,       # +20% take profit
    trail_stop=0.05,       # 5% trailing stop
    touched_exit=True,     # Use intraday OHLC for detection
)

With Benchmark Comparison

# Using a symbol in your data as benchmark
report = df.bt.backtest_with_report(
    position="weight",
    benchmark="0050",      # ETF ticker
)

# Or set after creation
report.benchmark = benchmark_df

# Get metrics with alpha, beta, m12WinRate
metrics = report.get_metrics(sections=["profitability", "winrate"])

With Factor Column (Adjusted Prices)

# When using adjusted prices, factor converts back to raw price
# raw_price = adj_close / factor
df = df.with_columns(
    (pl.col("close_raw") / pl.col("close_adj")).alias("factor")
)
report = df.bt.backtest_with_report(
    trade_at_price="close_adj",
    factor="factor",
)

With Liquidity Metrics

df = df.with_columns([
    pl.col("limit_up_price").alias("limit_up"),
    pl.col("limit_down_price").alias("limit_down"),
    (pl.col("close") * pl.col("volume")).alias("trading_value"),
])
report = df.bt.backtest_with_report(position="weight")
metrics = report.get_metrics(sections=["liquidity"])
# Returns: buyHigh, sellLow, capacity

Using Polars Expressions

# Pass expressions directly instead of column names
result = df.bt.backtest(
    trade_at_price=pl.col("adj_close"),
    position=pl.col("signal").cast(pl.Float64),
    resample="M",
)

Delayed Rebalancing

# Rebalance monthly, but execute 2 days after signal
report = df.bt.backtest_with_report(
    position="weight",
    resample="M",
    resample_offset="2d",
)

Analyzing Current Positions

report = df.bt.backtest_with_report(position="weight")

# Get current active trades
current = report.current_trades()

# Get recommended actions
actions = report.actions()  # enter/exit/hold per stock

Resample Options

Value Description
None Only rebalance when position changes
'D' Daily
'W' Weekly (Sunday)
'W-FRI' Weekly (Friday)
'M' Monthly
'Q' Quarterly
'Y' Yearly

Tips

  1. Weight normalization: Weights are automatically normalized to sum to 1.0 per date
  2. T+1 execution: Trades execute at next day's price (realistic simulation)
  3. Boolean signals: Pass boolean column as position, library converts True to equal weights
  4. Null handling: Null values in position column are filled with 0.0
  5. resample=None: Only rebalance when position changes (reduces turnover)
  6. Position limit: Use position_limit=0.1 to cap each stock at 10%