Интеграция Python скрипта с Telegram Bot API для отправки PnL отчета CCXT

Интеграция Python скрипта с Telegram Bot API для отправки PnL отчета CCXT Python & API
Пошаговое руководство по интеграции Python скрипта с Telegram Bot API для автоматической отправки отчетов по нереализованному PnL открытых позиций с биржи через CCXT.
Суть: В данной статье представлен готовый к продакшену асинхронный Python-скрипт, который использует библиотеку ccxt для получения текущих открытых позиций на бирже Bybit (или любой другой CEX) и отправляет структурированный PnL-отчет в Telegram-канал или чат через Telegram Bot API.

Исходный код

Для любого системного трейдера или квант-разработчика критически важно иметь оперативный доступ к метрикам риска своего портфеля. Если вы строите полноценного торгового робота, например, реализуя Пинг-понг стратегию на Bybit V5: Post-Only ордера на Python, регулярный мониторинг PnL становится ключевым элементом контроля просадок.

Для более сложных систем мониторинга, требующих мгновенной реакции на изменение рыночной микроструктуры, часто применяется Парсинг стакана ордеров Binance через WebSockets на Python asyncio. Однако для периодического контроля текущего состояния портфеля (например, раз в час) отлично подходит классический опрос REST API биржи с последующей отправкой отчета в Telegram.

В то время как на CEX мы полагаемся на API биржи, для DEX-сегмента мониторинг требует других подходов, таких как Декодирование транзакций Uniswap V3 Mint/Burn из мемпула на Python. В этой инструкции мы сфокусируемся на централизованных площадках и библиотеке ccxt.

import asyncio
import ccxt.async_support as ccxt
import aiohttp
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

API_KEY = 'YOUR_BYBIT_API_KEY'
API_SECRET = 'YOUR_BYBIT_API_SECRET'
TELEGRAM_TOKEN = 'YOUR_TELEGRAM_BOT_TOKEN'
TELEGRAM_CHAT_ID = 'YOUR_TELEGRAM_CHAT_ID'

async def send_telegram_message(session: aiohttp.ClientSession, text: str):
    url = f'https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage'
    payload = {
        'chat_id': TELEGRAM_CHAT_ID,
        'text': text,
        'parse_mode': 'HTML'
    }
    try:
        async with session.post(url, json=payload) as response:
            if response.status != 200:
                logger.error(f'Ошибка отправки TG: {await response.text()}')
    except Exception as e:
        logger.error(f'Ошибка сети при отправке в TG: {e}')

async def fetch_and_report():
    exchange = ccxt.bybit({
        'apiKey': API_KEY,
        'secret': API_SECRET,
        'options': {
            'defaultType': 'swap',
        }
    })

    async with aiohttp.ClientSession() as session:
        try:
            positions = await exchange.fetch_positions()
            active_positions = [p for p in positions if float(p.get('contracts', 0)) > 0]

            if not active_positions:
                await send_telegram_message(session, '📊 Отчет по позициям:\nНет открытых позиций.')
                return

            report = '📊 Отчет по открытым позициям:\n\n'
            total_unrealized_pnl = 0.0

            for pos in active_positions:
                symbol = pos.get('symbol')
                side = pos.get('side')
                size = float(pos.get('contracts', 0))
                entry_price = float(pos.get('entryPrice', 0))
                mark_price = float(pos.get('markPrice', 0))
                unrealized_pnl = float(pos.get('unrealizedPnl', 0))
                leverage = pos.get('leverage', 'N/A')

                total_unrealized_pnl += unrealized_pnl

                side_emoji = '🟢 LONG' if side.lower() == 'long' else '🔴 SHORT'
                pnl_emoji = '📈' if unrealized_pnl >= 0 else '📉'

                report += (
                    f'{symbol} ({side_emoji} x{leverage})\n'
                    f'• Размер: {size}\n'
                    f'• Вход: {entry_price:.4f} | Марк: {mark_price:.4f}\n'
                    f'• PnL: {pnl_emoji} {unrealized_pnl:+.2f} USDT\n\n'
                )

            pnl_total_emoji = '🟢' if total_unrealized_pnl >= 0 else '🔴'
            report += f'Итоговый нереализованный PnL: {pnl_total_emoji} {total_unrealized_pnl:+.2f} USDT'

            await send_telegram_message(session, report)

        except Exception as e:
            logger.error(f'Ошибка при получении данных: {e}')
            await send_telegram_message(session, f'❌ Ошибка выполнения скрипта: {str(e)}')
        finally:
            await exchange.close()

if __name__ == "__main__":
    asyncio.run(fetch_and_report())

Разбор параметров

  • API_KEY и API_SECRET: Ключи доступа к API биржи (в примере используется Bybit). Для безопасности рекомендуется использовать ключи с правами только на чтение (Read-Only).
  • TELEGRAM_TOKEN: Уникальный токен вашего Telegram-бота, полученный у официального бота @BotFather.
  • TELEGRAM_CHAT_ID: Идентификатор чата или канала, куда бот будет отправлять отчеты. Получить его можно через специализированных ботов, например, @userinfobot.
  • ccxt.bybit: Класс инициализации биржи. Благодаря унификации ccxt, вы можете легко заменить его на ccxt.binance или любой другой поддерживаемый коннектор.
  • fetch_positions(): Унифицированный метод ccxt для получения информации обо всех открытых позициях на фьючерсном аккаунте.

Как запустить

Для запуска скрипта вам понадобятся установленные библиотеки ccxt и aiohttp. Установите их с помощью пакетного менеджера: pip install ccxt aiohttp.

Сохраните код в файл pnl_reporter.py, укажите ваши API-ключи и Telegram-данные, после чего запустите скрипт командой: python pnl_reporter.py.

Для автоматизации регулярной отправки отчетов (например, каждые 30 минут) настройте планировщик задач cron в Linux или Task Scheduler в Windows.

Оцените статью
FinFluct