Большинство современных криптобирж отдают информацию через REST-запросы – клиент должен запросить через HTTP страницу с определенным адресом, отправить нужные параметры и получить некоторый ответ.
Сама по себе технология REST довольно интересна – незаметно для получателя запрос может путешествовать от одного сервера к другому, можно балансировать нагрузку, можно снизить кол-во отдаваемого трафика, но этого мало (с)
На крупных биржах счет пользователей идет на миллионы, а кол-во запросов к API намного выше, т.к. и команды пользователей идут через эти же интерфейсы, через них работают работы, через них другие сайты получают информацию для виджетов на свои сайты, брокеры выводят информацию своим клиентам, тысячи телеграм-каналов что-то там транслируют, анализируют, и многое-многое другое. А ведь каждый лишний байт трафика, помноженный на десятки миллионов запросов выливается в большие долларовые потери на оплату трафика, содержание серверов, сетевого оборудования, зарплаты техподдержки – поэтому REST становится накладным.
Для экономии трафика используется технология WebSocket - с ней некоторое кол-во трафика тратится один раз на установление соединения, после чего клиент и сервер обмениваются непосредственно данными. Это как связаться с кем-то по телефону – вы позвонили, трубку снял автоответчик, теперь вы можете бесконечно висеть на трубке и слушать, что там происходит. Вообще вебсокеты подразумевают двустороннюю связь – вы можете что-то говорить в трубку, ваш абонент может, но в случае Binance (и большинства других криптобирж) есть ограничения.
Так, например, на бинансе нельзя слушать сокет непрерывно свыше 24 часов. Так же связь односторонняя – сервер время от времени (один раз в секунду, как правило) выдаёт один и тот же набор данных всем, кто его слушает. Это как прийти на вокзал и слушать объявления – «Поезд на Бердичев прибыл на второй путь», «Отправление поезда Саратов-Омск» в толпе таких же людей.
Для работы вам потребуется установленный питон версии 3.6 и выше. Скачать его можно с официального сайта, при установке установив все флаги.
Технически, нет ничего сложного, чтобы реализовать протокол самому с нуля, для этого у вас всё есть, но не будем изобретать велосипеды и возьмем чужой готовый модуль питона websocket-client и посмотрим, что можно получить с binance. Для установки модуля выполните в командной строке
pip install websocket-client
Теперь давайте напишем простой скрипт для проверки работы, а потом пройдемся детальнее. Вот он:
import websocket def on_message(ws, message): print(message) def on_error(ws, error): print(error) def on_close(ws): print("### closed ###") def on_open(ws): print("### connected ###") if __name__ == "__main__": #ws = websocket.WebSocketApp("wss://stream.binance.com:9443/stream?streams=ltcbtc@aggTrade/ethbtc@aggTrade", ws = websocket.WebSocketApp("wss://stream.binance.com:9443/ws/ltcbtc@aggTrade/ethbtc@aggTrade", on_message = on_message, on_error = on_error, on_close = on_close) ws.on_open = on_open ws.run_forever()
После его запуска вы увидите нечто похожее:
Фактически, вы подключились к сокет-серверу и подписались на обновления сделок по парам LTCBTC и ETHBTC. Фактически синхронно с веб-интерфейсом у вас обновляются данные по последним сделкам. Теперь давайте рассмотрим подробнее, что и как можно и нужно делать. Начнем с режимов.
В моем скрипте одна строка закомментирована – вы можете её раскомментировать и удалить строку под ней – тогда вам будет выдаваться чуть больше информации, вот так:
import websocket def on_message(ws, message): print(message) def on_error(ws, error): print(error) def on_close(ws): print("### closed ###") def on_open(ws): print("### connected ###") if __name__ == "__main__": ws = websocket.WebSocketApp("wss://stream.binance.com:9443/stream?streams=ltcbtc@aggTrade/ethbtc@aggTrade", #ws = websocket.WebSocketApp("wss://stream.binance.com:9443/ws/ltcbtc@aggTrade/ethbtc@aggTrade", on_message = on_message, on_error = on_error, on_close = on_close) ws.on_open = on_open ws.run_forever()
Первый режим – это то, что Binance называет raw режимом – каждый набор данных отдается как есть, независимо от другого. Т.е. если в один момент времени произошли сделки И LTCBTC И ETHBTC, то вы получите две записи.
В случае combined режима, вы, скорее всего, получите одну запись, которая логически будет структурирована, и внутри которой будут сделки по каждой паре, каждая в своем разделе. Смотрите сами, как вам удобнее, мне удобнее raw.
Каждое подключение должно идти на адрес
wss://stream.binance.com:9443
В конце адреса нужно подставить параметр, что бы указать, какая информация вам нужна. В случае raw укажите /ws/…, в случае combined - /stream?streams=, как у меня в примере.
Все пары маленькими буквами, и не забывайте пересоздавать коннект раз в 24 часа.
Стримы – streams (потоки) – это то, что «льется» из биржи – например, информация по свечам EOSBTC – это один стрим, по свечам ONTBTC – другой, тикер по всем парам – третий, и т.п.
То, что мы смотрели в примере выше – сделки по паре (или парам), объединенные в рамках одного ордера. Иными словами, если по одной цене одним человеком по одной паре в течении последних милисекунд было совершено несколько сделок, то вы увидите одну строку.
Пример запроса: ethbtc@aggTrade
wss://stream.binance.com:9443/ws/ethbtc@aggTrade
wss://stream.binance.com:9443/stream?streams=ethbtc@aggTrade
Структура ответа:{ "e": "aggTrade", // Тип события "E": 123456789, // Время отправки события "s": "BNBBTC", // Пара "a": 12345, // ID возвращаемой записи "p": "0.001", // Цена "q": "100", // Кол-во "f": 100, // ID первой сделки "l": 105, // ID последней сделки "T": 123456785, // Время сделки "m": true, // Покупатель мейкер? "M": true // Не актуально. }
Выдается информация по сделкам, как есть.
Пример запроса: ethbtc@trade
wss://stream.binance.com:9443/ws/ethbtc@trade
wss://stream.binance.com:9443/stream?streams=ethbtc@trade
Структура ответа:
{ "e": "trade", // Тип события "E": 123456789, // Время отправки "s": "BNBBTC", // Пара "t": 12345, // ID события "p": "0.001", // Цена "q": "100", // Объем "b": 88, // Id заказа покупателя "a": 50, // Id заказа продавца "T": 123456785, // Время сделки "m": true, // Покупатель мейкер? "M": true // Не актуально. }
Отдается каждую секунду. Нужно указать период, за который интересует информация.
Формируется так: параkline_период
Например
wss://stream.binance.com:9443/ws/ethbtc@kline_5m
wss://stream.binance.com:9443/stream?streams=ethbtc@kline_5m
Единицы измерения:
m -> минуты; h -> часы; d -> дни; w -> недели; M -> месяца
Возможные варианты:
Структура ответа:
{ "e": "kline", // Тип события "E": 123456789, // Время события "s": "BNBBTC", // пара "k": { "t": 123400000, // Время открытия свечи (UNIXTIME) "T": 123460000, // Время закрытия свечи "s": "BNBBTC", // Пара "i": "1m", // Период "f": 100, // ID первой сделки периода "L": 200, // ID последней сделки периода "o": "0.0010", // Цена открытия "c": "0.0020", // Цена закрытия "h": "0.0025", // High "l": "0.0015", // Low "v": "1000", // Объем базовой валюты "n": 100, // Кол-во сделок "x": false, // Закрыта ли свеча? "q": "1.0000", // Объем квотируемой валюты "V": "500", // Сколько базовой валюты куплено тейкерами "Q": "0.500", // Сколько квотируемой валюты куплено тейкерами "B": "123456" // Не актуально } }
Статистика по паре за 24 часа
Отправляется с сервера раз в секунду.
Пример запроса: ethbtc@ticker
wss://stream.binance.com:9443/ws/ethbtc@ticker
wss://stream.binance.com:9443/stream?streams=ethbtc@ticker
Структура ответа:
{ "e": "24hrTicker", // Тип события "E": 123456789, // Время события "s": "BNBBTC", // Пара "p": "0.0015", // Изменение цены "P": "250.00", // Изменение цены в процентах "w": "0.0018", // Средневзвешенная цена "x": "0.0009", // Цена закрытия предыдущих суток "c": "0.0025", // Цена закрытия текущих суток "Q": "10", // Объем закрытия "b": "0.0024", // Цена лучшего Bid (спроса/покупки) "B": "10", // Объем лучшего Bid "a": "0.0026", // Цена лучшего ask (преложение/продажа) "A": "100", // Объем лучшего ask "o": "0.0010", // Цена открытия "h": "0.0025", // High "l": "0.0010", // Low "v": "10000", // Общий объем торгов в базовой валюте "q": "18", // Общий объем торгов в квотируемой валюте "O": 0, // Время начала сбора статистики "C": 86400000, // Время окончания сбора статистики "F": 0, // ID первой сделки "L": 18150, // Id последней сделки "n": 18151 // Общее кол-во сделок }
Отправляется раз в секунду.
Пример запроса: /!ticker@arr
wss://stream.binance.com:9443/ws/!ticker@arr
wss://stream.binance.com:9443/stream?streams=!ticker@arr
Возвращает то же, что и статистика за 24 часа, но по всем парам сразу, вот в такой структуре:
[ { // Отдельно взятая пара } ]
Лучшие предложения покупки и продажи. Допускается получать по 5, 10 или 20 предложений из каждого стакана. Обновляется раз в секунду
Пример запроса: ethbtc@depth5
wss://stream.binance.com:9443/ws/ethbtc@depth5
wss://stream.binance.com:9443/stream?streams=ethbtc@depth5
Структура ответа:
{ "lastUpdateId": 160, // ID события "bids": [ // Стакан покупок [ "0.0024", // Цена "10", // Объем [] // Не актуально ] ], "asks": [ // Стакан продаж [ "0.0026", // Цена "100", // Объем [] // Не актуально ] ] }
Обновляется раз в секунду. Метод нужен тем, кто локально собирает и анализирует копии стаканов.
Пример запроса: ethbtc@depth
wss://stream.binance.com:9443/ws/ethbtc@depth
wss://stream.binance.com:9443/stream?streams=ethbtc@depth
Структура ответа:
{ "e": "depthUpdate", // Тип события "E": 123456789, // Время события "s": "BNBBTC", // Пара "U": 157, // Первое ID события "u": 160, // Последнее ID события "b": [ // Покупки [ "0.0024", // Цена "10", // Объем [] // Не актуально ] ], "a": [ // Продажи [ "0.0026", // Цена "100", // Объем [] // Не актуально ] ] }