Главная Веб-разработка Как я пытался допилить криптобота, но всё пошло не по плану

Как я пытался допилить криптобота, но всё пошло не по плану

от admin

В простой криптоконвертер добавил алерты. Столкнулся с трудностями и решил их.

036 открытий915 показов

Изначально всё выглядело просто: криптоконвертер, немного кеша в JSON и WebSocket от Binance для алертов. Но с каждой новой фичей бот начинал вести себя странно. Настройки не сохранялись, алерты спамили, структура данных ломалась, сервер выдавал ошибки, а старый скрипт — не сдавался. В этой истории — реальный опыт разработки и отладки телеграм-бота, в котором всё пошло не так, как планировалось.

Начало истории

Это был просто криптоконвертер, который работал так:

REST API CoinGecko — раз в 10 минут обновлял курс. Кэш в JSON — чтобы не дудосить API. Теперь я решил добавить алерты.

Так как мой мой бот в дальнейшем будет обрастать всё новыми и новыми функциями, я решил разделять их на отдельные файлы.

Зачем разработчику знать SQL, если есть NoSQL? Разбираемся на примерахtproger.ru

Чтобы не приходилось постоянно отправлять запросы, реализовал алерты через Websocket binance.

Сделал сохранение настроек в database.json.

Я реально думал что это будет просто, ошибся:

  • При деплое выдало Sintaxis Error , хотя на компе всё было нормально;
  • Сохранение алертов пропадало после конвертации;
  • Алерты дико спамили.

Когда я запускал бота с компа, никакой синтаксической ошибки не наблюдалось, но после того, как закинул бота на сервер, мне выдало ошибку в строке:

			f"{random.choice(ALERT_TEMPLATES).format( 		

Сначала думал, что дело в кодировке и стоит по дефолту UTF-8 BOM. Но нет. Решил: сервер не видит, что скобка открытая в этой строке закрывается ниже. Разделил код:

			alert_template = random.choice(ALERT_TEMPLATES) formatted_alert = alert_template.format(     crypto=symbol.upper(),     direction=direction,     change=abs(price_change),     advice=random.choice(ADVICE_LIST) ) 		

Ошибка исчезла. Запустил, казалось бы, всё работает. Ставлю галочки на крипте, выхожу в меню, захожу обратно в алерты — галочки на месте. Но стоит мне перейти в конвертер и вернутся обратно, как галок и след простыл.

Как я пытался допилить криптобота, но всё пошло не по плану

Долго копался в коде, пока не понял, что сама структура данных была кривой:

			uuser_data = {     "alerts": ["BTC"],  # ← Это перезаписывалось конвертером!     "conversion": {"crypto": "ETH"} } 		

Datetime ломал JSON — нельзя просто так сериализовать datetime.now().

Разделил струтктуру сохранения, чтобы конвертация не влияла на алерты:

			user_data = {     "alerts": {"cryptos": ["BTC"], "threshold": 5.0},  # Теперь отдельный блок     "conversion": {...}  # Не влияет на алерты } 		

И добавил преобразование datetime в str

			timestamp = v["timestamp"].isoformat()  # Для сохранения datetime.fromisoformat(v["timestamp"])  # Для загрузки 		

Закинул на сервер. При запуске бот не заработал, поэтому я включил режим отладки и мне выдало такое:

			2025-05-07 08:57:50,151 - aiogram.dispatcher - ERROR - Failed to fetch updates - TelegramConflictError: Telegram server says - Conflict: terminated by other getUpdates request; make sure that only one bot instance is running 2025-05-07 08:57:50,151 - aiogram.dispatcher - WARNING - Sleep for 1.774987 seconds and try again... (tryings = 2, bot id = 7617680908) 		

Старый скрпит не хочет уступать без боя. Это конфликт ботов.

Читать также:
Chrome DevTools: основные инструменты и полезные функции

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

Курсы по Big Data, включая онлайн-обучение для аналитиков больших данныхtproger.ru

sudo pkill -f “python.*bot.py” && sleep 2

kill -9 <PID>

pkill -f bot.py

Но старый бот так и не умирает. А через некоторое время сам по себе перестает работать. Я пока не понял эту аномалию. Возможно, после команды sudo systemctl reload надо просто попить чаю и дать время сервису нормально перезагрузиться.

Хорошо, бота мы убили. Нового запустили. Все кнопки работают. Включили алерты на ETH и стали ждать…

И тут началось…

Как я пытался допилить криптобота, но всё пошло не по плану

Когда Эфириум подскачил на 7%, бот сошёл с ума, начал материться и спамить при малейшем сдвиге курса.

Было решено игнорировать мелкие колебания курса, установить минимальный порог реагирования 5% и высылать алерт не чаще чем 5 минут от предыдущего:

			def _need_alert(self, crypto: str, change: float) -> bool:     now = time.time()     last_alert = self.last_alerts.get(crypto, 0)     return (         abs(change) > self.threshold  # Порог (например, 5%)         and (now - last_alert) > 300  # 5 минут между алертами     ) 		

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

Со скриптом можете ознакомится здесь.

P.S. Пишите комментарии, предлагайте свои идеи. Деконструктивная и агрессивная критика приветствуется!))

Похожие статьи