Deribit WebSocket: Получение Греков Опционов в Реальном Времени с Asyncio

Deribit WebSocket: Получение Греков Опционов в Реальном Времени с Asyncio Python & API
Подробная инструкция по реализации асинхронного WebSocket-подключения к Deribit API на Python с использованием asyncio для получения греков опционов (Delta, Gamma, Vega, Theta, Rho, IV) в реальном времени.
Суть: Реализация асинхронного WebSocket-подключения к Deribit API с использованием библиотеки websockets и фреймворка asyncio для получения потоковых данных по грекам опционов (Delta, Gamma, Vega, Theta, Rho, IV) в реальном времени.

Исходный код

Представленный ниже Python-код демонстрирует создание асинхронного клиента для подключения к Deribit WebSocket API. Клиент подписывается на канал options.greeks.{instrument_name}.100ms, что позволяет получать обновления греков опционов с интервалом в 100 миллисекунд. В коде предусмотрена логика автоматического переподключения в случае разрыва соединения, а также динамическое получение актуального имени инструмента для подписки.

Полученные в реальном времени греки могут быть использованы для различных целей: от мониторинга рыночной волатильности и оценки рисков до интеграции в сложные торговые стратегии. Например, для классификации рыночных событий на основе этих данных можно использовать продвинутые методы машинного обучения, как описано в статье CatBoost для Классификации Ложных Пробоев в Торговом Боте на Python.


import asyncio
import websockets
import json
import time

class DeribitGreeksClient:
    def __init__(self, instrument_name: str, testnet: bool = True):
        self.instrument_name = instrument_name
        self.url = "wss://test.deribit.com/ws/api/v2" if testnet else "wss://www.deribit.com/ws/api/v2"
        self.websocket = None
        self.reconnect_interval = 5 # seconds

    async def connect(self):
        print(f"Connecting to Deribit WebSocket at {self.url}...")
        try:
            self.websocket = await websockets.connect(self.url)
            print("Connected to Deribit WebSocket.")
            await self.subscribe_to_greeks()
            return True
        except Exception as e:
            print(f"Connection failed: {e}")
            return False

    async def subscribe_to_greeks(self):
        channel = f"options.greeks.{self.instrument_name}.100ms"
        subscribe_request = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "public/subscribe",
            "params": {
                "channels": [channel]
            }
        }
        await self.websocket.send(json.dumps(subscribe_request))
        print(f"Subscribed to channel: {channel}")

    async def listen_for_messages(self):
        while True:
            try:
                message = await self.websocket.recv()
                data = json.loads(message)
                if data.get("method") == "subscription":
                    channel = data["params"]["channel"]
                    greeks_data = data["params"]["data"]
                    print(f"Received Greeks for {channel}:")
                    print(f"  Delta: {greeks_data.get('delta')}")
                    print(f"  Gamma: {greeks_data.get('gamma')}")
                    print(f"  Vega: {greeks_data.get('vega')}")
                    print(f"  Theta: {greeks_data.get('theta')}")
                    print(f"  Rho: {greeks_data.get('rho')}")
                    print(f"  Implied Volatility: {greeks_data.get('iv')}")
                    print("-" * 30)
                elif data.get("result"):
                    print(f"Subscription response: {data}")
                elif data.get("error"):
                    print(f"Error: {data['error']}")
            except websockets.exceptions.ConnectionClosedOK:
                print("Connection closed gracefully.")
                break
            except websockets.exceptions.ConnectionClosedError as e:
                print(f"Connection closed with error: {e}")
                await self.handle_reconnect()
                break
            except Exception as e:
                print(f"An unexpected error occurred: {e}")
                await self.handle_reconnect()
                break

    async def handle_reconnect(self):
        print(f"Attempting to reconnect in {self.reconnect_interval} seconds...")
        await asyncio.sleep(self.reconnect_interval)
        while not await self.connect():
            print(f"Reconnection failed, retrying in {self.reconnect_interval} seconds...")
            await asyncio.sleep(self.reconnect_interval)
        print("Reconnected successfully.")
        # After reconnecting, the subscription needs to be re-established
        await self.subscribe_to_greeks()
        # Restart listening
        asyncio.create_task(self.listen_for_messages())


async def get_some_instrument_name(testnet: bool = True):
    url = "wss://test.deribit.com/ws/api/v2" if testnet else "wss://www.deribit.com/ws/api/v2"
    try:
        async with websockets.connect(url) as ws:
            request = {
                "jsonrpc": "2.0",
                "id": 7617,
                "method": "public/get_instruments",
                "params": {
                    "currency": "BTC",
                    "kind": "option",
                    "expired": False
                }
            }
            await ws.send(json.dumps(request))
            response = await ws.recv()
            data = json.loads(response)
            if data and data.get("result"):
                # Find an active instrument, preferably with some trading activity
                for instrument in data["result"]:
                    if instrument["is_active"] and instrument["instrument_name"].startswith("BTC-"):
                        return instrument["instrument_name"]
            print("No active BTC option instrument found, using fallback.")
            return "BTC-29DEC23-60000-C" # Fallback, might be expired or inactive
    except Exception as e:
        print(f"Error fetching instrument name: {e}. Using fallback.")
        return "BTC-29DEC23-60000-C" # Fallback

async def main():
    instrument_to_subscribe = await get_some_instrument_name(testnet=True)
    if not instrument_to_subscribe:
        print("Could not fetch a valid instrument name. Exiting.")
        return

    print(f"Using instrument: {instrument_to_subscribe}")
    client = DeribitGreeksClient(instrument_to_subscribe, testnet=True)
    if await client.connect():
        await client.listen_for_messages()

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

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

  • instrument_name: Строка, представляющая полное имя опционного контракта на Deribit (например, 'BTC-29DEC23-60000-C'). Этот параметр определяет, для какого конкретного опциона будут запрашиваться греки. В примере используется функция get_some_instrument_name для динамического получения актуального имени инструмента с Deribit Testnet.
  • testnet: Булево значение (True по умолчанию), указывающее, следует ли подключаться к тестовой сети Deribit (wss://test.deribit.com/ws/api/v2) или к основной сети (wss://www.deribit.com/ws/api/v2). Для разработки и тестирования рекомендуется использовать тестовую сеть.
  • reconnect_interval: Целое число, задающее интервал (в секундах) между попытками переподключения к WebSocket в случае разрыва соединения. Обеспечивает устойчивость к временным сетевым проблемам.
  • channel: Строка, определяющая канал подписки на Deribit API. Для получения греков опционов используется формат options.greeks.{instrument_name}.100ms. Число 100ms указывает на частоту обновлений (каждые 100 миллисекунд).

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

Для запуска представленного кода выполните следующие шаги:

  1. Установите необходимые библиотеки: Убедитесь, что у вас установлен Python 3.7+ и библиотека websockets. Если нет, установите ее с помощью pip:
    
    pip install websockets
    
  2. Сохраните код: Скопируйте весь представленный Python-код и сохраните его в файл с расширением .py, например, deribit_greeks.py.
  3. Запустите скрипт: Откройте терминал или командную строку, перейдите в директорию, где вы сохранили файл, и выполните команду:

    
    python deribit_greeks.py
    

После запуска скрипт подключится к Deribit Testnet, динамически определит активный опционный инструмент и начнет выводить в консоль обновления греков для этого инструмента в реальном времени. Вы увидите сообщения о подключении, подписке и затем потоковые данные по Delta, Gamma, Vega, Theta, Rho и Implied Volatility.

Помимо получения греков, для комплексного анализа рынка можно также парсить исторические данные, например, информацию о ликвидациях, как это делается в статье Парсинг Исторических Ликвидаций с Coinglass API на Python. Это позволяет получить более полное представление о динамике рынка и поведении участников. Для обеспечения честной и эффективной работы торговых систем, важно также учитывать аспекты защиты от манипуляций, таких как wash trading, о чем подробно рассказано в статье Реализация защиты от Wash Trading в Matching Engine на Python.

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