Skip to content

Backtrader Compatibility Guide

Cracktrader is built on top of Backtrader, providing full compatibility with existing Backtrader strategies while adding cryptocurrency trading capabilities. This guide covers supported features, differences, and migration patterns.

Overview

What's Supported

Core Strategy Features: - All bt.Strategy methods (next(), __init__(), notify_*()) - Parameter system (params tuple) - Position management (buy(), sell(), close()) - Order management (market, limit, stop orders) - Data access patterns (self.data.close[0], self.data.high[-1])

Indicators (100+ Built-in): - All standard Backtrader indicators - Technical Analysis indicators - Custom indicator development - Indicator chaining and combinations

Analyzers: - Performance analyzers (Sharpe, Returns, Drawdown) - Trade analyzers (win rate, profit factor) - Custom analyzer development - Portfolio analysis

Data Handling: - Multiple timeframes - Data resampling and replaying - Historical and live data - Custom data feeds

What's Enhanced

Exchange Integration: - Real-time data from 100+ exchanges via CCXT - Live order execution on real exchanges - Unified paper/live trading modes - Advanced order types (OCO, brackets)

Modern Infrastructure: - Async/await support for real-time operations - Comprehensive logging and monitoring - Web API for remote control - Health monitoring and alerting

What's Different

Data Feeds: - CCXT-based feeds instead of file-based - Real-time streaming capabilities - Cryptocurrency-specific features (funding rates, etc.)

Broker Behavior: - Live execution involves actual exchange APIs - Commission models reflect real exchange fees - Slippage models based on orderbook depth

Migration Guide

Basic Strategy Migration

Before (Pure Backtrader):

import backtrader as bt

class MyStrategy(bt.Strategy):
    def __init__(self):
        self.sma = bt.indicators.SMA(period=20)

    def next(self):
        if self.data.close[0] > self.sma[0]:
            self.buy()

# Setup
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy)

# Add CSV data
data = bt.feeds.YahooFinanceData(dataname='AAPL')
cerebro.adddata(data)

cerebro.run()

After (Cracktrader):

import backtrader as bt
from datetime import datetime
from cracktrader import Cerebro, CCXTStore, CCXTDataFeed

class MyStrategy(bt.Strategy):  # No changes needed!
    def __init__(self):
        self.sma = bt.indicators.SMA(period=20)

    def next(self):
        if self.data.close[0] > self.sma[0]:
            self.buy()

# Enhanced setup
cerebro = Cerebro()  # Use Cracktrader's Cerebro
cerebro.addstrategy(MyStrategy)

# Add crypto data
store = CCXTStore(exchange='binance')
feed = CCXTDataFeed(
    store=store,
    symbol='BTC/USDT',
    ccxt_timeframe='1h',
    fromdate=datetime(2024, 1, 1),
    todate=datetime(2024, 3, 1)
)
cerebro.adddata(feed)

cerebro.run()

Data Feed Migration

CSV/Yahoo Finance → CCXT:

# Old way
from datetime import datetime
data = bt.feeds.YahooFinanceData(
    dataname='AAPL',
    fromdate=datetime(2023, 1, 1),
    todate=datetime(2023, 12, 31)
)

# New way
store = CCXTStore(exchange='binance')
data = CCXTDataFeed(
    store=store,
    symbol='BTC/USDT',
    ccxt_timeframe='1d',
    fromdate=datetime(2023, 1, 1),
    todate=datetime(2023, 12, 31)
)

Custom Data Feeds:

# Backtrader custom feed
class MyCSVData(bt.feeds.GenericCSVData):
    params = (
        ('datetime', 0),
        ('open', 1),
        ('high', 2),
        ('low', 3),
        ('close', 4),
        ('volume', 5),
    )

# Cracktrader focuses on CCXT-backed feeds. For custom sources,
# implement a Backtrader-compatible feed in your project.

Broker Migration

Backtrader Broker:

cerebro.broker.setcash(10000)
cerebro.broker.setcommission(commission=0.001)

Cracktrader Broker (Backtest):

# Same API - no changes needed
cerebro.broker.setcash(10000)
cerebro.broker.setcommission(commission=0.001)

# Or use BrokerFactory for paper mode
from cracktrader.broker import BrokerFactory
broker = BrokerFactory.create(mode='paper', cash=10000)
cerebro.setbroker(broker)

Cracktrader Broker (Live):

from cracktrader.broker import BrokerFactory

# Paper trading (with live data feed)
paper_broker = BrokerFactory.create(mode='paper', cash=10000)
cerebro.setbroker(paper_broker)

# Live trading
live_broker = BrokerFactory.create(mode='live', store=store)
cerebro.setbroker(live_broker)

Feature Compatibility Matrix

Core Strategy Methods

Method Backtrader Cracktrader Notes
__init__() Fully compatible
next() Fully compatible
prenext() Fully compatible
nextstart() Fully compatible
start() Fully compatible
stop() Enhanced with logging
notify_order() Enhanced order states
notify_trade() Enhanced trade info
notify_cashvalue() Real-time updates

Order Types

Order Type Backtrader Cracktrader Notes
Market Immediate execution
Limit Exchange limit orders
Stop Stop-loss orders
StopLimit Stop-limit combinations
Bracket Enhanced with OCO
OCO Cracktrader exclusive
Trailing Stop Cracktrader exclusive

Indicators

All Backtrader indicators are supported:

# Standard indicators work unchanged
self.sma = bt.indicators.SimpleMovingAverage(period=20)
self.rsi = bt.indicators.RSI(period=14)
self.macd = bt.indicators.MACD()
self.bb = bt.indicators.BollingerBands()

# Plotting works the same way
self.sma.plotinfo.plot = True
self.sma.plotinfo.plotname = 'SMA(20)'

Enhanced Cryptocurrency Indicators:

from cracktrader.indicators import FundingRate, PerpetualPremium

# Crypto-specific indicators
self.funding = FundingRate(period=8)  # 8-hour funding
self.premium = PerpetualPremium(spot_data=self.data0, perp_data=self.data1)

Analyzers

Standard Analyzers:

Analyzer Backtrader Cracktrader Enhancement
Returns Real-time calculation
SharpeRatio Multiple benchmarks
DrawDown Live monitoring
TradeAnalyzer Enhanced metrics
PositionsValue Multi-asset support

Enhanced Analyzers:

from cracktrader.analyzers import CryptoAnalyzer, RiskAnalyzer

# Crypto-specific analysis
cerebro.addanalyzer(CryptoAnalyzer, _name='crypto')
cerebro.addanalyzer(RiskAnalyzer, _name='risk')

Advanced Features

Multi-Exchange Support

# Connect to multiple exchanges
binance_store = CCXTStore(exchange='binance')
coinbase_store = CCXTStore(exchange='coinbase')

# Compare prices across exchanges
binance_feed = CCXTDataFeed(binance_store, 'BTC/USDT')
coinbase_feed = CCXTDataFeed(coinbase_store, 'BTC/USD')

cerebro.adddata(binance_feed, name='binance')
cerebro.adddata(coinbase_feed, name='coinbase')

class ArbitrageStrategy(bt.Strategy):
    def next(self):
        binance_price = self.datas[0].close[0]
        coinbase_price = self.datas[1].close[0]

        spread = (coinbase_price - binance_price) / binance_price
        if spread > 0.01:  # 1% arbitrage opportunity
            self.buy(data=self.datas[0])  # Buy on Binance
            self.sell(data=self.datas[1])  # Sell on Coinbase

Real-time Data Streaming

class LiveStrategy(bt.Strategy):
    def next(self):
        # This runs in real-time with live market data
        current_time = self.data.datetime.datetime()
        current_price = self.data.close[0]

        # Real-time decision making
        if self.should_trade():
            self.buy()

# Setup for live trading
store = CCXTStore(exchange='binance', sandbox=True)
feed = CCXTDataFeed(store=store, symbol='BTC/USDT', ccxt_timeframe='1m')
# No start/end dates = live streaming

cerebro = Cerebro()
cerebro.adddata(feed)
cerebro.addstrategy(LiveStrategy)
cerebro.run()  # Runs until stopped

Enhanced Order Management

class AdvancedOrderStrategy(bt.Strategy):
    def next(self):
        if not self.position:
            # Place bracket order (entry + stop + target)
            main_order = self.buy()

            # Automatic stop loss and take profit
            stop_price = self.data.close[0] * 0.95  # 5% stop
            target_price = self.data.close[0] * 1.10  # 10% target

            self.sell(exectype=bt.Order.Stop, price=stop_price, parent=main_order)
            self.sell(exectype=bt.Order.Limit, price=target_price, parent=main_order)

# OCO (One-Cancels-Other) orders
class OCOStrategy(bt.Strategy):
    def next(self):
        if not self.position:
            # Entry order
            entry_order = self.buy_bracket(
                price=self.data.close[0] * 1.01,  # Entry above current
                stopprice=self.data.close[0] * 0.95,  # Stop loss
                limitprice=self.data.close[0] * 1.15   # Take profit
            )

Performance Considerations

Backtrader vs Cracktrader Performance

Backtrader (File-based): - Fast for historical backtests - Limited by disk I/O for large datasets - No real-time capabilities

Cracktrader (Network-based): - Slightly slower for pure backtests (network overhead) - Excellent for real-time operations - Scalable with caching and optimization

Optimization Tips

# 1. Use appropriate timeframes
# High-frequency: Use lower timeframes sparingly
feed = CCXTDataFeed(store=store, symbol='BTC/USDT', timeframe='5m')  # Not '1s'

# 2. Limit historical data range
feed = CCXTDataFeed(
    store=store,
    symbol='BTC/USDT',
    timeframe='1h',
    start_date='2024-01-01',  # Don't go back years unless needed
    end_date='2024-03-01'
)

# 3. Use data caching
store = CCXTStore(exchange_id='binance', cache_enabled=True)

# 4. Optimize indicator calculations
class OptimizedStrategy(bt.Strategy):
    def __init__(self):
        # Calculate once, use many times
        self.sma = bt.indicators.SMA(period=20)
        self.signal = self.data.close > self.sma  # Boolean series

    def next(self):
        if self.signal[0]:  # Direct boolean check
            self.buy()

Testing Compatibility

Running Backtrader Tests

# Most Backtrader test patterns work unchanged
import unittest
from cracktrader import Cerebro  # Drop-in replacement

class TestMyStrategy(unittest.TestCase):
    def setUp(self):
        self.cerebro = Cerebro()
        self.cerebro.addstrategy(MyStrategy)

        # Use test data
        from tests.fixtures.fake_exchange import FakeExchange
        store = CCXTStore(exchange_id='fake', exchange=FakeExchange())
        feed = CCXTDataFeed(store=store, symbol='BTC/USDT')
        self.cerebro.adddata(feed)

    def test_strategy_runs(self):
        results = self.cerebro.run()
        self.assertIsNotNone(results)

Mocking for Tests

from unittest.mock import Mock, patch

class TestCryptoStrategy(unittest.TestCase):
    @patch('cracktrader.store.CCXTStore')
    def test_with_mocked_exchange(self, mock_store):
        # Mock exchange behavior
        mock_store.return_value.fetch_ohlcv.return_value = [
            [1640995200000, 50000, 51000, 49000, 50500, 100],  # OHLCV data
        ]

        cerebro = Cerebro()
        cerebro.addstrategy(MyStrategy)
        # Test continues...

Migration Checklist

Pre-Migration Assessment

  • [ ] Inventory existing strategies - List all Backtrader strategies
  • [ ] Identify data sources - CSV files, Yahoo Finance, custom feeds
  • [ ] Review custom indicators - Any custom-built indicators
  • [ ] Check broker configurations - Commission, slippage settings
  • [ ] List analyzers used - Performance analysis requirements

Migration Steps

  1. Install Cracktrader

    pip install -e .'[web]'
    

  2. Update imports

    # Add to existing imports
    from cracktrader import Cerebro, CCXTStore, CCXTDataFeed
    

  3. Replace Cerebro

    # cerebro = bt.Cerebro()
    cerebro = Cerebro()
    

  4. Replace data feeds

    # Replace file-based feeds with CCXT feeds
    store = CCXTStore(exchange_id='binance')
    feed = CCXTDataFeed(store=store, symbol='BTC/USDT', timeframe='1h')
    cerebro.adddata(feed)
    

  5. Test in sandbox mode

    store = CCXTStore(exchange_id='binance', sandbox=True)
    

  6. Validate results

  7. Compare backtest results with original
  8. Verify indicator calculations
  9. Check performance metrics

  10. Enable live trading (when ready)

    store = CCXTStore(exchange_id='binance', sandbox=False)
    

Post-Migration Validation

def validate_migration():
    """Validate that migrated strategy produces expected results."""

    # Run original Backtrader strategy
    bt_cerebro = bt.Cerebro()
    bt_cerebro.addstrategy(OriginalStrategy)
    # Add equivalent data...
    bt_results = bt_cerebro.run()

    # Run migrated Cracktrader strategy
    ct_cerebro = Cerebro()
    ct_cerebro.addstrategy(MigratedStrategy)
    # Add CCXT data...
    ct_results = ct_cerebro.run()

    # Compare results
    bt_final_value = bt_results[0].broker.getvalue()
    ct_final_value = ct_results[0].broker.getvalue()

    difference = abs(bt_final_value - ct_final_value) / bt_final_value
    assert difference < 0.01, f"Results differ by {difference:.2%}"

    print("✅ Migration validated successfully")

Troubleshooting Common Issues

Import Errors

# Issue: ModuleNotFoundError
# Solution: Check installation
pip list | grep backtrader
pip install -e .'[web]'

# Issue: Conflicting Backtrader versions
# Solution: Use virtual environment
python -m venv cracktrader_env
source cracktrader_env/bin/activate  # Linux/Mac
# cracktrader_env\Scripts\activate  # Windows
pip install -e .'[web]'

Data Format Issues

# Issue: Date format differences
# Backtrader expects datetime objects
# CCXT returns timestamps

# Solution: Automatic conversion in CCXTDataFeed
feed = CCXTDataFeed(
    store=store,
    symbol='BTC/USDT',
    timeframe='1h',
    start_date='2024-01-01T00:00:00Z',  # ISO format
    end_date='2024-03-01T23:59:59Z'
)

Performance Differences

# Issue: Slower backtests compared to file-based
# Solution: Use caching and optimize data fetching

store = CCXTStore(
    exchange_id='binance',
    cache_enabled=True,
    cache_ttl=3600  # 1 hour cache
)

# Or use local data storage
store = CCXTStore(
    exchange_id='binance',
    local_storage=True,
    storage_path='./data_cache'
)

Migration Support: - Issues: Report migration problems on GitHub - Examples: See examples/migration/ for complete migration examples - Community: Join discussions for migration tips and best practices

Next Steps: - Data Feeds Guide - CCXT data integration - Strategy Development - Advanced strategy patterns - Testing Guide - Testing migrated strategies