Интеграция с Backtrader (Python)
Backtrader — зрелый Python-фреймворк для бэктестинга и live trading. Существует с 2015 года, имеет обширную экосистему индикаторов, dataseries типов и брокеров. Хороший выбор для быстрого старта без написания движка с нуля.
Установка и базовая стратегия
import backtrader as bt
import backtrader.feeds as btfeeds
import pandas as pd
class RSIStrategy(bt.Strategy):
params = dict(
rsi_period=14,
rsi_oversold=30,
rsi_overbought=70,
)
def __init__(self):
self.rsi = bt.indicators.RSI(
self.data.close,
period=self.params.rsi_period
)
self.order = None
def next(self):
# Нет открытой позиции
if not self.position:
if self.rsi[0] < self.params.rsi_oversold:
self.order = self.buy()
# Есть открытая позиция
else:
if self.rsi[0] > self.params.rsi_overbought:
self.order = self.sell()
def notify_order(self, order):
if order.status in [order.Completed]:
direction = "BUY" if order.isbuy() else "SELL"
print(f"{direction} executed: price={order.executed.price:.2f}, "
f"cost={order.executed.value:.2f}, comm={order.executed.comm:.2f}")
def notify_trade(self, trade):
if trade.isclosed:
print(f"Trade closed: PnL={trade.pnl:.2f}, PnL net={trade.pnlcomm:.2f}")
Загрузка данных из pandas
def run_backtest(df: pd.DataFrame, strategy_class, **params) -> bt.Cerebro:
cerebro = bt.Cerebro()
# Конвертируем DataFrame в Backtrader feed
data = bt.feeds.PandasData(
dataname=df,
datetime=None, # индекс — это datetime
open='open',
high='high',
low='low',
close='close',
volume='volume',
openinterest=-1,
)
cerebro.adddata(data)
cerebro.addstrategy(strategy_class, **params)
# Настройка брокера
cerebro.broker.setcash(100_000)
cerebro.broker.setcommission(commission=0.001) # 0.1%
# Sizer: торгуем 95% доступного капитала
cerebro.addsizer(bt.sizers.PercentSizer, percents=95)
# Аналитики
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', riskfreerate=0.0)
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
return cerebro
# Запуск
cerebro = run_backtest(df, RSIStrategy, rsi_period=14)
results = cerebro.run()
strat = results[0]
# Извлечение результатов
sharpe = strat.analyzers.sharpe.get_analysis()['sharperatio']
drawdown = strat.analyzers.drawdown.get_analysis()['max']['drawdown']
trade_stats = strat.analyzers.trades.get_analysis()
print(f"Sharpe: {sharpe:.2f}, Max DD: {drawdown:.2f}%")
print(f"Total trades: {trade_stats.total.total}")
print(f"Win rate: {trade_stats.won.total / trade_stats.total.total:.1%}")
Оптимизация параметров
from itertools import product
def optimize_strategy(df: pd.DataFrame) -> pd.DataFrame:
results = []
for rsi_period, oversold, overbought in product(
range(7, 22, 7), # 7, 14, 21
range(20, 41, 10), # 20, 30, 40
range(60, 81, 10), # 60, 70, 80
):
cerebro = run_backtest(df, RSIStrategy,
rsi_period=rsi_period,
rsi_oversold=oversold,
rsi_overbought=overbought)
strategy_results = cerebro.run()
strat = strategy_results[0]
sharpe = strat.analyzers.sharpe.get_analysis().get('sharperatio', 0) or 0
dd = strat.analyzers.drawdown.get_analysis()['max']['drawdown']
final_value = cerebro.broker.getvalue()
results.append({
'rsi_period': rsi_period,
'oversold': oversold,
'overbought': overbought,
'sharpe': sharpe,
'max_drawdown': dd,
'final_value': final_value,
'return_pct': (final_value - 100_000) / 100_000 * 100,
})
return pd.DataFrame(results).sort_values('sharpe', ascending=False)
Кастомный индикатор
class OrderBookImbalance(bt.Indicator):
"""Имбаланс стакана из внешних данных"""
lines = ('imbalance',)
params = dict(period=5)
def __init__(self):
self.addminperiod(self.params.period)
def next(self):
# Данные имбаланса передаются через отдельный dataseries
self.lines.imbalance[0] = self.data[0]
Ограничения Backtrader
- Нет встроенной поддержки tick-данных (только OHLCV)
- Сложная работа с multiple timeframes
- Производительность при оптимизации — медленнее кастомных vectorized решений
- Развитие проекта замедлилось (последний major release — 2019)
Для простых стратегий на OHLCV — Backtrader отличный выбор. Для сложных multi-asset, multi-timeframe стратегий с tick-данными лучше рассмотреть Freqtrade, Jesse или кастомный движок.







