Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Binance backend #170

Merged
merged 6 commits into from
May 24, 2021
Merged

Add Binance backend #170

merged 6 commits into from
May 24, 2021

Conversation

guilledk
Copy link
Contributor

@guilledk guilledk commented May 7, 2021

}


class AutoReconWs:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put this in some sort of utils module or something like that, as it is shared between kraken & binance backends.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yah 💯.

We need to fix up the kraken ws respawning anyway so we should probably stick that generic subs mgmt code somewhere as well.

This gets the binance provider meeting the data feed schema requirements
of both the OHLC sampling/charting machinery as well as proper
formatting of historical OHLC history.

Notably,
- spec a minimal ohlc dtype based on the kline endpoint
- use a dataclass to parse out OHLC bar datums and pack into np.ndarray/shm
- add the ``aggTrade`` endpoint to get last clearing (traded) prices,
  validate with ``pydantic`` and then normalize these into our tick-quote
  format for delivery over the feed stream api.
- a notable requirement is that the "first" quote from the feed must
  contain a 'last` field so the clearing system can start up correctly.
@goodboy
Copy link
Contributor

goodboy commented May 21, 2021

@guilledk lol so as mentioned in chat, the quote rates coming from binance easily fall in the "higher" frequency realm 😂

binance quote rate (Hz): 201.71711633722887
binance quote rate (Hz): 176.93752372917106
binance quote rate (Hz): 552.900606380174
binance quote rate (Hz): 168.3918419784808
binance quote rate (Hz): 110.53058212770443
binance quote rate (Hz): 491.8850709510965
binance quote rate (Hz): 579.7241188666206
binance quote rate (Hz): 48.043618702893404
binance quote rate (Hz): 13.001965343005052
binance quote rate (Hz): 134.26928740636404
binance quote rate (Hz): 25.902277555456745
binance quote rate (Hz): 1047.2669163545568
binance quote rate (Hz): 46.08973330549542
binance quote rate (Hz): 14.019004836440086
binance quote rate (Hz): 255.75024390243902
binance quote rate (Hz): 207.49500346294647
binance quote rate (Hz): 30.968214472936157
binance quote rate (Hz): 810.3369397217929
binance quote rate (Hz): 172.3639352346511
binance quote rate (Hz): 111.79146565740025
binance quote rate (Hz): 690.4204115226338
binance quote rate (Hz): 279.41536206781694
binance quote rate (Hz): 66.22724688940819
binance quote rate (Hz): 1018.529383195726
binance quote rate (Hz): 686.1285784393915
binance quote rate (Hz): 240.80284762888965
binance quote rate (Hz): 1101.7346992382454

In which case we should be throttling graphics consumers to their local display / refresh rate to avoid unnecessary render cycles.

Pretty happy with the look of things so far 🏄🏼

Get binance OHLC history and quote format correct
row.append(bar.time / 1000.0)

else:
row.append(getattr(bar, name))
Copy link
Contributor

@goodboy goodboy May 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This felt really really clunky.

What's a better way to one shot validate these?
I don't know if you can unpack *bar in a pydantic model..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I mucked with this for a while and got nowhere too fancy 😂

Since our dtype is technically matching the dataclass we could actually probably just use asdict if we wanted to do it this way:

[nav] In [116]: @dataclass
           ...: class C:
           ...:     doggy: int
           ...:     num: int

[nav] In [117]: l = [C(doggy=9, num=10), C(doggy=11, num=12)]

[nav] In [118]: np.array(list(list(asdict(c).values()) for c in l), dtype={'names': ('doggy', 'num',), 'formats': (int, int)})
Out[118]:
array([[( 9,  9), (10, 10)],
       [(11, 11), (12, 12)]], dtype=[('doggy', '<i8'), ('num', '<i8')])

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a pydantic.BaseModel.dict() would require array unpacking each bar into dict form since I still don't think pydantic.BaseModel supports the OHLC(*bar) style creation.

Not sure it'd be worth it anyway for readability.

# validate
msg = AggTrade(**msg)

# TODO: type out and require this quote format
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely part of writing up the backend spec.

@guilledk guilledk marked this pull request as ready for review May 22, 2021 15:43

# UI components allow this to be declared such that additional
# (historical) fields can be exposed.
ohlc_dtype = np.dtype(_ohlc_dtype)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm it's interesting i think in this case we don't actually need to define this since it matches the default but, i guess for now documenting that we could have extras is handy?

class Client:

def __init__(self) -> None:
self._sesh = asks.Session(connections=4)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that was the other thing.

What do you think about swapping out httpx here?

Apparently everyone in trio is saying it's the more maintained project?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can defer to #135 as well if you want.

# TODO: maybe we should go nanoseconds on all
# history time stamps?
if name == 'time':
# convert to epoch seconds: float
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make an issue about possibly moving to nanoseconds as int for all time stamps.
I see no reason to not be thinking about UHFT down the road.

# identify those messages by matching keys
# https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-book-ticker-streams

if msg.get('u'):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that was my other question: can we do similar BaseModel unpacking/validation here for l1 messages?

@goodboy goodboy requested a review from iamzoltan May 22, 2021 16:54
@goodboy
Copy link
Contributor

goodboy commented May 22, 2021

@guilledk oh one more thing would be to find out if binance supports historical tick data like kraken such that we can get long(er) term views of high frequency sampled data (1s OHLC) going. If not we may have to look to some other historical resources.

Making at least issue for this task would be good.

@goodboy goodboy mentioned this pull request May 24, 2021
6 tasks
@goodboy goodboy merged commit 372b0db into pikers:master May 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants