Войти
Главная / Data science в трейдинге / Как создать торгового бота для ByBit на Python: полное руководство для начинающих
Хотите зарабатывать на трейдинге?

Подписывайтесь на наш телеграм-канал для трейдеров — с глубокой аналитикой и рабочими стратегиями

Подписаться

Как собрать свой журнал для тестирования стратегии? Заберите бесплатный гайд

Гайд от нашей команды поможет вам систематизировать торговлю и принимать взвешенные решения

Подтвердите согласие

Как создать торгового бота для ByBit на Python: полное руководство для начинающих

Вас когда-нибудь утомляла постоянная рутина в трейдинге? Следить за графиками, ловить сигналы, переживать из-за каждого движения рынка… Меня — да. Поэтому я задумался об автоматизации своей торговли. Сегодня я хочу поделиться с вами своим опытом создания торгового бота для биржи ByBit с использованием Python.

В последние годы автоматизация в трейдинге перестала быть чем-то сложным или доступным только крупным игрокам. Даже простой бот способен взять на себя рутинные задачи, минимизировать влияние эмоций и обеспечить стабильную работу по заранее заданной стратегии.

В этой статье я покажу, как шаг за шагом создать модульного торгового бота. Мы вместе разберём архитектуру проекта, подключим биржевые данные, реализуем индикаторы, пропишем торговую логику и даже создадим дашборд для мониторинга работы бота.

Почему стоит задуматься об автоматизации трейдинга?

Если вы до сих пор торгуете вручную, вот несколько причин, почему автоматизация может значительно улучшить ваш процесс:

  • Скорость реакции. Алгоритм принимает решения мгновенно, в отличие от человека.
  • Отсутствие эмоций. Бот не поддаётся страху или жадности — он просто выполняет инструкции.
  • Круглосуточная работа. Пока вы спите или отдыхаете, бот продолжает анализировать рынок и торговать.
  • Возможность тестировать стратегии. Прежде чем рисковать реальными средствами, вы можете проверить свои идеи на исторических данных.

Почему я выбрал Python?

Многие спрашивают меня: «Почему именно Python?». Ответ прост: это один из самых удобных языков для подобных задач. Вот его ключевые преимущества:

  • Лёгкий и понятный синтаксис — даже если вы не профессиональный разработчик, разобраться не так уж сложно.
  • Огромное количество библиотек для работы с данными, API и аналитикой.
  • Активное сообщество и масса готовых решений, которые можно использовать или доработать под свои нужды.

Почему именно ByBit?

За время работы с разными биржами я остановился на ByBit по нескольким причинам:

  • У них удобное и хорошо задокументированное API, что критично для алгоритмической торговли.
  • Поддержка как REST API, так и WebSocket — можно получать как исторические данные, так и котировки в реальном времени.
  • Высокая ликвидность и быстрое исполнение ордеров.
  • Возможность торговать не только спотом, но и деривативами, что открывает больше возможностей для стратегий.

В этой серии шагов я подробно расскажу, как построить простого, но гибкого торгового бота для ByBit с использованием модульной архитектуры. Мы не просто напишем код «на коленке», а создадим фундамент для будущего развития — будь то добавление новых стратегий, улучшение риск-менеджмента или подключение уведомлений.

Обзор архитектуры проекта

Когда начинаешь писать своего первого торгового бота, хочется быстро написать код и запустить сделки. Я через это проходил. Но со временем понял: если не продумать структуру проекта с самого начала, потом можно залипнуть в бесконечные правки и путаницу.

Я придерживаюсь простого принципа: каждый элемент проекта должен лежать на своём месте. Для этого я разбиваю всё по папкам — чтобы данные, логика, настройки и визуализация не мешались друг с другом.

Вот структура, которая отлично показала себя в деле:

_00_config/        # Все настройки и конфигурационные файлы
_01_sources/       # Источники данных (API, WebSocket и пр.)
_02_etl/           # Модули для извлечения, трансформации и загрузки данных
_03_datasets/      # Управление и хранение подготовленных данных
_04_indicators/    # Реализация технических индикаторов
_05_patterns/      # Алгоритмы распознавания торговых паттернов
_06_visualization/ # Визуализация данных и сигналов
_07_management/    # Управление рисками и капиталом
_08_baktesting/    # Бэктестинг торговых стратегий
_09_dashboard/     # Интерфейс для мониторинга и контроля
_10_trading/       # Основная логика торговли и взаимодействие с биржей
_11_notebooks/     # Jupyter-ноутбуки для аналитики и экспериментов

Зачем всё это?

  • Порядок в проекте. Вы всегда знаете, где что лежит.
  • Легко дорабатывать. Захотели добавить новый индикатор или стратегию — просто создаёте новый файл в нужной папке.
  • Приятно работать. Когда всё разложено по полочкам, и думать легче.

Конфигурация проекта (_00_config)

Итак, начнём с самого важного шага перед написанием кода — настроек вашего бота.

Поверьте моему опыту, если не вынести все параметры в одно место с самого начала, потом придётся лазить по коду в поисках нужного числа или ключа. А это неудобно и опасно — можно случайно что-то поломать.

Именно поэтому я всегда создаю отдельную папку для конфигурации — _00_config. Здесь будут храниться все настройки, которые вы захотите менять без необходимости копаться в логике бота.

Что должно быть в настройках?

  • API ключи и секреты для подключения к бирже.
  • Выбранные торговые пары (например, BTCUSDT).
  • Параметры стратегии: таймфреймы, периоды индикаторов и т.д.
  • Настройки по управлению рисками: сколько процентов от депозита использовать, где ставить стоп-лосс и тейк-профит.
  • Режим работы: тестовый или боевой.
  • Пути к папкам для хранения данных и логов.

Пример конфигурационного файла

Вот как может выглядеть файл config.py:

# _00_config/config.py

BYBIT_API_KEY = "your_api_key"
BYBIT_API_SECRET = "your_api_secret"

TRADING_PAIR = "BTCUSDT"
TIMEFRAME = "15m"

# Параметры стратегии
EMA_SHORT = 9
EMA_LONG = 21

# Риск-менеджмент
MAX_TRADE_SIZE = 0.05  # В BTC
STOP_LOSS_PERCENT = 1.5
TAKE_PROFIT_PERCENT = 3.0

# Режим работы
MODE = "paper"  # Возможные значения: "paper" или "live"

# Пути
DATA_PATH = "./_03_datasets/"
LOG_PATH = "./logs/"

Теперь, если вам нужно поменять торговую пару или настроить риски — достаточно открыть один файл.

Пару слов о безопасности

Если вы планируете хранить проект в Git или делиться им:

  • Никогда не выкладывайте API-ключи в открытый доступ.
  • Используйте переменные окружения или файл .env.
  • Добавьте config.py в .gitignore.

Для работы с .env удобно использовать библиотеку python-dotenv. Вот как это выглядит:

# .env файл
BYBIT_API_KEY=your_api_key
BYBIT_API_SECRET=your_api_secret
# config.py с использованием dotenv
from dotenv import load_dotenv
import os

load_dotenv()

BYBIT_API_KEY = os.getenv("BYBIT_API_KEY")
BYBIT_API_SECRET = os.getenv("BYBIT_API_SECRET")

Итог: все, что может меняться — должно быть в конфигурации. Это делает ваш проект удобным и безопасным.

Источники данных (_01_sources)

Теперь, когда у нас есть настройки, самое время подключиться к рынку и начать получать данные. Ведь без актуальных котировок бот просто не сможет работать.

В этом модуле мы научим бота «общаться» с биржей ByBit: запрашивать цены, получать информацию о счёте и следить за рынком в реальном времени.

Какие данные нужны торговому боту?

  1. Исторические данные — так называемые свечи (OHLCV). Они нужны для расчёта индикаторов и бэктестинга.
  2. Текущие цены — чтобы понять, когда входить или выходить из сделки.
  3. Данные о вашем балансе и позициях — чтобы контролировать риски.
  4. Статус ордеров — чтобы знать, исполнились ли ваши сделки.

Как получать данные с ByBit?

Биржа предоставляет два основных способа:

  • REST API — подходит для запросов исторических данных, информации о балансе и управления ордерами.
  • WebSocket API — для получения котировок и событий в режиме реального времени.

Чтобы не «изобретать велосипед», я использую готовую библиотеку pybit. Она сильно упрощает работу с API ByBit.

Пример подключения к ByBit через pybit

Создадим файл bybit_client.py в папке _01_sources:

# _01_sources/bybit_client.py

from pybit.unified_trading import HTTP
from _00_config import config

session = HTTP(
    api_key=config.BYBIT_API_KEY,
    api_secret=config.BYBIT_API_SECRET,
    testnet=(config.MODE == "paper")
)

def get_ohlcv(symbol, interval, limit=200):
    response = session.get_kline(
        category="linear",
        symbol=symbol,
        interval=interval,
        limit=limit
    )
    return response['result']['list']

# Пример вызова
if __name__ == "__main__":
    data = get_ohlcv(config.TRADING_PAIR, config.TIMEFRAME)
    print(data[:2])  # Выводим первые две свечи

Что мы сделали:

  • Подключились к API ByBit.
  • Реализовали функцию для получения исторических данных.
  • Настроили автоматический выбор между тестовой и реальной средой.

Что можно добавить позже:

  • Подключение к WebSocket для получения данных в реальном времени.
  • Обработку ошибок (интернет может «падать», API — отвечать с задержкой).
  • Логирование всех запросов для отладки.

Теперь наш бот может видеть, что происходит на рынке.

ETL-процесс: Загрузка и обработка данных (_02_etl)

Итак, мы уже умеем получать данные с биржи. Но просто «сырые» данные — это ещё не то, с чем удобно работать. Биржи часто выдают данные в неудобном формате, иногда с ошибками или пропусками. Поэтому следующий шаг — привести всё в порядок. Для этого существует классический процесс под названием ETL — Extract, Transform, Load (Извлечение, Преобразование, Загрузка).

Зачем вообще нужен ETL в трейдинге?

  • Чистота данных. Бывает, что биржа присылает некорректные или неполные данные.
  • Удобство. Нам нужно преобразовать данные так, чтобы можно было легко рассчитывать индикаторы.
  • Экономия времени. Зачем каждый раз запрашивать старые данные, если их можно сохранить и использовать повторно?

Что делает модуль _02_etl?

  1. Извлекает данные с биржи (мы уже реализовали это в _01_sources).
  2. Преобразует их в удобный формат (например, в DataFrame с правильными типами данных).
  3. Сохраняет результат локально для дальнейшей работы.

Пример простого ETL-процесса

Создадим файл etl_processor.py:

# _02_etl/etl_processor.py

import pandas as pd
from _01_sources.bybit_client import get_ohlcv  # Импорт функции для получения данных с ByBit
from _00_config import config  # Импорт конфигурационных параметров

def run_etl():
    # Шаг 1: Извлечение данных с биржи (получаем "сырые" данные в виде списка)
    raw_data = get_ohlcv(config.TRADING_PAIR, config.TIMEFRAME)
    
    # Шаг 2: Преобразование данных в DataFrame для удобной работы
    df = pd.DataFrame(raw_data, columns=[
        'timestamp',  # Время открытия свечи (в миллисекундах)
        'open',       # Цена открытия
        'high',       # Максимальная цена
        'low',        # Минимальная цена
        'close',      # Цена закрытия
        'volume',     # Объём торгов
        'turnover'    # Дополнительные данные (оборот)
    ])
    
    # Шаг 3: Преобразуем timestamp в читаемый формат даты и времени
    df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
    
    # Шаг 4: Приводим числовые данные к типу float для корректных вычислений
    df[['open', 'high', 'low', 'close', 'volume']] = df[['open', 'high', 'low', 'close', 'volume']].astype(float)
    
    # Шаг 5: Сортируем данные по времени (на случай, если биржа вернула их неупорядоченными)
    df = df.sort_values('timestamp')
    
    # Шаг 6: Сохраняем итоговый датасет в формате CSV для дальнейшего использования
    df.to_csv(f"{config.DATA_PATH}{config.TRADING_PAIR}_{config.TIMEFRAME}.csv", index=False)
    
    # Сообщаем пользователю о завершении процесса
    print(f"Данные сохранены: {config.DATA_PATH}{config.TRADING_PAIR}_{config.TIMEFRAME}.csv")

# Запускаем процесс ETL, если файл выполняется напрямую
if __name__ == "__main__":
    run_etl()

Что у нас получилось:

  • Данные теперь чистые и готовы к использованию.
  • Не нужно каждый раз обращаться к бирже за историей — всё сохраняется локально.
  • Мы подготовили базу для расчёта индикаторов и тестирования стратегий.

Что можно улучшить в будущем:

  • Добавить автоматическое обновление данных.
  • Сохранять файлы не только в CSV, но и в более эффективном формате, например, Parquet.
  • Проверять целостность данных (нет ли пропущенных свечей).
  • При желании — подключить базу данных.

Теперь у нас есть аккуратный набор данных, с которым бот сможет работать.

В следующей части мы научим бота удобно управлять этими датасетами. Ведь просто сохранить файл — это только половина дела.

Работа с датасетами (_03_datasets)

Ну что ж, данные с биржи мы уже скачали и аккуратно сохранили с помощью ETL. Теперь нужно сделать так, чтобы бот мог легко эти данные использовать.

Представьте, что у вас есть полка с книгами (в нашем случае — это CSV-файлы с данными). Нужно уметь быстро взять нужную «книгу», открыть её на правильной странице и, если что, обновить содержание.

Вот для этого и нужен модуль _03_datasets — он помогает боту «общаться» с нашими сохранёнными данными.

Что должен уметь этот модуль?

  1. Загружать данные из файла, когда это нужно.
  2. Обновлять данные, если появились новые свечи.
  3. Быстро отдавать боту нужную часть информации для расчётов.

Простой пример: Менеджер данных

Чтобы не писать одно и то же каждый раз, я сделал специальный класс — DatasetManager. Он управляет нашими данными.

Вот как это выглядит:

# _03_datasets/dataset_manager.py

import pandas as pd
import os
from _00_config import config
from _02_etl import etl_processor  # Импортируем ETL для обновления данных

class DatasetManager:
    def __init__(self, symbol, timeframe):
        """
        Инициализация менеджера датасетов с указанием торговой пары и таймфрейма.
        """
        self.symbol = symbol
        self.timeframe = timeframe
        self.file_path = f"{config.DATA_PATH}{symbol}_{timeframe}.csv"
        self.data = None  # Здесь будет храниться DataFrame с данными

    def load_data(self):
        """
        Загружаем датасет из CSV-файла.
        Если файл отсутствует — запускаем ETL для его создания.
        """
        if not os.path.exists(self.file_path):
            print("Датасет не найден. Запуск ETL для получения данных...")
            etl_processor.run_etl()

        # Чтение данных из CSV в DataFrame
        self.data = pd.read_csv(self.file_path, parse_dates=['timestamp'])
        print(f"Данные успешно загружены: {self.file_path}")

    def get_latest_data(self, n=50):
        """
        Возвращает последние n свечей из датасета.
        """
        if self.data is None:
            self.load_data()
        return self.data.tail(n)

    def refresh_data(self):
        """
        Обновление датасета (перезапуск ETL).
        """
        print("Обновляем данные...")
        etl_processor.run_etl()
        self.load_data()

# Пример использования
if __name__ == "__main__":
    dm = DatasetManager(config.TRADING_PAIR, config.TIMEFRAME)
    dm.load_data()  # Загружаем данные
    print(dm.get_latest_data(5))  # Показываем последние 5 свечей

Как это работает:

  • Если данных нет — бот сам их загрузит.
  • Если данные есть — бот спокойно их использует.
  • Нужно обновить данные? Пара строк — и всё готово.

Что можно улучшить потом:

  • Добавить поддержку других форматов хранения.
  • Управлять сразу несколькими торговыми парами.
  • Сделать кэширование, чтобы не загружать файлы каждый раз.

Теперь наш бот умеет быстро доставать нужные данные и обновлять их.

Индикаторы для принятия решений (_04_indicators)

Вот мы и подошли к самому интересному — к анализу рынка.

Представьте, что данные — это просто цифры. Но чтобы понять, что происходит на графике, нужен инструмент, который поможет эти цифры «перевести» в сигналы для действий. Здесь на помощь приходят технические индикаторы.

Что такое индикаторы и зачем они боту?

Индикаторы — это специальные формулы, которые помогают понять, куда может пойти рынок. Именно на основе этих расчетов бот решает: пора покупать, продавать или лучше подождать.

Есть куча разных индикаторов, но я всегда советую начинать с простого и проверенного варианта — скользящие средние.

В этой части мы реализуем EMA (Exponential Moving Average) — это усреднённая цена за определённый период, но с акцентом на более свежие данные.

Пример: Как посчитать EMA

Сложного тут ничего нет. Библиотека pandas уже умеет это делать за нас.

Создадим файл ema_calculator.py:

# _04_indicators/ema_calculator.py

import pandas as pd

def calculate_ema(df, period, column='close'):
    """
    Функция для расчета экспоненциальной скользящей средней (EMA).

    :param df: DataFrame с рыночными данными (должен содержать колонку 'close')
    :param period: Период для расчета EMA (например, 9 или 21)
    :param column: Колонка, по которой рассчитывается EMA (по умолчанию 'close')
    :return: DataFrame с добавленной колонкой EMA_{period}
    """
    ema_column_name = f'EMA_{period}'  # Имя новой колонки для хранения значений EMA

    # Используем встроенную функцию pandas для расчета EMA
    df[ema_column_name] = df[column].ewm(span=period, adjust=False).mean()

    return df

# Пример использования
if __name__ == "__main__":
    # Загружаем тестовый датасет (предполагаем, что он уже есть после работы DatasetManager)
    df = pd.read_csv('./_03_datasets/BTCUSDT_15m.csv', parse_dates=['timestamp'])

    # Рассчитываем две EMA с разными периодами (например, для стратегии пересечения EMA)
    df = calculate_ema(df, period=9)
    df = calculate_ema(df, period=21)

    # Выводим последние 5 строк для проверки результата
    print(df[['timestamp', 'close', 'EMA_9', 'EMA_21']].tail(5))

Что мы сделали:

  • Добавили в наш датасет две новые колонки с EMA.
  • Теперь бот видит, как меняется средняя цена за последние 9 и 21 свечу.
  • Это первый шаг к созданию торговых сигналов.

Почему именно EMA?

Потому что это просто, наглядно и эффективно для базовых стратегий. Многие стратегии работают на принципе «пересечения» двух EMA — короткой и длинной.

Что можно добавить позже:

  • Другие индикаторы, например, RSI или Bollinger Bands.
  • Использовать готовые библиотеки типа pandas_ta для быстрого подключения сотен индикаторов.
  • Создать набор универсальных функций для расчёта разных показателей.

Распознавание торговых паттернов (_05_patterns)

Итак, мы уже научили бота получать данные и считать индикаторы. Но как ему понять, когда нажимать «КУПИТЬ», а когда «ПРОДАТЬ»? Ведь сам по себе индикатор — это просто линия на графике. Чтобы бот начал принимать решения, нужно задать ему чёткие правила. Эти правила называются торговые сигналы или паттерны.

Пример: Стратегия пересечения EMA

Реализуем простейший паттерн:

  • Buy (LONG): если EMA с коротким периодом пересекла EMA с длинным периодом снизу вверх.
  • Sell (SHORT): если EMA с коротким периодом пересекла EMA с длинным периодом сверху вниз.

Код с полными комментариями:

# _05_patterns/ema_crossover_strategy.py

import pandas as pd

def detect_ema_crossover_signals(df, short_period=9, long_period=21):
    """
    Функция для обнаружения сигналов на основе пересечения EMA.

    :param df: DataFrame с рассчитанными EMA (должны быть колонки EMA_short_period и EMA_long_period)
    :param short_period: Период короткой EMA
    :param long_period: Период длинной EMA
    :return: DataFrame с добавленной колонкой 'signal'
    """
    # Названия колонок с EMA
    short_ema_col = f'EMA_{short_period}'
    long_ema_col = f'EMA_{long_period}'

    # Инициализация новой колонки 'signal' значениями 0 (нет сигнала)
    df['signal'] = 0

    # Логика пересечения EMA:
    # Если короткая EMA была ниже длинной и стала выше — это сигнал на покупку (1)
    # Если короткая EMA была выше длинной и стала ниже — это сигнал на продажу (-1)

    for i in range(1, len(df)):
        if df[short_ema_col].iloc[i-1] < df[long_ema_col].iloc[i-1] and df[short_ema_col].iloc[i] > df[long_ema_col].iloc[i]:
            df.at[i, 'signal'] = 1   # Buy signal
        elif df[short_ema_col].iloc[i-1] > df[long_ema_col].iloc[i-1] and df[short_ema_col].iloc[i] < df[long_ema_col].iloc[i]:
            df.at[i, 'signal'] = -1  # Sell signal

    return df

# Пример использования
if __name__ == "__main__":
    # Загружаем датасет с рассчитанными EMA (см. предыдущий модуль)
    df = pd.read_csv('./_03_datasets/BTCUSDT_15m.csv', parse_dates=['timestamp'])

    # Предполагаем, что EMA уже добавлены (либо добавить расчёт здесь)
    df = detect_ema_crossover_signals(df, short_period=9, long_period=21)

    # Показываем строки, где есть сигналы
    signals = df[df['signal'] != 0]
    print(signals[['timestamp', 'close', 'EMA_9', 'EMA_21', 'signal']])

Что делает этот код:

  • Добавляет в датасет колонку signal:
    • 1 — сигнал на покупку.
    • 1 — сигнал на продажу.
    • 0 — нейтральная зона (ожидание).
  • Проверяет каждую свечу на факт пересечения EMA.
  • На выходе мы получаем список точек входа и выхода.

Что можно добавить позже:

  • Фильтрацию ложных сигналов (например, по объёму или дополнительным индикаторам).
  • Более сложные паттерны с комбинированием нескольких условий.
  • Поддержку разных стратегий в одном модуле.

Визуализация данных и сигналов (_06_visualization)

Согласитесь, всегда проще понять, как работает стратегия, когда видишь всё на графике, а не просто в таблице с цифрами. Я всегда говорю — прежде чем доверять боту реальные деньги, посмотрите, где он даёт сигналы. Может, он хочет купить на самом пике или продать в самый неудачный момент? Чтобы это проверить, давайте научим бота рисовать графики.

Чем будем рисовать?

Есть много инструментов, но для простоты я использую:

  • matplotlib — стандартная библиотека для графиков.
  • Можно добавить и красивые свечные графики с помощью mplfinance, но пока обойдёмся простыми линиями.

Как показать сигналы на графике

Давайте сделаем так:

  • Нарисуем линию цены.
  • Добавим линии наших EMA.
  • Отметим зелёными стрелочками, где бот хочет купить.
  • Красными — где он хочет продать.

Вот пример кода:

# _06_visualization/plot_signals.py

import pandas as pd
import matplotlib.pyplot as plt

def plot_ema_signals(df, short_period=9, long_period=21):
    """
    Функция для построения графика цены с наложенными EMA и торговыми сигналами.

    :param df: DataFrame с колонками ['timestamp', 'close', 'EMA_xx', 'signal']
    :param short_period: Период короткой EMA
    :param long_period: Период длинной EMA
    """
    plt.figure(figsize=(14, 7))  # Размер графика

    # Строим линию цены (close)
    plt.plot(df['timestamp'], df['close'], label='Close Price', linewidth=1)

    # Строим EMA линии
    plt.plot(df['timestamp'], df[f'EMA_{short_period}'], label=f'EMA {short_period}', linestyle='--')
    plt.plot(df['timestamp'], df[f'EMA_{long_period}'], label=f'EMA {long_period}', linestyle='--')

    # Добавляем точки входа и выхода
    buy_signals = df[df['signal'] == 1]
    sell_signals = df[df['signal'] == -1]

    # Отмечаем buy сигналы зелёными треугольниками
    plt.scatter(buy_signals['timestamp'], buy_signals['close'], marker='^', color='green', label='Buy Signal', s=100)

    # Отмечаем sell сигналы красными перевёрнутыми треугольниками
    plt.scatter(sell_signals['timestamp'], sell_signals['close'], marker='v', color='red', label='Sell Signal', s=100)

    # Настройки графика
    plt.title(f"Торговые сигналы по стратегии EMA Crossover ({short_period}/{long_period})")
    plt.xlabel('Время')
    plt.ylabel('Цена')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()

    # Показываем график
    plt.show()

# Пример использования
if __name__ == "__main__":
    # Загружаем датасет с рассчитанными EMA и сигналами
    df = pd.read_csv('./_03_datasets/BTCUSDT_15m.csv', parse_dates=['timestamp'])

    # Строим график
    plot_ema_signals(df, short_period=9, long_period=21)


Что делает этот код:

  • Строит график цены с наложенными линиями EMA.
  • Отмечает сигналы на покупку и продажу разными маркерами.
  • Помогает визуально проверить, насколько стратегия адекватно «видит» рынок.

Как это выглядит:

  • Синяя линия — цена закрытия.
  • Пунктирные линии — EMA 9 и EMA 21.
  • Зелёные стрелки вверх — сигналы на покупку.
  • Красные стрелки вниз — сигналы на продажу.

Что можно добавить:

  • Визуализацию других индикаторов (например, RSI в отдельном окне).
  • Сохранение графиков в файл.
  • Интерактивные графики с Plotly или Dash.

Управление рисками и капиталом (_07_management)

Если честно, могу признаться — в начале своего пути я недооценивал риск-менеджмент. Казалось, что главное — найти хорошие сигналы, а дальше «рынок сам всё даст». Но рынок быстро учит, что без контроля над рисками можно легко потерять большую часть депозита даже с рабочей стратегией.

Поэтому правило №1: бот должен не только зарабатывать, но и защищать ваш капитал

Вот основные вещи, которые должен уметь любой торговый бот:

  1. Не входить в сделку на весь депозит.
    Например, торговать только на 2-3% от баланса в одной сделке.
  2. Ставить Стоп-Лосс (SL) — это автоматическое ограничение убытка.
    Если цена пошла не туда — бот сам закроет сделку с минимальными потерями.
  3. Ставить Тейк-Профит (TP) — фиксировать прибыль, когда цена достигла цели.
  4. Не открывать слишком много сделок подряд.
  5. Отключаться при больших потерях за день — чтобы не усугублять ситуацию.

Простой пример расчёта размера сделки и уровней SL/TP

Создадим файл risk_manager.py, где бот будет рассчитывать:

  • Сколько купить (или продать).
  • Где поставить защитные ордера.
# _07_management/risk_manager.py

from _00_config import config

def calculate_position_size(balance, price):
    """
    Рассчитываем размер позиции на основе баланса и настроек риска.

    :param balance: Текущий баланс в USDT
    :param price: Текущая цена актива
    :return: Размер позиции в BTC (или другом активе)
    """
    # Ограничение: максимальный процент от баланса в одной сделке
    risk_usdt = balance * (config.MAX_TRADE_SIZE_PERCENT / 100)

    # Конвертируем сумму в количество актива
    position_size = risk_usdt / price

    return round(position_size, 6)  # Округляем до 6 знаков (актуально для крипты)

def calculate_sl_tp(entry_price):
    """
    Рассчитываем уровни стоп-лосса и тейк-профита.

    :param entry_price: Цена входа в сделку
    :return: Кортеж (stop_loss_price, take_profit_price)
    """
    stop_loss = entry_price * (1 - config.STOP_LOSS_PERCENT / 100)
    take_profit = entry_price * (1 + config.TAKE_PROFIT_PERCENT / 100)

    return round(stop_loss, 2), round(take_profit, 2)

# Пример использования
if __name__ == "__main__":
    current_balance = 1000  # Допустим, у нас 1000 USDT
    current_price = 30000   # Цена BTC

    # Расчёт размера позиции
    size = calculate_position_size(current_balance, current_price)
    print(f"Рекомендованный размер позиции: {size} BTC")

    # Расчёт уровней SL и TP
    sl, tp = calculate_sl_tp(current_price)
    print(f"Stop Loss: {sl} USDT, Take Profit: {tp} USDT")

Что делает этот код:

  • Не позволяет боту открыть слишком большую позицию.
  • Автоматически рассчитывает уровни защиты для каждой сделки.
  • Работает по принципу «сначала защита, потом прибыль».

Пример настроек в config.py:

MAX_TRADE_SIZE_PERCENT = 2  # Не более 2% от депозита в одной сделке
STOP_LOSS_PERCENT = 1.5     # Стоп-лосс на 1.5% ниже входа
TAKE_PROFIT_PERCENT = 3.0   # Тейк-профит на 3% выше входа

Что можно добавить позже:

  • Трейлинг-стоп — это «умный» стоп-лосс, который двигается вслед за ценой.
  • Ограничение на количество сделок в день.
  • Автоматическое отключение бота при экстремальных ситуациях.
  • Ведение статистики по рискам.

Проверяем стратегию на истории: Бэктестинг (_08_baktesting)

Прежде чем запускать бота в реальную торговлю (даже на тестовом счёте), нужно ответить на простой вопрос: работала ли эта стратегия в прошлом? Для этого существует бэктестинг — это когда мы «проигрываем» стратегию на исторических данных и смотрим, как бот бы торговал. Это как тренировка перед настоящим боем — лучше ошибиться на истории, чем на реальных деньгах.

Что включает модуль бэктестинга:

  1. Берёт исторические данные (те самые свечи).
  2. Применяет ваши сигналы (например, пересечение EMA).
  3. Считает, где бы бот открыл и закрыл сделки.
  4. Подсчитывает итог: заработал бы бот или ушёл в минус.

Пример простого бэктестера

Создадим файл backtester.py. Здесь всё будет максимально просто:

  • Открываем сделку по сигналу.
  • Закрываем её по стоп-лоссу или тейк-профиту.
  • Считаем результат.
# _08_baktesting/backtester.py

import pandas as pd  # Библиотека для работы с таблицами данных (DataFrame)
from _07_management.risk_manager import calculate_sl_tp  # Импорт функции расчёта уровней стоп-лосса и тейк-профита

def run_backtest(df, initial_balance=1000):
    """
    Простой бэктестинг стратегии на основе сигналов.
    
    :param df: DataFrame с колонками ['timestamp', 'close', 'signal']
    :param initial_balance: Стартовый баланс в USDT
    :return: Список логов всех сделок
    """
    balance = initial_balance  # Устанавливаем начальный баланс
    position = 0               # Переменная для отслеживания позиции (0 = нет позиции, 1 = LONG, -1 = SHORT)
    entry_price = 0            # Цена входа в сделку
    trade_log = []             # Список для хранения логов всех совершённых сделок

    # Проходим по каждой строке DataFrame (по каждой свече)
    for index, row in df.iterrows():
        signal = row['signal']  # Получаем значение сигнала на текущей свече
        price = row['close']    # Получаем цену закрытия свечи

        # --- Открытие позиции ---
        if position == 0 and signal != 0:  # Если нет открытой позиции и есть торговый сигнал
            entry_price = price            # Фиксируем цену входа
            sl, tp = calculate_sl_tp(entry_price)  # Рассчитываем уровни стоп-лосса и тейк-профита
            position = signal              # Открываем позицию (1 для LONG, -1 для SHORT)
            trade_log.append(f"Открыта {'LONG' if signal == 1 else 'SHORT'} по цене {price} | SL: {sl}, TP: {tp}")

        # --- Проверка условий закрытия позиции ---
        if position != 0:  # Если позиция открыта
            if position == 1:  # Если это LONG-позиция
                if price <= sl or price >= tp:  # Если сработал SL или TP
                    result = tp - entry_price if price >= tp else sl - entry_price  # Расчёт прибыли/убытка
                    balance += result  # Корректируем баланс
                    trade_log.append(f"Закрыт LONG по цене {price} | Результат: {result:.2f} USDT")
                    position = 0  # Закрываем позицию

            elif position == -1:  # Если это SHORT-позиция
                if price >= sl or price <= tp:  # Если сработал SL или TP
                    result = entry_price - tp if price <= tp else entry_price -

Что делает этот бэктестер:

  • Имитирует открытие и закрытие сделок по заранее определённым сигналам.
  • Учитывает уровни SL и TP.
  • Ведёт журнал всех операций.
  • Считает финальный баланс после серии сделок.

Ограничения простого бэктеста:

  • Нет учета комиссий биржи..
  • Нет задержек и проскальзывания.
  • Работаем с одной сделкой за раз.

Но для первой проверки этого достаточно,

Что добавить позже:

  • Учёт комиссий.
  • Более сложную аналитику: просадки, винрейт, среднюю прибыль.
  • Красивый график баланса (equity curve).
  • Моделирование реальных условий рынка.

Дашборд на Plotly + Dash (_09_dashboard)

Сейчас я покажу пример минималистичного дашборда с использованием Dash:

  • Отображение текущего баланса.
  • График изменения equity (баланса во времени).
  • Последние сигналы и статус бота.

В реальном проекте ты сможешь легко добавить больше элементов: таблицы, графики, кнопки управления и т.д.

📊 Пример Dash-дашборда с комментариями

# _09_dashboard/dash_dashboard.py

import dash  # Фреймворк для создания веб-дашбордов
from dash import html, dcc  # Компоненты интерфейса
import plotly.graph_objs as go  # Для построения графиков
import pandas as pd  # Работа с данными
from datetime import datetime, timedelta  # Для генерации временных меток
import numpy as np  # Для создания тестовых данных

# --- Генерация тестовых данных для примера ---
dates = [datetime.now() - timedelta(minutes=15*i) for i in range(20)][::-1]  # Последние 20 точек времени
balances = np.cumsum(np.random.randn(20)) + 1000  # Симуляция баланса

df = pd.DataFrame({'time': dates, 'balance': balances})  # Создаем DataFrame

# --- Инициализация Dash-приложения ---
app = dash.Dash(__name__)

# --- Описание интерфейса дашборда ---
app.layout = html.Div(children=[
    html.H1(children='Trading Bot Dashboard', style={'textAlign': 'center'}),  # Заголовок

    html.Div(children=f"Статус бота: Активен", style={'textAlign': 'center', 'fontSize':20}),  # Статус бота
    html.Div(children=f"Текущий баланс: {df['balance'].iloc[-1]:.2f} USDT", style={'textAlign': 'center', 'fontSize':20}),  # Баланс

    # График изменения баланса
    dcc.Graph(
        id='balance-graph',
        figure={
            'data': [
                go.Scatter(
                    x=df['time'],
                    y=df['balance'],
                    mode='lines+markers',
                    name='Equity Curve'
                )
            ],
            'layout': go.Layout(
                title='Динамика Баланса',
                xaxis={'title': 'Время'},
                yaxis={'title': 'Баланс (USDT)'},
                template='plotly_dark'
            )
        }
    )
])

# --- Запуск сервера ---
if __name__ == '__main__':
    app.run_server(debug=True)

Что делает этот код:

  • Создает простой веб-дашборд по адресу http://127.0.0.1:8050.
  • Показывает текущий статус и баланс.
  • Строит интерактивный график баланса (equity curve).
  • Использует стиль plotly_dark для стильной тёмной темы.

Как запустить:

  1. Установить библиотеки:
pip install dash plotly pandas numpy

2. Запустить скрипт:

python _09_dashboard/dash_dashboard.py

3. Перейти в браузере по адресу http://127.0.0.1:8050.

Что можно добавить:

  • Таблицу с последними сделками.
  • График цены + сигналы (можно встроить Plotly-график с ценой).
  • Автоматическое обновление данных (через callbacks).
  • Интеграцию с реальным состоянием бота.

Реализация логики торговли (_10_trading)

Теперь, когда все детали готовы — данные получаем, сигналы считаем, риски контролируем, дашборд есть — пора собрать это в одно целое.

В этом шаге мы напишем главный цикл, где бот будет:

  1. Обновлять данные.
  2. Считать индикаторы.
  3. Искать сигналы.
  4. Если сигнал есть — открывать сделку через API.
  5. И повторять это снова и снова.

Как будет работать бот?

Очень просто:

  • Каждую минуту (или по вашему таймфрейму) он смотрит на рынок.
  • Если видит сигнал на покупку или продажу — отправляет ордер.
  • Если сигналов нет — просто ждет следующего раза.

Пример простой логики бота

# _10_trading/trading_bot.py

import time  # Импортируем модуль для создания задержек между итерациями цикла
from _03_datasets.dataset_manager import DatasetManager  # Импортируем менеджер для работы с датасетами
from _04_indicators.ema_calculator import calculate_ema  # Импорт функции расчёта EMA
from _05_patterns.ema_crossover_strategy import detect_ema_crossover_signals  # Импорт стратегии поиска сигналов
from _07_management.risk_manager import calculate_position_size, calculate_sl_tp  # Импорт функций риск-менеджмента
from _01_sources.bybit_client import session  # Импорт сессии подключения к API ByBit
from _00_config import config  # Импорт конфигурационных параметров проекта

def run_trading_bot():
    """
    Основной цикл работы торгового бота.
    Здесь происходит получение данных, анализ и отправка ордеров.
    """
    balance = 1000  # Устанавливаем стартовый баланс (в реальном боте получаем с биржи)

    # Инициализируем менеджер данных для выбранной торговой пары и таймфрейма
    dm = DatasetManager(config.TRADING_PAIR, config.TIMEFRAME)

    while True:  # Запускаем бесконечный цикл для постоянной работы бота
        dm.refresh_data()  # Обновляем данные (запуск ETL и загрузка актуальных свечей)
        df = dm.get_latest_data(50)  # Получаем последние 50 свечей для анализа

        # Расчитываем две экспоненциальные скользящие средние (EMA 9 и EMA 21)
        df = calculate_ema(df, period=9)
        df = calculate_ema(df, period=21)

        # Определяем торговые сигналы на основе пересечения EMA
        df = detect_ema_crossover_signals(df, short_period=9, long_period=21)

        # Получаем последний сигнал (на текущей свече)
        last_signal = df['signal'].iloc[-1]

        if last_signal != 0:  # Если есть сигнал (1 = Buy, -1 = Sell)
            current_price = df['close'].iloc[-1]  # Получаем текущую цену актива
            position_size = calculate_position_size(balance, current_price)  # Рассчитываем безопасный объем сделки
            sl, tp = calculate_sl_tp(current_price)  # Рассчитываем уровни стоп-лосса и тейк-профита

            # Отправляем рыночный ордер на биржу ByBit через API
            order = session.place_order(
                category="linear",  # Тип рынка (фьючерсы)
                symbol=config.TRADING_PAIR,  # Торговая пара
                side="Buy" if last_signal == 1 else "Sell",  # Направление сделки в зависимости от сигнала
                orderType="Market",  # Рыночный ордер
                qty=position_size,  # Количество актива
                stopLoss=str(sl),  # Уровень стоп-лосса
                takeProfit=str(tp)  # Уровень тейк-профита
            )

            # Выводим информацию об отправленном ордере
            print(f"Отправлен ордер: {order}")
        else:
            # Если сигнала нет, бот просто ждет следующей проверки
            print("Сигнала нет. Ожидание следующего цикла...")

        time.sleep(60)  # Пауза на 60 секунд перед следующей итерацией (зависит от таймфрейма стратегии)

# Точка входа для запуска бота
if __name__ == "__main__":
    run_trading_bot()  # Запуск основного цикла торгового бота

Важно:

  • Это пример для тестнета. Не запускайте на реальных деньгах, пока не проверите всё 100 раз!
  • В реальной торговле нужно:
    • Проверять, нет ли уже открытой позиции.
    • Обрабатывать ошибки API.
    • Добавить логирование.
    • Ограничивать количество сделок.

Финальный запуск: Главный скрипт проекта (main.py)

Итак, мы всё подготовили:

  • Бот умеет анализировать рынок и торговать.
  • Дашборд показывает, что происходит.
  • Все модули разложены по полочкам.

 Структура финального проекта

trading_bot_project/
├── _00_config/
├── _01_sources/
├── _02_etl/
├── _03_datasets/
├── _04_indicators/
├── _05_patterns/
├── _06_visualization/
├── _07_management/
├── _08_baktesting/
├── _09_dashboard/
├── _10_trading/
└── main.py   <-- Главный скрипт запуска бота

Теперь осталось сделать так, чтобы одним запуском всё это включалось и работало. Для этого создадим главный файл — main.py.

Что будет делать main.py?

  • Запустит дашборд в отдельном потоке.
  • Запустит торгового бота.
  • Всё это будет работать параллельно.
# main.py

"""
Главный скрипт для запуска торгового бота на ByBit.
Этот файл объединяет все модули и инициирует работу системы.
"""

import threading  # Для параллельного запуска дашборда и бота
from _09_dashboard.dash_dashboard import app  # Импорт Dash-приложения
from _10_trading.trading_bot import run_trading_bot  # Импорт функции запуска торгового бота

def start_dashboard():
    """
    Запуск веб-дашборда в отдельном потоке.
    """
    app.run_server(debug=False, use_reloader=False)  # Запуск Dash без режима перезагрузки

def start_bot():
    """
    Запуск торгового бота.
    """
    run_trading_bot()

if __name__ == "__main__":
    # Создаем поток для дашборда
    dashboard_thread = threading.Thread(target=start_dashboard)
    dashboard_thread.start()  # Запускаем дашборд

    # Запускаем бота в основном потоке
    start_bot()

Что делает этот скрипт:

  • Запускает дашборд и бота одновременно с помощью многопоточности.
  • Пользователь получает как торговлю, так и визуальный контроль.
  • Это удобная точка входа для всего проекта.

Как запустить бота

  1. Убедись, что установлены все зависимости:
pip install dash plotly pandas numpy pybit

2. Заполни конфигурацию в _00_config/config.py (API-ключи, параметры стратегии).

3. Запусти главный скрипт:

python main.py

4. Открой браузер и перейди по адресу http://127.0.0.1:8050 для мониторинга.

Поздравляю! Теперь у вас есть полноценный торговый бот с удобной архитектурой, дашбордом и возможностью проверки стратегии на истории.

Что мы сделали:

  • Построили модульную архитектуру проекта.
  • Реализовали получение данных, расчёт индикаторов и генерацию сигналов.
  • Добавили риск-менеджмент для защиты капитала.
  • Реализовали бэктестинг для проверки стратегии.
  • Создали дашборд для мониторинга работы бота.
  • Связали всё в единый рабочий процесс.

Что дальше?

Вот несколько идей, как прокачать проект:

  • Добавить новые стратегии и индикаторы.
  • Сделать уведомления в Telegram о сделках.
  • Перевести бота на VPS для круглосуточной работы.
  • Реализовать умные стопы и продвинутый риск-менеджмент.
  • Добавить логирование и систему оповещений при сбоях.
  • Подключить реальные данные и перейти с тестнета на «боевой режим».

Если будут вопросы или захочется доработать какие-то части — всегда рад помочь: Спасибо, что прошли этот путь со мной. Удачи вам и вашему боту 🚀

Хотите разбираться в рынках и зарабатывать на них при любых условиях?

Подписывайтесь на наш Telegram-канал о финансах и Data Science в трейдинге:
– Делаем глубокую аналитику
– Тестируем и разрабатываем торговые стратегии
– Кодим индикаторы и алгоритмы
– Собираем базу знаний для трейдеров

Подписаться
Хотите разбираться в рынках и зарабатывать на них при любых условиях?

Подписывайтесь на наш Telegram-канал о финансах и Data Science в трейдинге:
– Делаем глубокую аналитику
– Тестируем и разрабатываем торговые стратегии
– Кодим индикаторы и алгоритмы
– Собираем базу знаний для трейдеров

Подписаться

Научитесь читать графики всего за 15 минут

Заберите простой мини-гайд для быстрого старта в трейдинге. Идеально для новичков

Подтвердите согласие
Колонка трейдера: как мы пережили трудный рынок в августе
Наши ошибки и защита сделок в трейдинге Привет, на связи Григорий Соколов, CTO Trade2good. Август 2025 года стал одним из самых непростых...
Читать далее
🗝️ Как определять паттерны индикатора market profile
Индикатор профиль рынка (market profile)— полезный инструмент для понимания работы рынка в разные торговые сессии. Этот метод помогает анализировать движение...
Читать далее
🎩 Статистика, нормальное распределение и закон больших чисел
Статистика трейдинга помогает улучшать стратегии, видеть ошибки и точнее оценивать риски. Разберемся, как связана математическая статистика с теорией вероятности, что...
Читать далее