Цель этой статьи — максимально подробно и практично разобрать реальный Python‑проект автоматического трейдинга. Это не концепт, а рабочий бот, который: непрерывно анализирует рынок Binance Futures, ищет сигналы по открытому интересу (Open Interest), применяет набор защитных фильтров, работает с множеством пользователей одновременно, управляется через Telegram‑интерфейс и при необходимости открывает реальные сделки через API биржи BingX.
Далее я последовательно разберу всю логику и все функции основного файла main.py, объясняя, как и зачем они реализованы именно так.
Общая архитектура проекта
Архитектурно проект разделён на два слоя:
Управляющий слой (
main.py) — получение данных, расчёт сигналов, фильтры, Telegram‑интерфейс, логика пользователей и принятие решений.Исполнительный слой (
bingx_client.py) — работа с торговым API BingX: подпись запросов, установка плеча, открытие ордеров, трейлинг.
Ключевая идея — вся торговая логика должна быть независима от конкретной биржи. В main.py мы оперируем функции вроде place_market_order(), а не HTTP‑запросами. Клиент для биржи я написал самостоятельно и использую его во всех своих проектах и статьях. Ссылка на файла проекта, включая этот клиент: github
Хранение пользователей и состояния
Бот поддерживает одновременную работу с большим количеством пользователей. Для этого используется простая, но надёжная модель хранения состояния в JSON:
USERS_FILE = Path("users.json") def load_users(): if USERS_FILE.exists(): return json.loads(USERS_FILE.read_text()) return {} def save_users(users): USERS_FILE.write_text(json.dumps(users, indent=4)) users = load_users()
Каждый пользователь — это словарь с настройками торговли, фильтрами, чёрным списком и служебными метаданными. Такой подход позволяет легко сериализовать состояние, не зависеть от БД, безопасно переживать перезапуск процесса.
Вспомогательные функции и утилиты
Процентные изменения
def pct(now, past): if past == 0: return 0.0 return (now - past) / past * 100.0
Эта функция используется повсеместно: и для цены, и для OI. Явное вынесение её в утилиту снижает вероятность логических ошибок и делает расчёты единообразными.
Отправка сообщений в Telegram
def send_alert(chat_id, text): try: bot.send_message( chat_id=chat_id, text=text, parse_mode="HTML" ) except Exception as e: print(f"Telegram error {chat_id}: {e}")
Работа с Binance Futures API
Данные рынка получаются исключительно через публичные эндпоинты Binance Futures:
def binance_get(endpoint, params=None): url = BINANCE_FAPI_URL + endpoint r = requests.get(url, params=params, timeout=REQUEST_TIMEOUT) r.raise_for_status() return r.json()
Поверх неё реализованы функции, работающие с апи. Например:
def get_symbols(): data = binance_get("/fapi/v1/exchangeInfo") return [ s["symbol"] for s in data["symbols"] if s["contractType"] == "PERPETUAL" and s["quoteAsset"] == "USDT" and s["status"] == "TRADING" ]
Здесь мы получаем все фьючерсные символы, которые торгуются к валюте USDT. Это позволят перебирать только релевантные активы.
Логика OI‑сигнала
Основная аналитика сосредоточена в функции check_symbol.
oi_4h = get_oi_hist(symbol, 48) oi_24h = get_oi_hist(symbol, 288)
48 и 288 точек соответствуют 4 и 24 часам при таймфрейме 5 минут. Это делает расчёт полностью детерминированным.
Далее извлекаются крайние значения и рассчитываются проценты:
oi_now = float(oi_4h[-1]["sumOpenInterestValue"]) oi_4h_ago = float(oi_4h[0]["sumOpenInterestValue"]) oi_growth_4h = pct(oi_now, oi_4h_ago)
Сигнал формируется не только по росту OI, но и по соотношению с ценой с помощью коэффициента PRICE_OI_RATIO = 0,5:
signal_4h = ( oi_growth_4h >= OI_4H_THRESHOLD and price_growth_4h <= oi_growth_4h * PRICE_OI_RATIO )
Это принципиально: стратегия ищет накопление, а не импульс.
Анти‑спам и защита от переоткрытия
Каждый пользователь имеет словарь last_signal_time:
last_signals = user_data.get("last_signal_time", {}) if symbol in last_signals: if datetime.utcnow() - datetime.fromisoformat(last_signals[symbol]) < timedelta(hours=SIGNAL_COOLDOWN_HOURS): continue
Этот механизм предотвращает повторные входы по одному инструменту и делает автотрейдинг более контролируемым.
Фильтры: объём и ликвидность
Минимальный OI
if oi_now < MIN_OI_USDT: return
Этот фильтр встроен в код. В целом, его основная цель - отсеять неверные данные и совсем низколиквидные монетки, которые иногда могут затесаться на binance.
Фильтр объёма
def check_volume_filter(symbol, multiplier): klines = get_klines(symbol, Vol_period) volumes = [float(k[5]) for k in klines[:-1]] avg_volume = sum(volumes) / len(volumes) current_volume = float(klines[-1][5]) return current_volume >= avg_volume * multiplier
Этот фильтр позволяет торговать только в моменты повышенной активности рынка. На практике при тестировании он действительно кратко уменьшил количество сделок и повысил винрейт в любых рыночных условиях. Его отключение уводило стратегию в убыток, так что такой фильтр отлично себя показывает в данной ТС. Каждый пользователь может поставить персональный мультипликатор (multiplier) в настройках.
Чёрный список (blacklist)
Каждый пользователь может управлять списком запрещённых инструментов с помощью команд /blacklist_add и /blacklist_remove, а также смотреть символы в /blacklist_show.
def blacklist_add(update: Update, context): chat_id = str(update.effective_chat.id) if not context.args: update.message.reply_text("Использование: /blacklist_add BTCUSDT") return symbol = context.args[0].upper() users[chat_id].setdefault("blacklist", []) if symbol not in users[chat_id]["blacklist"]: users[chat_id]["blacklist"].append(symbol) save_users(users) update.message.reply_text(f"⛔ {symbol} добавлен в чёрный список") def blacklist_remove(update: Update, context): chat_id = str(update.effective_chat.id) if not context.args: update.message.reply_text("Использование: /blacklist_remove BTCUSDT") return symbol = context.args[0].upper() if symbol in users[chat_id].get("blacklist", []): users[chat_id]["blacklist"].remove(symbol) save_users(users) update.message.reply_text(f"✅ {symbol} удалён из чёрного списка") def blacklist_show(update: Update, context): chat_id = str(update.effective_chat.id) blacklist = users.get(chat_id, {}).get("blacklist", []) if not blacklist: update.message.reply_text("📭 Чёрный список пуст") return text = "<b>⛔ Чёрный список:</b>\n\n" text += "\n".join(f"• {s}" for s in sorted(blacklist)) update.message.reply_text(text, parse_mode="HTML")
Проверка перед сделкой:
if symbol in user_data.get("blacklist", []): continue
Это важнейший элемент риск‑менеджмента при реальной торговле.
Переход от сигнала к сделке
qty = (margin_usdt * leverage) / price_now stop_price = price_now * (1 - stop_loss_pct / 100) tp_price = price_now * (1 + take_profit_pct / 100)
Все параметры сделки вычисляются исходя из настроек каждого юзера
Открытие сделки делаем с помощью функции bingx_client. Все сделки будут в лонг, так как OI лонг сигналы работают лучше шортовых. Так что пераметр long передаём явно, остальные вычисляли ранее (s - символ на бирже bingx):
resp = bx.place_market_order('long', qty, s, stop_price, tp_price)
Telegram‑интерфейс и кнопки
Меню настроек реализовано через inline‑кнопки:
keyboard = [ [InlineKeyboardButton("Торговля", callback_data='toggle_trading')], [InlineKeyboardButton("Плечо", callback_data='set_leverage')] ]
Каждая кнопка обрабатывается единым обработчиком:
def button_handler(update, context): data = query.data if data == 'toggle_trading': users[chat_id]['trading_enabled'] = not users[chat_id]['trading_enabled']
Это позволяет легко работать с масштабирование интерфейса, логика понятная и простая. Также такая логика не перегружает код.
Универсальная обработка пользовательского ввода
def set_value(update, context, key, type_func=str): value = type_func(update.message.text.strip()) users[chat_id][key] = value save_users(users)
Благодаря этому добавление нового параметра требует минимального количества кода.
Основной цикл работы
for symbol in symbols: check_symbol(symbol) time.sleep(0.15)
Функция check_symbols выполняет абсолютно всю логику - проверка OI, применение фильтров, проверка на blacklist и открытие сделок при наличии сигнала. Таким образом, мы перебираем все binance символы и открываем сделки на бирже с помощью готового клиента. Я выбрал биржей для открытия bingX из-за комиссий, тем более что binance в России сейчас имеет проблемы.
Заключение
Надеюсь, что у меня получилось объяснить основную логику кода и функций. Всё что вам нужно, чтобы запустить этот проект - получить токен в @botfather и вставить его в переменную BOT_TOKEN. Напоминаю, что весь код я выложил на github.
Данный бот показывает среднюю прибыль в течение 2 недель около 2% в среднем. Были как удачные дни, так и не очень удачные, в которые амплитуда депозита могла быть и более 5% в обе стороны. Так что используйте бота осторожно. Он имеет встроенную функцию работы с testnet, обязательно тестируйте свои настройки сначала там! Я имею следующие настройки сейчас:

Этот проект показывает, как выглядит реальный автоматический трейдинг на Python: с фильтрами, защитой, пользовательским управлением и строгим разделением логики. Именно такой уровень детализации позволяет использовать автотрейдинг качественно.
Всем успехов! Надеюсь что этот продукт будет способен в итоге принести реальную прибыль и вам.
