Интеграция с Backtrader (Python)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Интеграция с Backtrader (Python)
Средний
~2-3 дня
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1286
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    902
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1122
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    859

Интеграция с 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 или кастомный движок.