← Back to list
💰

backtrader Checked

Event-driven backtesting with bar-by-bar execution, complex order types, multiple analyzers, and …
💰 Finance & Trading skills By agiprolabs Version v1.0.0 Added 2026-09-20 Updated 2026-09-20 Source ↗
8.6Overall rating
2Views
6Downloads
366Stars

Installation

🤖 Install via AI

Copy the prompt below and send it to your AI assistant (e.g. Claude Code) — it will follow the instructions and install automatically.

Install the "backtrader" skill by following the instructions at https://skill123.me/install/backtrader.
⌨️ Command line install

Run in your terminal — downloads and installs to ~/.claude/skills/.

curl -fsSL https://skill123.me/install/backtrader.sh | bash
📦 Download ZIP

Download the zip and extract it into your skills directory (e.g. ~/.claude/skills/), then restart your session.

⬇ Download v1.0.0 · 20 KB
📊 Static rating
8.6/10
Trigger
6.0
Structure
9.3
Workflow
8.0
Content
10.0
Engineering
10.0
Security
10.0

Six-dimension rubric with reviewer rationale.

View scorecard ↓
🛡 Dynamic test
—

Not live-tested yet — this skill is rated on static analysis only.

About this skill

Event-driven backtesting with bar-by-bar execution, complex order types, multiple analyzers, and custom indicators

Backtrader

Backtrader is a Python event-driven backtesting framework that processes data bar-by-bar, simulating realistic execution with a built-in broker, order management, and position tracking. Unlike vectorized frameworks (vectorbt, pandas), backtrader walks through history one bar at a time, firing callbacks that let you implement complex order logic that depends on previous fills, partial executions, and conditional brackets.

Documentation

Event-driven backtesting with bar-by-bar execution, complex order types, multiple analyzers, and custom indicators

Backtrader

Backtrader is a Python event-driven backtesting framework that processes data bar-by-bar, simulating realistic execution with a built-in broker, order management, and position tracking. Unlike vectorized frameworks (vectorbt, pandas), backtrader walks through history one bar at a time, firing callbacks that let you implement complex order logic that depends on previous fills, partial executions, and conditional brackets.

Event-Driven vs Vectorized

| Aspect | Backtrader (event-driven) | vectorbt (vectorized) |

|---|---|---|

| Execution model | Bar-by-bar callbacks | Whole-array operations |

| Speed | Slower (Python loop) | Fast (NumPy/Numba) |

| Order types | Market, limit, stop, stop-limit, bracket, OCO | Market only (native) |

| Realism | Built-in broker with commission, slippage, margin | Manual slippage modeling |

| Multi-timeframe | Native resampledata | Manual alignment |

| Best for | Complex strategies, bracket orders, portfolio | Fast parameter sweeps, simple signals |

**Use backtrader when you need:**

  • Bracket orders (entry + stop loss + take profit as a unit)
  • Stop-limit or trailing stop orders
  • Order-dependent logic (scale in after first fill, cancel if not filled in N bars)
  • Multi-timeframe strategies (daily signals, hourly execution)
  • Realistic commission and slippage modeling

**Use vectorbt when you need:**

  • Fast parameter optimization over thousands of combinations
  • Simple long/short signals without complex order management
  • Quick prototyping and statistical analysis of results

---

Core Concepts

Backtrader has five core objects that interact through an event loop:

### 1. Cerebro (the engine)

The central orchestrator. You add strategies, data feeds, analyzers, and sizers to Cerebro, then call run().


import backtrader as bt

cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy, fast_period=10, slow_period=30)
cerebro.adddata(data_feed)
cerebro.broker.setcash(100_000)
cerebro.broker.setcommission(commission=0.003)  # 0.3%
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="sharpe")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.run()

### 2. Strategy (your logic)

A Strategy subclass contains all trading logic. Key methods:

  • __init__() — Define indicators. Runs once before backtesting starts.
  • next() — Called on every bar. Place orders here.
  • notify_order(order) — Called when order status changes (submitted, accepted, completed, canceled, margin, expired).
  • notify_trade(trade) — Called when a trade opens or closes. Access P&L here.

class EMACrossover(bt.Strategy):
    params = (
        ("fast_period", 10),
        ("slow_period", 30),
    )
View full documentation

def __init__(self) -> None:

self.ema_fast = bt.ind.EMA(period=self.p.fast_period)

self.ema_slow = bt.ind.EMA(period=self.p.slow_period)

self.crossover = bt.ind.CrossOver(self.ema_fast, self.ema_slow)

def next(self) -> None:

if not self.position:

if self.crossover > 0:

self.buy()

elif self.crossover < 0:

self.close()



### 3. Data Feed

Backtrader data feeds provide OHLCV lines. The most common approach is loading from a pandas DataFrame:

import pandas as pd

df = pd.DataFrame({

"open": [...], "high": [...], "low": [...],

"close": [...], "volume": [...],

}, index=pd.DatetimeIndex([...]))

data = bt.feeds.PandasData(dataname=df)

cerebro.adddata(data)



For CSV files:

data = bt.feeds.GenericCSVData(

dataname="ohlcv.csv",

dtformat="%Y-%m-%d",

openinterest=-1, # no open interest column

)



### 4. Broker

The built-in broker simulates order execution with configurable cash, commission, and slippage.

cerebro.broker.setcash(100_000)

cerebro.broker.setcommission(commission=0.003) # 0.3% per trade

Cheat-on-open: execute at the open of the signal bar (avoids lookahead)

cerebro.broker.set_coo(True)



### 5. Analyzers

Analyzers compute performance metrics after the backtest completes.

cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="sharpe",

riskfreerate=0.0, annualize=True, timeframe=bt.TimeFrame.Days)

cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")

cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="trades")

cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")

results = cerebro.run()

strat = results[0]

sharpe = strat.analyzers.sharpe.get_analysis()

dd = strat.analyzers.drawdown.get_analysis()

trades = strat.analyzers.trades.get_analysis()



---

## Order Types

Backtrader supports complex order types critical for realistic crypto backtesting.

### Market Order

self.buy() # market buy

self.sell() # market sell

self.close() # close current position



### Limit Order

self.buy(exectype=bt.Order.Limit, price=95.0)

self.sell(exectype=bt.Order.Limit, price=105.0)



### Stop Order

Triggers a market order when price reaches the stop level:

self.sell(exectype=bt.Order.Stop, price=90.0) # stop loss



### Stop-Limit Order

Triggers a limit order when price reaches the stop level:

self.buy(exectype=bt.Order.StopLimit, price=100.0, plimit=101.0)



### Bracket Order

Entry + stop loss + take profit as an atomic unit. If the stop fills, the take profit is canceled (and vice versa).

self.buy_bracket(

price=100.0, # entry limit

stopprice=95.0, # stop loss

limitprice=110.0, # take profit

exectype=bt.Order.Limit,

stopexec=bt.Order.Stop,

limitexec=bt.Order.Limit,

)



See `references/strategy_patterns.md` for bracket order patterns with ATR-based stops.

---

## Position Sizing (Sizers)

Sizers determine how many units to buy/sell per order.

Fixed size

cerebro.addsizer(bt.sizers.FixedSize, stake=100)

Percent of portfolio

cerebro.addsizer(bt.sizers.PercentSizer, percents=95)

All available cash

cerebro.addsizer(bt.sizers.AllInSizer, percents=95)



Custom sizer:

class RiskSizer(bt.Sizer):

params = (("risk_pct", 0.02),)

def _getsizing(self, comminfo, cash, data, isbuy):

risk_amount = cash * self.p.risk_pct

atr = self.strategy.atr[0]

if atr <= 0:

return 0

size = risk_amount / atr

return int(size)



---

## Crypto Considerations

### 24/7 Markets

Crypto trades around the clock. When using daily bars, there are no weekends to skip. Set the session times or use `sessionstart`/`sessionend` if analyzing specific windows.

### High Fees

DEX swaps on Solana typically cost 0.25-0.30% per trade. Set commission accordingly:

cerebro.broker.setcommission(commission=0.003) # 0.3% round trip per side



### Fractional Sizing

Crypto allows fractional units. Backtrader supports this natively -- no special config needed.

### Slippage

For realistic simulation, enable cheat-on-open and add slippage:

cerebro.broker.set_coo(True)

cerebro.broker.set_slippage_perc(0.001) # 0.1% slippage



### Volatile Data

Crypto OHLCV data often has extreme wicks. Use ATR-based stops rather than fixed percentage stops to adapt to volatility.

---

## Multi-Timeframe

Backtrader can resample data to multiple timeframes within a single strategy:

data_1h = bt.feeds.PandasData(dataname=df_1h)

cerebro.adddata(data_1h)

Resample 1h to daily

cerebro.resampledata(data_1h, timeframe=bt.TimeFrame.Days, compression=1)



Access in strategy:

def __init__(self):

self.ema_1h = bt.ind.EMA(self.datas[0], period=20) # hourly

self.ema_daily = bt.ind.EMA(self.datas[1], period=20) # daily



---

## Custom Indicators

class SpreadIndicator(bt.Indicator):

lines = ("spread", "zscore",)

params = (("period", 20),)

def __init__(self):

mean = bt.ind.SMA(self.data, period=self.p.period)

std = bt.ind.StdDev(self.data, period=self.p.period)

self.lines.

Score breakdown

Trigger
6.0
What-only description with framework keywords; strong Use-backtrader-when / Use-vectorbt-when guidance in body but not in description; no trigger variants, no Chinese keywords.
Structure
9.3
348-line SKILL.md; api_guide + strategy_patterns references and two scripts; Files table; inline See-references pointers.
Workflow
8.0
Task-oriented guide with runnable EMA-crossover and bracket-order demo scripts (synthetic data, seeded), realistic-commission and slippage configuration, lookahead avoidance via set_coo; moderate failure-path coverage (order status notifications documented).
Content
10.0
Concise tables, complete code snippets with parameters, consistent formatting.
Engineering
10.0
Valid frontmatter; shebangs, deps declared in Quick Start, --demo flags default to synthetic data; all referenced paths exist.
Security
10.0
Manifest: no network, no file/env/credential reads (plot example writes a PNG to cwd, benign); pure local backtesting on synthetic data; capabilities match declared scope. No injection, no secrets.
Clear framework guide: event-driven vs vectorized decision table (use backtrader vs vectorbt), core object walkthrough, order types incl. brackets, crypto-specific commission/slippage/lookahead guidance (cheat-on-open), two demo scripts on synthetic data. Description is What-only; When/When-Not lives in body only.