Как превратить "черный ящик" в кристально понятный инструмент.
Прежде чем мы начнем, давайте быстро разберемся с основными понятиями, чтобы говорить на одном языке.
Ваш бот работает в Docker на сервере. Чтобы понять, что с ним происходит, вам нужно:
docker logs trading_bot и пытаться найти нужную информацию в потоке текста.Это стресс, неэффективность и постоянное чувство "а вдруг что-то не так?". 🤷♂️
У вас есть одна ссылка, которая открывает в браузере живую приборную панель. На ней в реальном времени видно:
Вы спокойны, информированы и можете принимать решения, основанные на данных, а не на догадках. ✨📈
Представьте: пятница, вечер. Вы запускаете обновленную версию вашего трейдинг-бота и уходите на выходные. Он должен торговать на низко-волатильном рынке, сделок может быть немного.
Проходит три часа. Вам приходит мысль: "А он вообще работает?". Вы открываете логи — там тишина. Последняя запись — "Bot started successfully".
Сердце начинает биться чаще. Что это значит? Он ждет идеального момента для входа? Или он упал, но Docker его автоматически перезапустил, и поэтому в логах чисто? А может, он подключился к бирже, но из-за ошибки в коде не может получить данные о ценах? Или, что хуже всего, он открыл убыточную сделку и сейчас медленно сливает депозит, а система логирования ошибок сломалась?
Вы не знаете. И это неведение — худшее. Вы тратите вечер субботы, подключаясь к серверу, пытаясь понять, что происходит, вместо того чтобы отдыхать. Вам нужен не просто лог-файл, вам нужен живой пульт управления.
Вот примеры панелей, которые мы создадим. Это наша цель.
Мы расширим наш docker-compose.yml из Урока 4, добавив два новых сервиса: prometheus и grafana.
Создайте файл prometheus.yml рядом с docker-compose.yml. Он нужен, чтобы сказать Prometheus, куда ходить за метриками.
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'trading-bot'
static_configs:
- targets: ['host.docker.internal:5001']
Заметка: host.docker.internal — это специальное имя, которое позволяет контейнеру Docker "достучаться" до сервиса, запущенного на основной машине (хосте). Мы запустим нашего бота на порту 5001.
version: '3.8'
services:
nginx:
# ... ваша конфигурация nginx из прошлых уроков
# ... порты 80 и 443 должны быть открыты
trading_bot:
# ... ваша конфигурация бота из прошлых уроков
# Убедитесь, что порт 5001 сопоставлен, если вы хотите обращаться к нему напрямую
# Но для Prometheus это не обязательно, он использует host.docker.internal
prometheus:
image: prom/prometheus:v2.47.0
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
ports:
- "9090:9090"
restart: unless-stopped
grafana:
image: grafana/grafana-oss:10.1.5
container_name: grafana
volumes:
- grafana_data:/var/lib/grafana
ports:
- "3000:3000"
restart: unless-stopped
volumes:
prometheus_data:
grafana_data:
Теперь, после запуска docker-compose up -d, у вас будут работать Grafana (http://localhost:3000) и Prometheus (http://localhost:9090).
Чтобы Prometheus мог что-то собирать, наш бот должен научиться "рассказывать" о себе в понятном для него формате. Для этого есть три основных типа метрик:
trades_total (общее количество сделок), errors_total (общее количество ошибок).pnl_usd (текущий PnL в USD), open_positions_count (количество открытых позиций).api_request_latency_seconds (время ответа API биржи).Теперь научим нашего бота отдавать метрики. Мы будем использовать Flask для создания простого веб-сервера, который на запрос /metrics будет отдавать все наши показатели.
Сначала установите библиотеку: pip install prometheus_client Flask
Вот полный пример кода. Вы можете интегрировать его в своего бота.
from flask import Flask, Response
from prometheus_client import Counter, Gauge, Histogram, generate_latest
import time
import random
import threading
# 1. Создаем Flask-приложение
app = Flask(__name__)
# 2. Декларируем наши метрики. Это лучше делать на глобальном уровне.
# Counter для событий, которые только накапливаются
TRADES_TOTAL = Counter('trades_total', 'Total number of trades executed', ['symbol', 'side'])
ERRORS_TOTAL = Counter('errors_total', 'Total number of critical errors', ['error_type'])
# Gauge для значений, которые могут расти и падать
PNL_USD = Gauge('pnl_usd', 'Current Profit and Loss in USD')
OPEN_POSITIONS = Gauge('open_positions', 'Number of currently open positions')
# Histogram для измерения времени отклика
REQUEST_LATENCY = Histogram('api_request_latency_seconds', 'API Request Latency', ['exchange'])
# 3. Создаем endpoint /metrics, который будет отдавать данные для Prometheus
@app.route('/metrics')
def metrics():
return Response(generate_latest(), mimetype='text/plain; version=0.0.4; charset=utf-8')
# 4. Симуляция работы бота в отдельном потоке
def run_bot_simulation():
"""Эта функция симулирует работу вашего бота"""
pnl = 0.0
while True:
# Симуляция сделки
if random.random() > 0.8:
pnl += random.uniform(-10.0, 15.0)
PNL_USD.set(pnl) # Устанавливаем новое значение PnL
TRADES_TOTAL.labels(symbol='BTC/USDT', side='buy').inc() # Увеличиваем счетчик сделок
print(f"New trade! Current PnL: {pnl:.2f}")
# Симуляция измерения времени ответа API
with REQUEST_LATENCY.labels(exchange='binance').time():
# Ваш реальный код запроса к API биржи будет здесь
time.sleep(random.uniform(0.05, 0.2))
# Симуляция ошибки
if random.random() > 0.98:
ERRORS_TOTAL.labels(error_type='api_connection').inc()
print("API connection error occurred!")
# Обновляем Gauge с количеством открытых позиций
OPEN_POSITIONS.set(random.randint(0, 5))
time.sleep(2)
if __name__ == '__main__':
# Запускаем симуляцию в фоновом потоке
bot_thread = threading.Thread(target=run_bot_simulation)
bot_thread.daemon = True
bot_thread.start()
# Запускаем веб-сервер для отдачи метрик на порту 5001
app.run(host='0.0.0.0', port=5001)
Запустив этот код, вы можете открыть в браузере http://localhost:5001/metrics и увидеть текстовое представление всех ваших метрик.
Давайте создадим один график вручную, чтобы понять процесс.
http://localhost:3000). Логин/пароль по умолчанию: admin/admin.http://prometheus:9090. Нажмите "Save & Test". Должна появиться зеленая галочка.rate(trades_total[5m])
Что это значит? rate() — это функция, которая вычисляет скорость роста счетчика в секунду. trades_total[5m] — мы берем данные метрики trades_total за последние 5 минут. Итого: "покажи мне среднее количество сделок в секунду за последние 5 минут".
Создавать сложные дашборды вручную — долго. Гораздо проще импортировать готовый. Мы подготовили для вас JSON-файл, который содержит все панели, описанные в Части 1.
(Здесь в реальном курсе была бы ссылка на скачивание файла dashboard.json)
Как его импортировать:
Вуаля! Перед вами полностью готовая приборная панель, которая уже начала показывать живые данные от вашего бота.
Мониторинг — это хорошо, но мы не можем смотреть в дашборд 24/7. Давайте настроим оповещение, если бот перестал торговать.
Задача: Отправить сообщение в Telegram, если за последний час не было ни одной сделки.
$B < 1.$B < 1 было истинно на протяжении всего последнего часа, то сработать".Теперь, если ваш бот "заснет" и не будет совершать сделок в течение часа, Grafana заметит это и пришлет вам гневное сообщение в Telegram. Вы снова у руля!
Поздравляем! Ваш бот теперь под полным контролем, он прозрачен и предсказуем. Вы видите его пульс в реальном времени и получите сигнал, если что-то пойдет не так.
Но... что, если сам сервер "ляжет"? Отключение электричества, сбой диска, ошибка у хостинг-провайдера.
Все ваши данные Prometheus, все ваши красивые дашборды и настройки алертов в Grafana — всё это хранится на диске этого самого сервера. В один миг всё может исчезнуть.
В следующем уроке мы решим эту фундаментальную проблему, настроив автоматические и надежные бэкапы в облачное хранилище Backblaze. До встречи в Уроке 7!
[tokens: in=399 out=4520 thinking=2829 | cost=$0.074]Хочешь больше? Полный курс AI Agents включает Production-модуль + 27 других уроков
AI Agents $199 →