Frequently Asked Questions (FAQ)¶
This document addresses common questions, issues, and best practices when using Backtrader for quantitative trading and backtesting.
Table of Contents¶
1. Installation & Setup¶
Q: Why does Cython compilation fail on Windows?¶
A:* Windows compilation may have minor warnings that can be safely ignored. The key is to use the correct command separator:
# Windows - use semicolons
cd backtrader; python -W ignore compile_cython_numba_files.py; cd ..; pip install -U .
```bash
If compilation completely fails, ensure you have:
- Microsoft Visual C++ Build Tools installed
- Python 3.11 or higher
- All required dependencies from `requirements.txt`
- *Reference:** [Installation Guide](../opts/getting_started/installation.md)
### Q: Do I need to compile Cython files?
- *A:** Cython compilation is recommended but not strictly required. The framework will work without it, but you'll miss out on 10-100x performance improvements for:
- Time series calculations (`ts` mode)
- Cross-section calculations (`cs` mode)
- Performance indicator calculations
For production backtesting, always compile with Cython.
### Q: Which Python version should I use?
- *A:** Python 3.11 or higher is recommended. The framework is tested on Python 3.8-3.13, but 3.11+ offers the best performance and compatibility.
### Q: Can I use this framework without git?
- *A:** Yes, you can download the repository as a ZIP file and extract it. However, using git makes it easier to update and track changes.
### Q: ImportError: No module named 'backtrader' after installation
- *A:** This usually means the installation didn't complete successfully. Try:
```bash
# Reinstall with upgrade flag
pip install -U /path/to/backtrader
# Or if in the source directory
cd /path/to/backtrader
pip install -U .
```bash
- --
## 2. Data Feed Issues
### Q: How do I handle missing data in my CSV file?
- *A:** There are several approaches:
```python
# Option 1: Forward fill missing data
import pandas as pd
df = pd.read_csv('data.csv', parse_dates=['datetime'])
df = df.set_index('datetime').asfreq('1D').ffill()
# Option 2: Use PandasData with checks
data = bt.feeds.PandasData(dataname=df)
# Option 3: Custom data feed with preprocessing
class MyCSVData(bt.feeds.GenericCSVData):
params = (
('nullvalue', 0.0), # Replace NaN with 0
('fillvalue', 0.0),
)
```bash
### Q: Why is my data feed not loading?
- *A:**Common causes:
1.**Wrong datetime format**: Specify the correct format
```python
data = bt.feeds.GenericCSVData(
dataname='data.csv',
dtformat='%Y-%m-%d %H:%M:%S',
)
Column mismatch: Verify column indices match your CSV
data = bt.feeds.GenericCSVData( dataname='data.csv', datetime=0, open=1, high=2, low=3, close=4, volume=5, )
File path issues: Use absolute paths
import os path = os.path.abspath('data.csv')
Q: How do I use multiple data feeds?¶
A:* Add multiple feeds and access them by name:
cerebro = bt.Cerebro()
# Add feeds with names
data1 = bt.feeds.PandasData(dataname=df1)
data2 = bt.feeds.PandasData(dataname=df2)
cerebro.adddata(data1, name='asset1')
cerebro.adddata(data2, name='asset2')
# In strategy, access by data name
class MyStrategy(bt.Strategy):
def __init__(self):
self.data1 = self.getdatabyname('asset1')
self.data2 = self.getdatabyname('asset2')
def next(self):
if self.data1.close[0] > self.data2.close[0]:
self.buy()
```bash
### Q: How do I resample data to a different timeframe?
- *A:** Use `resampledata`:
```python
# Load 1-minute data
data = bt.feeds.PandasData(dataname=minute_df)
# Resample to hourly
cerebro.resampledata(
data,
timeframe=bt.TimeFrame.Minutes,
compression=60, # 60 minutes = 1 hour
)
# Keep original and resampled
cerebro.adddata(data, name='minute')
cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=60, name='hour')
```bash
### Q: Why are my indicators showing NaN values?
- *A:** Indicators need a minimum number of bars (warmup period) before producing valid values:
```python
class MyStrategy(bt.Strategy):
def __init__(self):
self.sma = bt.indicators.SMA(period=20)
def next(self):
# Check if indicator has enough data
if len(self.data) >= self.sma.period:
# Now SMA has valid values
print(f'SMA: {self.sma[0]}')
else:
print(f'Warming up... {len(self.data)}/{self.sma.period}')
```bash
- *Reference:** [Data Feeds Guide](../opts/user_guide/data_feeds.md)
- --
## 3. Performance Problems
### Q: Why is my backtest so slow?
- *A:** Several factors affect performance:
- *1. Not using Cython:**
```bash
# Compile for 10-100x speedup
cd backtrader && python -W ignore compile_cython_numba_files.py && cd .. && pip install -U .
```bash
- *2. Using inefficient data access:**
```python
# SLOW - Repeated attribute access
for i in range(len(data)):
close = data.close[0] # Accesses property each time
# FAST - Cache reference
close_line = data.close
for i in range(len(data)):
close = close_line[0]
```bash
- *3. Too many indicators:**
```python
# Consider using only essential indicators
# Or use preloading with runonce()
cerebro.run(runonce=True) # Much faster for large datasets
```bash
- *4. Large datasets without limits:**
```python
# Use date range or numdos
data = bt.feeds.PandasData(
dataname=df,
fromdate=datetime(2023, 1, 1),
todate=datetime(2023, 12, 31),
)
```bash
- *5. Debug mode enabled:**
```python
# Ensure cerebro not in debug mode
cerebro = bt.Cerebro() # Default is fastest
```bash
### Q: How can I speed up optimization?
- *A:** Use parallel processing and reduce parameters:
```python
# Use multiprocessing
cerebro.optstrategy(
MyStrategy,
period=[5, 10, 20, 50],
devfactor=[1.0, 2.0],
)
maxcpu = cerebro.run(maxcpu=4) # Use 4 CPU cores
```bash
### Q: Memory usage is too high with large datasets
- *A:** Implement these strategies:
```python
# 1. Use qbuffer to limit memory
cerebro.run(qbuffer=True)
# 2. Process in chunks
def run_backtest_chunks(start_date, end_date, chunk_days=30):
results = []
current = start_date
while current < end_date:
chunk_end = min(current + timedelta(days=chunk_days), end_date)
data = load_data(current, chunk_end)
# Run backtest for this chunk
cerebro = bt.Cerebro()
cerebro.adddata(data)
result = cerebro.run()
results.append(result)
current = chunk_end
return results
# 3. Use HDF5 with compression
import pandas as pd
df.to_hdf('data.h5', 'data', mode='w', complevel=9, complib='blosc')
data = bt.feeds.PandasData(dataname=pd.read_hdf('data.h5'))
```bash
- *Reference:** [Performance Optimization Summary](../opts/performance_optimization_summary.md)
### Q: Why is the `dev` branch faster than `master`?
- *A:** The `dev` branch includes:
- Metaclass removal (45% performance improvement)
- Optimized broker operations
- Cython-accelerated calculations
- Reduced redundant function calls
For production use, prefer the `dev` branch for better performance.
- --
## 4. Live Trading Questions
### Q: CCXT connection errors - how to fix?
- *A:** Common CCXT issues and solutions:
- *1. Rate limit exceeded:**
```python
# Enable rate limiting
store = bt.stores.CCXTStore(
exchange='binance',
config={
'apiKey': 'your_key',
'secret': 'your_secret',
'enableRateLimit': True, # Essential
'rateLimit': 1200, # Requests per minute
}
)
```bash
- *2. Network timeout:**
```python
# Increase timeout and add retry
broker = store.getbroker(
max_retries=3,
retry_delay=1.0,
)
```bash
- *3. Invalid API keys:**
```python
# Verify API keys have correct permissions
# Required: Read + Trade (no withdrawal needed)
```bash
- *4. WebSocket fallback:**
```python
# Enable automatic fallback
data = store.getdata(
dataname='BTC/USDT',
use_websocket=True,
# Falls back to REST if WS fails
)
```bash
- *Reference:** [CCXT Live Trading Guide](../CCXT_LIVE_TRADING_GUIDE.md)
### Q: CTP login failures - what to check?
- *A:** CTP (China Futures) login issues:
```python
# Common fixes:
store = bt.stores.CTPStore(
user_id='your_id',
password='your_password',
broker_id='9999', # Check broker ID
td_address='sim.nowgateway.future.com.cn:10101', # Check address
md_address='sim.nowgateway.future.com.cn:10131',
app_id='simnow_client', # For SimNow
auth_code='0000000000000000', # For SimNow
# Production uses different addresses
)
# Check:
# 1. Trading hours (CTP has specific market hours)
# 2. Network connectivity to CTP servers
# 3. User ID and password correctness
# 4. Broker ID validity
```bash
- *Reference:** [CTP Data Feed Documentation](../backtrader/feeds/ctpdata.py)
### Q: How do I handle live data disconnections?
- *A:** Implement reconnection logic:
```python
class RobustStrategy(bt.Strategy):
def notify_data(self, data, status, *args, **kwargs):
if status == data.DISCONNECTED:
self.log(f'Data disconnected: {data._name}')
# Implement alert logic
# Could trigger reconnect or pause trading
def next(self):
# Check data freshness
if hasattr(self.data, '_last_update'):
age = datetime.now() - self.data._last_update
if age > timedelta(minutes=5):
self.log('WARNING: Stale data detected')
```bash
### Q: WebSocket vs REST for live trading?
- *A:** Use WebSocket when possible:
```python
# WebSocket (Recommended)
data = store.getdata(
dataname='BTC/USDT',
use_websocket=True, # Lower latency, less API usage
)
# REST Polling (Fallback)
data = store.getdata(
dataname='BTC/USDT',
# use_websocket=False (default)
)
```bash
- *Comparison:**
| Feature | WebSocket | REST |
|---------|-----------|------|
| Latency | 10-50ms | 100-500ms |
| API Usage | Minimal | High |
| Complexity | Medium | Low |
| Reliability | Good | Excellent |
- *Reference:** [WebSocket Guide](../WEBSOCKET_GUIDE.md)
- --
## 5. Error Messages & Solutions
### Q: "KeyError: datetime" when loading CSV data
- *A:** The datetime column isn't being parsed correctly:
```python
# Solution 1: Specify column
data = bt.feeds.GenericCSVData(
dataname='data.csv',
datetime=0, # Column index
dtformat='%Y-%m-%d %H:%M:%S',
)
# Solution 2: Use Pandas to preprocess
df = pd.read_csv('data.csv')
df['datetime'] = pd.to_datetime(df['datetime'])
data = bt.feeds.PandasData(dataname=df)
```bash
### Q: "IndexError: array index out of range"
- *A:** Accessing data beyond available length:
```python
# WRONG
class MyStrategy(bt.Strategy):
def next(self):
ma = self.sma[-50] # May not exist yet
# CORRECT
class MyStrategy(bt.Strategy):
def next(self):
if len(self.data) >= 50:
ma = self.sma[-50]
```bash
### Q: "AttributeError: 'Strategy' object has no attribute 'position'"
- *A:** Forgetting to call parent `__init__`:
```python
# WRONG
class MyStrategy(bt.Strategy):
def __init__(self):
# Missing super().__init__()
self.sma = bt.indicators.SMA(period=20)
# CORRECT - Call super first!
class MyStrategy(bt.Strategy):
def __init__(self):
super().__init__() # CRITICAL - sets up position, orders, etc.
self.sma = bt.indicators.SMA(period=20)
```bash
### Q: "RuntimeError: live feed must use preloading=False and runonce=False"
- *A:** Live feeds require specific settings:
```python
# This error is automatically handled
# Backtrader detects live feeds and adjusts
# But if you manually set:
cerebro = bt.Cerebro()
# Don't set:
# cerebro.run(preload=False, runonce=False)
# It's automatic for live feeds
```bash
### Q: "ZeroDivisionError" in custom indicators
- *A:** Handle edge cases:
```python
class MyIndicator(bt.Indicator):
lines = ('value',)
def next(self):
# WRONG
self.lines.value[0] = self.data.close[0] / self.data.volume[0]
# CORRECT
vol = self.data.volume[0]
if vol > 0:
self.lines.value[0] = self.data.close[0] / vol
else:
self.lines.value[0] = 0.0
```bash
- --
## 6. Common Gotchas
### Q: Why are my indicators not updating?
- *A:** Common causes:
- *1. Indicator not registered:**
```python
class MyStrategy(bt.Strategy):
def __init__(self):
super().__init__() # Must call super!
# Indicators auto-register after super().__init__()
self.sma = bt.indicators.SMA(self.data, period=20)
```bash
- *2. Missing data owner:**
```python
# WRONG - Indicator created outside strategy
sma = bt.indicators.SMA(period=20) # No owner
# CORRECT - Created within strategy
class MyStrategy(bt.Strategy):
def __init__(self):
super().__init__()
self.sma = bt.indicators.SMA(period=20) # Strategy is owner
```bash
- *3. Parameter access before initialization:**
```python
# WRONG - Accessing self.p before super().__init__()
class MyStrategy(bt.Strategy):
def __init__(self):
self.period = self.p.period # ERROR!
# CORRECT
class MyStrategy(bt.Strategy):
def __init__(self):
super().__init__() # Sets up self.p
self.period = self.p.period # Now it works
```bash
### Q: Why does my strategy miss the first bar?
- *A:** Indicators need warmup period:
```python
class MyStrategy(bt.Strategy):
def __init__(self):
super().__init__()
self.sma20 = bt.indicators.SMA(period=20)
self.sma50 = bt.indicators.SMA(period=50)
# Strategy won't trade until bar 50
def start(self):
# Override start() to reduce warmup
# (Not recommended - indicators will be invalid)
pass
```bash
- *Solution:** Use `prenext()` to handle warmup:
```python
class MyStrategy(bt.Strategy):
def prenext(self):
# Called during warmup
self.log(f'Warming up... {len(self.data)}')
def next(self):
# Called after warmup complete
pass
```bash
### Q: Why are my order sizes incorrect?
- *A:** Check broker settings and calculations:
```python
class MyStrategy(bt.Strategy):
def next(self):
# WRONG - Doesn't account for available cash
self.buy(size=100)
# CORRECT - Calculate position size
cash = self.broker.getcash()
price = self.data.close[0]
size = int(cash *0.95 / price) # Use 95% of cash
self.buy(size=size)
```bash
### Q: Plotting issues on different platforms
- *A:** Platform-specific solutions:
- *Linux (no display):**
```python
# Use Agg backend (no display)
import matplotlib
matplotlib.use('Agg')
import backtrader as bt
# Or save directly
cerebro.plot()[0][0].savefig('output.png')
```bash
- *macOS (Python 3.11+):**
```bash
# May need: pip install pyqt5
export MPLBACKEND=Qt5Agg
```bash
- *Large datasets:**
```python
# Use plotly for interactive charts
cerebro.plot(style='plotly', volume=False) # Disable volume for speed
```bash
- *Reference:** [Plotting Documentation](../plot/README.md)
- --
## 7. Best Practices
### Q: How should I structure my backtesting project?
- *A:** Recommended structure:
```bash
project/
├── data/ # Data files
├── strategies/ # Strategy definitions
│ ├── __init__.py
│ ├── base.py # Base strategy class
│ └── my_strategy.py
├── indicators/ # Custom indicators
├── tests/ # Unit tests
├── configs/ # Configuration files
├── results/ # Backtest results
├── notebooks/ # Jupyter notebooks
└── main.py # Entry point
```bash
### Q: How do I properly size positions?
- *A:** Use risk-based position sizing:
```python
class RiskManagedStrategy(bt.Strategy):
params = (
('risk_per_trade', 0.02), # 2% risk per trade
('stop_distance_pct', 0.02), # 2% stop loss
)
def calculate_position_size(self):
account_value = self.broker.getvalue()
risk_amount = account_value *self.p.risk_per_trade
stop_distance = self.data.close[0]*self.p.stop_distance_pct
position_size = risk_amount / stop_distance
return int(position_size)
```bash
### Q: How do I validate my strategy?
- *A:** Multi-step validation:
```python
# 1. In-sample test
train_data = load_data(start='2020-01-01', end='2022-12-31')
cerebro_train = bt.Cerebro()
cerebro_train.adddata(train_data)
results_train = cerebro_train.run()
# 2. Out-of-sample test
test_data = load_data(start='2023-01-01', end='2024-12-31')
cerebro_test = bt.Cerebro()
cerebro_test.adddata(test_data)
results_test = cerebro_test.run()
# 3. Walk-forward analysis
# (Split data into multiple train/test periods)
# 4. Monte Carlo simulation
# (Randomize order of trades)
```bash
### Q: How do I log effectively?
- *A:** Use structured logging:
```python
import logging
from datetime import datetime
class LoggingStrategy(bt.Strategy):
def __init__(self):
super().__init__()
self.logger = logging.getLogger(__name__)
self.logger.setLevel(logging.INFO)
def log(self, txt, dt=None):
dt = dt or self.data.datetime[0]
if isinstance(dt, float):
dt = datetime.fromtimestamp(dt)
self.logger.info(f'{dt.isoformat()} {txt}')
def next(self):
if self.sma[0] > self.data.close[0]:
self.log(f'SMA > Close: {self.sma[0]:.2f} > {self.data.close[0]:.2f}')
```bash
### Q: How do I handle commissions and slippage?
- *A:** Configure broker properly:
```python
cerebro = bt.Cerebro()
# Set commission scheme
cerebro.broker.setcommission(
commission=0.001, # 0.1%
mult=1, # Multiplier
margin=0.1, # Margin requirement (10%)
commtype=bt.CommInfoBase.COMM_PERC, # Percentage-based
)
# Add slippage
cerebro.broker.set_slippage_perc(perc=0.0005) # 0.05% slippage
# Or fixed per-share
cerebro.broker.setcommission(commission=0.001, commtype=bt.CommInfoBase.COMM_FIXED)
```bash
### Q: How do I export backtest results?
- *A:**Multiple methods:
```python
# 1. Use analyzers
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
strat = cerebro.run()[0]
sharpe = strat.analyzers.sharpe.get_analysis()
drawdown = strat.analyzers.drawdown.get_analysis()
trades = strat.analyzers.trades.get_analysis()
# 2. Export to CSV
class CSVWriter(bt.Analyzer):
def __init__(self):
self.file = open('trades.csv', 'w')
self.file.write('date,price,size,value\n')
def notify_trade(self, trade):
if trade.isclosed:
self.file.write(f'{trade.dt},{trade.price},{trade.size},{trade.value}\n')
# 3. Save plot
fig = cerebro.plot()[0][0]
fig.savefig('backtest.png')
```bash
- --
## Additional Resources
| Topic | Documentation |
|-------|---------------|
| Installation | [Installation Guide](../opts/getting_started/installation.md) |
| Quick Start | [Quick Start Guide](../opts/getting_started/quickstart.md) |
| Data Feeds | [Data Feeds Guide](../opts/user_guide/data_feeds.md) |
| Indicators | [Indicators Guide](../opts/user_guide/indicators.md) |
| Strategies | [Strategies Guide](../opts/user_guide/strategies.md) |
| CCXT Trading | [CCXT Live Trading Guide](../CCXT_LIVE_TRADING_GUIDE.md) |
| WebSocket | [WebSocket Guide](../WEBSOCKET_GUIDE.md) |
| Performance | [Performance Optimization](../opts/performance_optimization_summary.md) |
| Architecture | [Architecture Documentation](../ARCHITECTURE.md) |
## Getting Help
If you don't find an answer here:
1.**Search existing documentation**- Most issues are covered
2.**Check the test files**- `tests/` directory has examples
3.**Review source code**- Well-commented code explains behavior
4.**File an issue** - Include minimal reproducible example
## Quick Reference: Common Commands
```bash
# Run tests
pytest tests/ -n 4 -v
# Compile Cython
cd backtrader && python -W ignore compile_cython_numba_files.py && cd .. && pip install -U .
# Generate documentation
make docs
# Run with coverage
pytest tests/ --cov=backtrader --cov-report=term-missing
# Type checking
mypy backtrader/
# Code formatting
black backtrader/
```bash
- --
- Last updated: 2026-03-01*