Got rid of websocket OHLC API, and added l1 tick streaming

binance_backend
Guillermo Rodriguez 2021-05-07 10:59:08 -03:00
parent 7e493625f6
commit 604e195bc0
No known key found for this signature in database
GPG Key ID: 3F61096EC7DF75A8
1 changed files with 27 additions and 95 deletions

View File

@ -55,28 +55,6 @@ log = get_logger(__name__)
_url = 'https://api.binance.com'
# Broker specific ohlc schema (websocket)
_websocket_ohlc_dtype = [
('index', int),
('time', int),
('close_time', int),
('symbol', str),
('interval', str),
('first_trade_id', int),
('last_trade_id', int),
('open', float),
('close', float),
('high', float),
('low', float),
('volume', float),
('num_trades', int),
('closed', bool),
('quote_asset_volume', float),
('taker_buy_base_asset_volume', float),
('taker_buy_quote_asset_volume', float),
('ignore', int)
]
# Broker specific ohlc schema (rest)
_ohlc_dtype = [
('index', int),
@ -150,6 +128,8 @@ class OHLC:
buy_base_vol: float
buy_quote_vol: float
ignore: int
# (sampled) generated tick data
ticks: List[Any] = field(default_factory=list)
# convert arrow timestamp to unixtime in miliseconds
@ -235,30 +215,29 @@ async def get_client() -> Client:
async def stream_messages(ws):
too_slow_count = last_hb = 0
while True:
with trio.move_on_after(5) as cs:
msg = await ws.recv_msg()
if msg.get('e') == 'kline':
# for l1 streams binance doesn't add an event type field so
# identify those messages by matching keys
if list(msg.keys()) == ['u', 's', 'b', 'B', 'a', 'A']:
sym = msg['s']
bid = float(msg['b'])
bsize = float(msg['B'])
ask = float(msg['a'])
asize = float(msg['A'])
yield 'ohlc', OHLC(*msg['k'].values())
def normalize(
ohlc: OHLC,
) -> dict:
quote = asdict(ohlc)
quote['broker_ts'] = quote['start_time']
quote['brokerd_ts'] = time.time()
quote['last'] = quote['close']
quote['time'] = quote['start_time']
# print(quote)
return ohlc.symbol, quote
yield 'l1', {
'symbol': sym,
'ticks': [
{'type': 'bid', 'price': bid, 'size': bsize},
{'type': 'bsize', 'price': bid, 'size': bsize},
{'type': 'ask', 'price': ask, 'size': asize},
{'type': 'asize', 'price': ask, 'size': asize}
]
}
def make_sub(pairs: List[str], sub_name: str, uid: int) -> Dict[str, str]:
@ -389,10 +368,6 @@ async def stream_quotes(
task_status: TaskStatus[Tuple[Dict, Dict]] = trio.TASK_STATUS_IGNORED,
) -> None:
"""Subscribe for ohlc stream of quotes for ``pairs``.
``pairs`` must be formatted <crypto_symbol><fiat_symbol>.
"""
# XXX: required to propagate ``tractor`` loglevel to piker logging
get_console_log(loglevel or tractor.current_actor().loglevel)
@ -421,14 +396,9 @@ async def stream_quotes(
async with open_autorecon_ws('wss://stream.binance.com/ws') as ws:
# XXX: setup subs
ohlc_sub = make_sub(symbols, 'kline_1m', uid)
uid += 1
await ws.send_msg(ohlc_sub)
res = await ws.recv_msg()
# trade data (aka L1)
l1_sub = make_sub(symbols, 'trade', uid)
l1_sub = make_sub(symbols, 'bookTicker', uid)
uid += 1
await ws.send_msg(l1_sub)
@ -438,56 +408,18 @@ async def stream_quotes(
msg_gen = stream_messages(ws)
# TODO: use ``anext()`` when it lands in 3.10!
typ, ohlc_last = await msg_gen.__anext__()
typ, tick = await msg_gen.__anext__()
topic, quote = normalize(ohlc_last)
first_quote = {topic: quote}
first_quote = {tick['symbol']: tick}
task_status.started((init_msgs, first_quote))
# lol, only "closes" when they're margin squeezing clients ;P
feed_is_live.set()
# keep start of last interval for volume tracking
last_interval_start = ohlc_last.end_time
# start streaming
async for typ, ohlc in msg_gen:
...
# if typ == 'ohlc':
async for typ, msg in msg_gen:
# # TODO: can get rid of all this by using
# # ``trades`` subscription...
if typ == 'l1':
topic = msg['symbol']
quote = msg
# # generate tick values to match time & sales pane:
# # https://trade.kraken.com/charts/KRAKEN:BTC-USD?period=1m
# volume = ohlc.volume
# # new OHLC sample interval
# if ohlc.etime > last_interval_start:
# last_interval_start = ohlc.etime
# tick_volume = volume
# else:
# # this is the tick volume *within the interval*
# tick_volume = volume - ohlc_last.volume
# ohlc_last = ohlc
# last = ohlc.close
# if tick_volume:
# ohlc.ticks.append({
# 'type': 'trade',
# 'price': last,
# 'size': tick_volume,
# })
# topic, quote = normalize(ohlc)
# elif typ == 'l1':
# quote = ohlc
# topic = quote['symbol']
# # XXX: format required by ``tractor.msg.pub``
# # requires a ``Dict[topic: str, quote: dict]``
# await send_chan.send({topic: quote})
await send_chan.send({topic: quote})