Как создать торгового бота для 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: запрашивать цены, получать информацию о счёте и следить за рынком в реальном времени.
Какие данные нужны торговому боту?
- Исторические данные — так называемые свечи (OHLCV). Они нужны для расчёта индикаторов и бэктестинга.
- Текущие цены — чтобы понять, когда входить или выходить из сделки.
- Данные о вашем балансе и позициях — чтобы контролировать риски.
- Статус ордеров — чтобы знать, исполнились ли ваши сделки.
Как получать данные с 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?
- Извлекает данные с биржи (мы уже реализовали это в _01_sources).
- Преобразует их в удобный формат (например, в DataFrame с правильными типами данных).
- Сохраняет результат локально для дальнейшей работы.
Пример простого 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 — он помогает боту «общаться» с нашими сохранёнными данными.
Что должен уметь этот модуль?
- Загружать данные из файла, когда это нужно.
- Обновлять данные, если появились новые свечи.
- Быстро отдавать боту нужную часть информации для расчётов.
Простой пример: Менеджер данных
Чтобы не писать одно и то же каждый раз, я сделал специальный класс — 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: бот должен не только зарабатывать, но и защищать ваш капитал
Вот основные вещи, которые должен уметь любой торговый бот:
- Не входить в сделку на весь депозит.
Например, торговать только на 2-3% от баланса в одной сделке. - Ставить Стоп-Лосс (SL) — это автоматическое ограничение убытка.
Если цена пошла не туда — бот сам закроет сделку с минимальными потерями. - Ставить Тейк-Профит (TP) — фиксировать прибыль, когда цена достигла цели.
- Не открывать слишком много сделок подряд.
- Отключаться при больших потерях за день — чтобы не усугублять ситуацию.
Простой пример расчёта размера сделки и уровней 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)
Прежде чем запускать бота в реальную торговлю (даже на тестовом счёте), нужно ответить на простой вопрос: работала ли эта стратегия в прошлом? Для этого существует бэктестинг — это когда мы «проигрываем» стратегию на исторических данных и смотрим, как бот бы торговал. Это как тренировка перед настоящим боем — лучше ошибиться на истории, чем на реальных деньгах.
Что включает модуль бэктестинга:
- Берёт исторические данные (те самые свечи).
- Применяет ваши сигналы (например, пересечение EMA).
- Считает, где бы бот открыл и закрыл сделки.
- Подсчитывает итог: заработал бы бот или ушёл в минус.
Пример простого бэктестера
Создадим файл 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 для стильной тёмной темы.
Как запустить:
- Установить библиотеки:
pip install dash plotly pandas numpy
2. Запустить скрипт:
python _09_dashboard/dash_dashboard.py
3. Перейти в браузере по адресу http://127.0.0.1:8050.

Что можно добавить:
- Таблицу с последними сделками.
- График цены + сигналы (можно встроить Plotly-график с ценой).
- Автоматическое обновление данных (через callbacks).
- Интеграцию с реальным состоянием бота.
Реализация логики торговли (_10_trading)
Теперь, когда все детали готовы — данные получаем, сигналы считаем, риски контролируем, дашборд есть — пора собрать это в одно целое.
В этом шаге мы напишем главный цикл, где бот будет:
- Обновлять данные.
- Считать индикаторы.
- Искать сигналы.
- Если сигнал есть — открывать сделку через API.
- И повторять это снова и снова.
Как будет работать бот?
Очень просто:
- Каждую минуту (или по вашему таймфрейму) он смотрит на рынок.
- Если видит сигнал на покупку или продажу — отправляет ордер.
- Если сигналов нет — просто ждет следующего раза.
Пример простой логики бота
# _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()
Что делает этот скрипт:
- Запускает дашборд и бота одновременно с помощью многопоточности.
- Пользователь получает как торговлю, так и визуальный контроль.
- Это удобная точка входа для всего проекта.
Как запустить бота
- Убедись, что установлены все зависимости:
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 для круглосуточной работы.
- Реализовать умные стопы и продвинутый риск-менеджмент.
- Добавить логирование и систему оповещений при сбоях.
- Подключить реальные данные и перейти с тестнета на «боевой режим».
Если будут вопросы или захочется доработать какие-то части — всегда рад помочь: Спасибо, что прошли этот путь со мной. Удачи вам и вашему боту 🚀