Расчет Taker Buy/Sell Ratio с Binance AggTrades на Python

Расчет Taker Buy/Sell Ratio с Binance AggTrades на Python Python & API
Подробное руководство по созданию Python-скрипта для расчета метрики Taker Buy/Sell Ratio на основе тиковых данных (AggTrades) с Binance WebSocket API. Включает исходный код и пошаговую инструкцию.
Суть: Мы разработаем асинхронный Python-скрипт, который подключается к WebSocket API Binance, получает поток агрегированных тиковых сделок (AggTrades) и в реальном времени рассчитывает метрику Taker Buy/Sell Ratio, используя флаг ‘m’ (isBuyerMaker) для определения направления taker-ордера.

Метрика Taker Buy/Sell Ratio является одним из ключевых индикаторов активности участников рынка, позволяя оценить доминирование покупателей или продавцов, агрессивно исполняющих свои ордера по рыночной цене. В отличие от обычного объема, который включает как лимитные, так и рыночные ордера, Taker Buy/Sell Ratio фокусируется исключительно на ‘taker’ активности, то есть на тех участниках, которые ‘забирают’ ликвидность с рынка. Понимание этой метрики критически важно для квантов и трейдеров, стремящихся получить преимущество в высокочастотной торговле и анализе рыночной микроструктуры.

В этой статье мы покажем, как создать надежный Python-скрипт для сбора данных AggTrades с Binance и расчета Taker Buy/Sell Ratio в реальном времени. Мы будем использовать асинхронное программирование для эффективной обработки потоковых данных, что является стандартом в работе с биржевыми API. Если вы интересуетесь другими продвинутыми торговыми стратегиями, рекомендуем ознакомиться с нашей статьей Автоматическое Дельта-Хеджирование на Deribit с Python: Гайд для Квантов.

Исходный код

Представленный ниже скрипт подключается к WebSocket API Binance для получения агрегированных тиковых сделок (AggTrades) по указанному символу. Он использует класс TakerRatioCalculator для обработки входящих сообщений, определения типа taker-ордера (покупка или продажа) и расчета Taker Buy/Sell Ratio в скользящем окне. Результаты выводятся в консоль, предоставляя актуальное представление о рыночной агрессии.


import asyncio
import websockets
import json
import pandas as pd
from collections import deque

class TakerRatioCalculator:
    def __init__(self, symbol: str, window_size: int = 100):
        self.symbol = symbol.upper()
        self.window_size = window_size
        self.trades_buffer = deque(maxlen=window_size)
        self.taker_buy_volume = 0.0
        self.taker_sell_volume = 0.0
        print(f"[INFO] Инициализирован калькулятор для {self.symbol} с окном {self.window_size} сделок.")

    def _process_trade(self, trade_data: dict):
        """
        Обрабатывает одну агрегированную сделку, определяя ее как Taker Buy или Taker Sell.
        'm': true - buyer is maker, means seller is taker (Taker Sell)
        'm': false - seller is maker, means buyer is taker (Taker Buy)
        """
        quantity = float(trade_data['q']) # Количество
        price = float(trade_data['p'])   # Цена
        is_buyer_maker = trade_data['m'] # True, если покупатель - мейкер
        trade_volume = quantity * price

        if is_buyer_maker: # Покупатель - мейкер -> продавец - тейкер -> Taker Sell
            self.taker_sell_volume += trade_volume
            return 'sell', trade_volume
        else: # Продавец - мейкер -> покупатель - тейкер -> Taker Buy
            self.taker_buy_volume += trade_volume
            return 'buy', trade_volume

    def _update_buffer(self, trade_type: str, trade_volume: float):
        """
        Добавляет новую сделку в буфер и удаляет старейшую, если буфер полон.
        Обновляет суммарные объемы Taker Buy/Sell.
        """
        if len(self.trades_buffer) == self.window_size:
            old_trade_type, old_trade_volume = self.trades_buffer.popleft()
            if old_trade_type == 'buy':
                self.taker_buy_volume -= old_trade_volume
            else:
                self.taker_sell_volume -= old_trade_volume
        
        self.trades_buffer.append((trade_type, trade_volume))

    def _calculate_ratio(self) -> float:
        """
        Рассчитывает Taker Buy/Sell Ratio.
        Ratio = Taker Buy Volume / (Taker Buy Volume + Taker Sell Volume)
        """
        total_taker_volume = self.taker_buy_volume + self.taker_sell_volume
        if total_taker_volume == 0:
            return 0.5 # Нейтральное значение, если нет объема
        return self.taker_buy_volume / total_taker_volume

    async def _handle_message(self, message: str):
        """
        Обрабатывает входящее сообщение WebSocket.
        """
        data = json.loads(message)
        if data['e'] == 'aggTrade': # Проверяем, что это агрегированная сделка
            trade_type, trade_volume = self._process_trade(data)
            self._update_buffer(trade_type, trade_volume)
            
            if len(self.trades_buffer) == self.window_size: # Рассчитываем только когда буфер заполнен
                ratio = self._calculate_ratio()
                print(f"[{pd.to_datetime(data['E'], unit='ms')}] {self.symbol} Taker Buy/Sell Ratio: {ratio:.4f} (Buy: {self.taker_buy_volume:.2f}, Sell: {self.taker_sell_volume:.2f})")

async def main():
    symbol = "BTCUSDT"
    window_size = 200 # Количество последних сделок для расчета соотношения
    calculator = TakerRatioCalculator(symbol, window_size)

    uri = f"wss://stream.binance.com:9443/ws/{symbol.lower()}@aggTrade"
    print(f"[INFO] Подключение к WebSocket: {uri}")

    async with websockets.connect(uri) as websocket:
        print("[INFO] Подключено. Ожидание данных...")
        while True:
            try:
                message = await websocket.recv()
                await calculator._handle_message(message)
            except websockets.exceptions.ConnectionClosedOK:
                print("[INFO] Соединение закрыто.")
                break
            except Exception as e:
                print(f"[ERROR] Произошла ошибка: {e}")
                await asyncio.sleep(1) # Пауза перед повторной попыткой

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

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

  • symbol: Строка, представляющая торговую пару, для которой будет рассчитываться метрика. Например, "BTCUSDT" или "ETHUSDT". Регистр не имеет значения, так как скрипт преобразует его в верхний регистр.
  • window_size: Целое число, определяющее размер скользящего окна для расчета Taker Buy/Sell Ratio. Это количество последних агрегированных сделок, которые будут учитываться при расчете. Большее значение window_size сглаживает метрику, меньшее делает ее более чувствительной к краткосрочным изменениям.

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

Для запуска этого скрипта вам потребуется установленный Python 3.7+ и несколько библиотек. Если вы сталкиваетесь с проблемами при работе с API, возможно, вам будет полезна статья Обход Cloudflare на DexScreener: Скрипт на Python и Selenium, хотя для Binance WebSocket это не требуется.

  1. Установите необходимые библиотеки: Откройте терминал или командную строку и выполните следующую команду:

    
    pip install websockets pandas
    
  2. Сохраните код: Скопируйте предоставленный выше Python-код и сохраните его в файл с расширением .py, например, taker_ratio_calculator.py.

  3. Запустите скрипт: Откройте терминал в директории, где вы сохранили файл, и выполните команду:

    
    python taker_ratio_calculator.py
    
  4. Наблюдайте за результатом: Скрипт начнет подключаться к Binance WebSocket и выводить в консоль текущее значение Taker Buy/Sell Ratio по мере поступления новых данных и заполнения скользящего окна. Вы увидите логи, подобные этим:

    
    [INFO] Инициализирован калькулятор для BTCUSDT с окном 200 сделок.
    [INFO] Подключение к WebSocket: wss://stream.binance.com:9443/ws/btcusdt@aggTrade
    [INFO] Подключено. Ожидание данных...
    [2023-10-27 10:30:01.123] BTCUSDT Taker Buy/Sell Ratio: 0.5234 (Buy: 12345.67, Sell: 11223.45)
    [2023-10-27 10:30:01.456] BTCUSDT Taker Buy/Sell Ratio: 0.5198 (Buy: 12500.10, Sell: 11500.20)
    ...
    

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

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