binance: port `stream_messages()` to use `match:` and a new `L1` struct

rekt_pps
Tyler Goodlet 2023-04-21 15:04:47 -04:00
parent f6cd08c6fa
commit af068c5c51
1 changed files with 91 additions and 39 deletions

View File

@ -176,6 +176,18 @@ class OHLC(Struct):
bar_wap: float = 0.0 bar_wap: float = 0.0
class L1(Struct):
# https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-book-ticker-streams
update_id: int
sym: str
bid: float
bsize: float
ask: float
asize: float
# convert datetime obj timestamp to unixtime in milliseconds # convert datetime obj timestamp to unixtime in milliseconds
def binance_timestamp( def binance_timestamp(
when: datetime when: datetime
@ -363,45 +375,85 @@ async def stream_messages(
) -> AsyncGenerator[NoBsWs, dict]: ) -> AsyncGenerator[NoBsWs, dict]:
# TODO: match syntax here! # TODO: match syntax here!
msg: dict[str, Any]
async for msg in ws: async for msg in ws:
match msg:
# for l1 streams binance doesn't add an event type field so # for l1 streams binance doesn't add an event type field so
# identify those messages by matching keys # identify those messages by matching keys
# https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-book-ticker-streams # https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-book-ticker-streams
if msg.get('u'): case {
sym = msg['s'] # NOTE: this is never an old value it seems, so
bid = float(msg['b']) # they are always sending real L1 spread updates.
bsize = float(msg['B']) 'u': upid, # update id
ask = float(msg['a']) 's': sym,
asize = float(msg['A']) 'b': bid,
'B': bsize,
'a': ask,
'A': asize,
}:
# TODO: it would be super nice to have a `L1` piker type
# which "renders" incremental tick updates from a packed
# msg-struct:
# - backend msgs after packed into the type such that we
# can reduce IPC usage but without each backend having
# to do that incremental update logic manually B)
# - would it maybe be more efficient to use this instead?
# https://binance-docs.github.io/apidocs/spot/en/#diff-depth-stream
l1 = L1(
update_id=upid,
sym=sym,
bid=bid,
bsize=bsize,
ask=ask,
asize=asize,
)
l1.typecast()
# repack into piker's tick-quote format
yield 'l1', { yield 'l1', {
'symbol': sym, 'symbol': l1.sym,
'ticks': [ 'ticks': [
{'type': 'bid', 'price': bid, 'size': bsize}, {
{'type': 'bsize', 'price': bid, 'size': bsize}, 'type': 'bid',
{'type': 'ask', 'price': ask, 'size': asize}, 'price': l1.bid,
{'type': 'asize', 'price': ask, 'size': asize} 'size': l1.bsize,
},
{
'type': 'bsize',
'price': l1.bid,
'size': l1.bsize,
},
{
'type': 'ask',
'price': l1.ask,
'size': l1.asize,
},
{
'type': 'asize',
'price': l1.ask,
'size': l1.asize,
}
] ]
} }
elif msg.get('e') == 'aggTrade': # https://binance-docs.github.io/apidocs/spot/en/#aggregate-trade-streams
case {
# NOTE: this is purely for a definition, ``msgspec.Struct`` 'e': 'aggTrade',
# does not runtime-validate until you decode/encode. }:
# see: https://jcristharif.com/msgspec/structs.html#type-validation # NOTE: this is purely for a definition,
# ``msgspec.Struct`` does not runtime-validate until you
# decode/encode, see:
# https://jcristharif.com/msgspec/structs.html#type-validation
msg = AggTrade(**msg) msg = AggTrade(**msg)
msg.typecast()
# TODO: type out and require this quote format
# from all backends!
yield 'trade', { yield 'trade', {
'symbol': msg.s, 'symbol': msg.s,
'last': msg.p, 'last': msg.p,
'brokerd_ts': time.time(), 'brokerd_ts': time.time(),
'ticks': [{ 'ticks': [{
'type': 'trade', 'type': 'trade',
'price': float(msg.p), 'price': msg.p,
'size': float(msg.q), 'size': msg.q,
'broker_ts': msg.T, 'broker_ts': msg.T,
}], }],
} }