1. Введение: что делает бот
Продолжая проект из первой части статьи, бот стал полноценной системой:
принимает сигналы четырёх типов: 5% long / 5% short / 12% long / 12% short
фильтрует их по дисбалансу ордеров в стакане, капитализации (MCAP), cooldown'у
рассчитывает стопы, тейки, трейлинг при необходимости
открывает сделки на BingX demo через свой API-клиент
управляет пользователями через SQLite и Telegram меню
работает асинхронно и обрабатывает десятки сигналов одновременно
Теперь поехали по ключевой функциональности.
Я решил ввести два типа сделок, зависящих от 5% и 12% сигналов. При 12% движении мы открываем позиции в контр-тренд, при 5% движении открываем позиции в продолжение тренда. Такие проценты были выведены путём довольно долгой ручной торговле. На монетках средней и маленькой капитализации это действительно рабочая стратегия. Вероятно, она основана на принципах работы ММ.
Всю эту стратегию я реализовал в телеграмм бота - с ручными настройками каждой из четырех стратегий, с фильтрами. Бот сейчас находится в тестнете и является на 100% бесплатным. Так что вы можете тестировать его не опасаясь за свои деньги - все сделки будут происходить на демо-счёте. ссылка на бота
База данных: как устроено хранение пользователей
Когда проект вырос из простого парсера сигналов в полноценного торгового бота, появилась необходимость хранить индивидуальные настройки каждого пользователя:
API ключи BingX
плечо / маржу
включённые стратегии (5long, 5short, 12long, 12short)
стопы, тейк-профиты
мкап фильтр
фильтр дисбаланса
трейлинг стопы
коэффициенты трейлинга
cooldown на повторные сделки
Именно поэтому был создан SQLite хранилище, ведь оно является отличным решением как по скорости, так и по функциональности.
Создание базы данных
При каждом запуске бот проверяет наличие таблицы users, а если её нет — создаёт.
Структура:
def setup_db():
conn = sqlite3.connect("users.db")
c = conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
api_key TEXT,
api_secret TEXT,
leverage REAL DEFAULT 20,
margin REAL DEFAULT 10,
# Включение стратегий
enable_5long INTEGER DEFAULT 1,
enable_5short INTEGER DEFAULT 1,
enable_12long INTEGER DEFAULT 1,
enable_12short INTEGER DEFAULT 1,
# Стопы и тейки
stop_5long REAL DEFAULT 5,
stop_5short REAL DEFAULT 5,
stop_12long REAL DEFAULT 12,
stop_12short REAL DEFAULT 12,
tp_5long TEXT DEFAULT "5,10,15",
tp_5short TEXT DEFAULT "5,10,15",
tp_12long TEXT DEFAULT "12,18,25",
tp_12short TEXT DEFAULT "12,18,25",
# Фильтры
mcap_filter INTEGER DEFAULT 0,
imbalance_filter INTEGER DEFAULT 0,
# Трейлинг стоп
trailing INTEGER DEFAULT 0,
trail_rate_5long REAL DEFAULT 0.005,
trail_rate_5short REAL DEFAULT 0.005,
trail_rate_12long REAL DEFAULT 0.01,
trail_rate_12short REAL DEFAULT 0.01,
cooldown INTEGER DEFAULT 0
);
""")
conn.commit()
conn.close()
Фильтр дисбаланса (Orderbook imbalance)
Это очень важная часть проекта, так как она позволяет опираться при открытии сделок на объективные рыночные данные.
Что делает фильтр:
Получает стаканы сразу с bingX
Анализирует объёмы покупателей и продавцов на глубине 1000 тиков.
Вычисляет формулу дисбаланса:
imbalance = (bid_volume-ask_volume)/(bid_volume+ask_volume)
? За что отвечает imbalance?
показывает давление покупателей / продавцов
отсеивает ложные сигналы
помогает торговать по тренду для 5% сигналов
помогает торговать контртренд для 12% сигналов
def get_bingx_orderbook(symbol: str = "BTC-USDT", limit: int = 100):
url = "https://open-api.bingx.com/openApi/swap/v2/quote/depth"
params = {
"symbol": symbol.replace("/", "-"), # на всякий случай
"limit": int(limit)
}
# Сортируем параметры и добавляем timestamp
sorted_keys = sorted(params.keys())
params_str = "&".join([f"{k}={params[k]}" for k in sorted_keys])
timestamp = str(int(time.time() * 1000))
query_string = f"{params_str}×tamp={timestamp}" if params_str else f"timestamp={timestamp}"
# Подпись (даже для публичного эндпоинта — BingX требует подпись)
signature = hmac.new(
SECRETKEY.encode("utf-8"),
query_string.encode("utf-8"),
hashlib.sha256
).hexdigest()
# Финальный URL
final_url = f"{url}?{query_string}&signature={signature}"
headers = {
"X-BX-APIKEY": APIKEY, # можно пустой
}
response = requests.get(final_url, headers=headers, timeout=10)
data = response.json()
if data.get("code") != 0:
print(f"[BingX Depth] Ошибка API: {data}")
return None
bids = [(float(x[0]), float(x[1])) for x in data["data"]["bids"]]
asks = [(float(x[0]), float(x[1])) for x in data["data"]["asks"]]
return {"bids": bids, "asks": asks, "timestamp": data["data"].get("timestamp")}
Фильтр MCAP (капитализация / white-list)
Этот фильтр защищает от торговли низколиквидными шиткоинами, которые:
могут пампиться сидящими группами
могут закрыть позицию одним большим ордером
не имеют реальной рыночной глубины
Фильтр использует файл с кешем о лоу-кап тикерах, которые есть на bingX. Сторонний скрипт постоянно обновляет этот список и перезаписывает сам файл. Сейчас я использую монетки до 150млн капитализации.
Почему это важно:
90% фейковых пампов происходят на токенах с капитализацией < $100M
ликвидность в стакане низкая, так что актив двигается гораздо легче
можно попасть на сквиз 20–50%. Так как торгуем со стопами, то можно не боятся выноса в большой убыток. А вот хороший профит можно забрать с трейлингом без проблем.
Этот фильтр — один из самых важных для реальной торговли.
Как фильтры работают вместе
Сигнал →
Проверка включена ли стратегия →
MCAP фильтр →
Фильтр дисбаланса стакана →
Открытие позиции →
Трейлинг / тейки / стоп
Handler сигналов: сердце бота
Этот блок — самый важный во всём проекте.
В телеграмм группы (куда собственно и идёт пересылка сообщений о пампах) присылаются текстовые уведомления. Таких группы 2: 12% signals и 5% signals. Handler превращает их в полноценные торговые операции на бирже.
Вот формальная задача:
Принять сообщение → извлечь тикер → определить тип сигнала → пройти фильтры → открыть сделку → установить стопы/тейки → отправить уведомление в Telegram.
Именно это делает следующий обработчик.
1. Получение и первичная фильтрация сигнала
@client.on(events.NewMessage(chats=[channel_5long, channel_12short]))
async def handler(event):
raw_text = event.message.message or ""
text = raw_text.strip()
# Фильтруем сигнал — он должен начинаться с ? или ?
if not text.startswith("?") and not text.startswith("?"):
return
Сигналы о пампе или дампе приходят только с эмодзи — остальное можно игнорировать. Это экономит ресурсы и избавляет от ложных запусков.
2. Извлечение тикера
ticker_match = re.search(r'\$([A-Z]{2,12})\b', text)
if not ticker_match:
print("Не найден тикер в сообщении")
return
token = ticker_match.group(1).upper()
symbol = f"{token}-USDT"
Здесь бот вытаскивает $BTC, $XRP, $SOL из текста.
Почему важно делать именно так? сигналы могут содержать текст, числа, описание • но формат $TOKEN стабилен
3. Oпределение канала = определение стратегии
chat = await event.get_chat()
is_5_channel = chat_id == str(channel_5long_id) or "5%" in chat_title.lower()
is_12_channel = chat_id == str(channel_12short_id) or "12%" in chat_title.lower()
4. Определение направления и стратегии
Интересный момент — преобразование сигналов.
5%:
? = long
? = short
12% — наоборот:
? = short
? = long
И код:
side = 'long' if text.startswith("?") else 'short'
if side == 'long' and is_5_channel:
strategy = '5long'
elif side == 'long' and is_12_channel:
strategy = '12long'
side = 'short'
elif side == 'short' and is_12_channel:
strategy = '12short'
side = 'long'
elif side == 'short' and is_5_channel:
strategy = '5short'
5. Получение пользователей из БД
c.execute("SELECT user_id FROM users WHERE api_key IS NOT NULL AND api_secret IS NOT NULL")
Бот открывает сделки для каждого пользователя с API-ключами, то есть работает сразу для всех подписчиков.
6. Проверка включена ли стратегия
if not settings.get(f"enable_{strategy}", 0):
continue
Каждый пользователь вручную включает каждую стратегию с помощью кнопок.
7. Фильтр капитализации (MCAP filter)
if settings.get("mcap_filter", 0):
if token not in ALLOWED_TICKERS:
continue
Что делает фильтр
Отбирает монетки с низкой ликвидностью, которые ходят гораздо легче и не так подвержены влиянию общего рынка
8. Фильтр дисбаланса ORDBOOK IMBALANCE
До открытия сделки мы рассчитываем дисбаланс ордеров, показал это ранее
✔ Для 5% сигналов — фильтр по тренду
if strategy == "5long" and imbalance < 0: continue
if strategy == "5short" and imbalance > 0: continue
✔ Для 12% сигналов — фильтр против тренда
if strategy == "12long" and imbalance > 0: continue
if strategy == "12short" and imbalance < 0: continue
То есть бот смотрит, когда монетка действительно готова идти в нашем направлении и есть поддержка в виде ордеров в стакане.
9. Фильтр COOL-DOWN
Чтобы не открывать одну и ту же сделку много раз:
if now - last_trade_times[user_id][trade_key] < cooldown:
continue
Открытие позиции
После выполнения всех данных фильтров, их расчёта, пришло время открыть позицию. Подтянув данные из базы данных о тейках и стопах расчитываем цены для них и открываем позицию с помощью bingX клиента (упомянул в прошлой статье). Делаем мы это следующим образом:
stop_pct = settings.get(f"stop_{strategy}", 0.05)
sl_level = round(mark_price * (1 - stop_pct) if side == "long" else mark_price * (1 + stop_pct), precision)
order = bx.place_market_order(side, qty, symbol, sl_level)
tp_str = settings.get(f"tp_{strategy}", "5,10,15")
tp_percents = parse_levels(tp_str)
tp_prices = [
mark_price * (1 + p) if side=="long" else mark_price * (1 - p)
for p in tp_percents]
bx.set_multiple_tp(symbol, qty, mark_price, side, tp_prices)
trail_act = settings.get(f"trail_active_{strategy}", 0)
trail_rate = settings.get(f"trail_rate_{strategy}", 0)
if trail_act > 0 and trail_rate > 0:
act_price = mark_price * (1 + trail_act) if side == "long" else mark_price * (1 - trail_act)
bx.set_trailing(symbol, qty, act_price, trail_rate, side)
bot_sender.send_message(
user_id,
f"Deal opened: {strategy}, imbalance={imbalance:.2f}, stop={stop_pct}, tp={tp_percents}"
)
last_trade_times[user_id][trade_key] = now
Что делает handler шаг за шагом
Получение сигнала
→ Проверка формата
→ Извлечение тикера
→ Определение канала (5%/12%)
→ Определение стратегии (5long/12short...)
→ Получение всех пользователей
→ Фильтр "стратегия выключена"
→ Фильтр MCAP
→ Фильтр дисбаланса рынка
→ Фильтр Cooldown
→ Получение биржевой цены
→ Расчёт количества
→ Расчёт стоп-лосса
→ Открытие позиции (MARKET + SL)
→ Выставление тейков
→ Выставление трейлинга
→ Уведомление пользователя
→ Запись времени сделки
Этот обработчик полностью автономен, безопасен и стабилен.
Вывод
Таким образом, мы написали полностью автономную стратегию. Вопрос лишь в том - как каждый пользователь настроит данные стратегии. Важная часть этого бота - комбинирование. Кроме того, если вы уверены, например, в лонговом нарративе на рынке, можно оставить лишь лонговых ботов. Аналогично, если думаете, что рынок будет пдаать в ближайшей перспективе. Этих настроек вполне достаточно для грамотной и полноценной работы по данной торговой стратегии.
Безусловно, сейчас бот находится в тестовом режиме. Обратите внимание что сейчас он в тестнете. Но каждый может его протестировать и подобрать свои настройки. Со временем будут выпущены готовые торговые модели и бот уже будет запущен в mainnet. Так как тут настройки субъективны, то обязательно нужно всё протестировать временем.
Продукт абсолютно бесплатен и будет оставаться таковым - пробуйте и эксперементируйте - @parsertoyosha_bot.