From e68c55e9bd56bfcdfec17665e1db37a1c1049577 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 12 Jun 2023 21:58:46 -0400 Subject: [PATCH] Switch `Client.mkt_mode` to 'usd_futes' if 'perp' in fqme The beginning of supporting multi-markets through a common API client. Change to futes market mode in the client if `.perp.` is matched in the fqme. Currently the exchange info and live feed ws impl will swap out for their usd-margin futures market equivalent (endpoints). --- piker/brokers/binance/api.py | 51 +++++++++++++++------------------ piker/brokers/binance/broker.py | 1 + piker/brokers/binance/feed.py | 23 +++++++++++++-- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/piker/brokers/binance/api.py b/piker/brokers/binance/api.py index fd0a0c82..8caaa760 100644 --- a/piker/brokers/binance/api.py +++ b/piker/brokers/binance/api.py @@ -30,7 +30,6 @@ from datetime import datetime from typing import ( Any, Callable, - Literal, ) import hmac import hashlib @@ -53,8 +52,9 @@ from piker.brokers._util import ( get_logger, ) from .schemas import ( - SpotPair, - FutesPair, + PAIRTYPES, + Pair, + MarketType, ) log = get_logger('piker.brokers.binance') @@ -150,14 +150,6 @@ def binance_timestamp( return int((when.timestamp() * 1000) + (when.microsecond / 1000)) -MarketType: Literal[ - 'spot', - 'margin', - 'usd_futes', - 'coin_futes', -] - - class Client: ''' Async ReST API client using ``trio`` + ``asks`` B) @@ -319,7 +311,7 @@ class Client: self, sym: str | None = None, - mkt_type: MarketType = 'spot', + mkt_type: MarketType | None = None, ) -> dict[str, Pair] | Pair: ''' @@ -334,7 +326,10 @@ class Client: https://binance-docs.github.io/apidocs/delivery/en/#exchange-information ''' - cached_pair = self._pairs.get(sym) + mkt_type: MarketType = mkt_type or self.mkt_mode + cached_pair = self._pairs.get( + (sym, mkt_type) + ) if cached_pair: return cached_pair @@ -344,16 +339,15 @@ class Client: sym = sym.lower() params = {'symbol': sym} - resp = await self.mkt_req[self.mkt_mode]('exchangeInfo', params=params) + resp = await self.mkt_req[mkt_type]('exchangeInfo', params=params) entries = resp['symbols'] if not entries: raise SymbolNotFound(f'{sym} not found:\n{resp}') # import tractor # await tractor.breakpoint() - pairs = {} + pairs: dict[str, Pair] = {} for item in entries: - symbol = item['symbol'] # for spot mkts, pre-process .filters field into # a table.. @@ -364,17 +358,14 @@ class Client: ftype = entry['filterType'] filters[ftype] = entry - # TODO: lookup pair schema by mkt type - # pair_type = mkt_type + item['filters'] = filters - # pairs[symbol] = SpotPair( - # filters=filters, - # ) - pairs[symbol] = FutesPair(**item) + symbol = item['symbol'] + pair_type: Pair = PAIRTYPES[mkt_type or self.mkt_mode] + pairs[(symbol, mkt_type)] = pair_type( + **item, + ) - # pairs = { - # item['symbol']: Pair(**item) for item in entries - # } self._pairs.update(pairs) if sym is not None: @@ -633,8 +624,12 @@ class Client: @acm -async def get_client() -> Client: - client = Client(mkt_mode='usd_futes') - log.info('Caching exchange infos..') +async def get_client( + mkt_mode: str = 'spot', +) -> Client: + client = Client(mkt_mode=mkt_mode) + + log.info(f'{client} in {mkt_mode} mode: caching exchange infos..') await client.exch_info() + yield client diff --git a/piker/brokers/binance/broker.py b/piker/brokers/binance/broker.py index d2edbd9a..5c17b194 100644 --- a/piker/brokers/binance/broker.py +++ b/piker/brokers/binance/broker.py @@ -104,6 +104,7 @@ async def trades_dialogue( ) -> AsyncIterator[dict[str, Any]]: async with open_cached_client('binance') as client: + await tractor.breakpoint() if not client.api_key: await ctx.started('paper') return diff --git a/piker/brokers/binance/feed.py b/piker/brokers/binance/feed.py index 83e7bee0..561b5fbc 100644 --- a/piker/brokers/binance/feed.py +++ b/piker/brokers/binance/feed.py @@ -50,6 +50,7 @@ from piker._cacheables import ( from piker.accounting._mktinfo import ( Asset, MktPair, + unpack_fqme, digits_to_dec, ) from piker.data.types import Struct @@ -263,9 +264,27 @@ async def get_mkt_info( ) -> tuple[MktPair, Pair]: - async with open_cached_client('binance') as client: + # uppercase since kraken bs_mktid is always upper + if 'binance' not in fqme: + fqme += '.binance' - pair: Pair = await client.exch_info(fqme.upper()) + bs_fqme, _, broker = fqme.rpartition('.') + broker, mkt_ep, venue, suffix = unpack_fqme(fqme) + # bs_fqme, _, broker = fqme.partition('.') + + mkt_mode: str = 'spot' + if 'perp' in bs_fqme: + mkt_mode = 'usd_futes' + + async with open_cached_client( + 'binance', + mkt_mode=mkt_mode, + ) as client: + + pair_str: str = mkt_ep.upper() + pair: Pair = await client.exch_info(pair_str) + + await tractor.breakpoint() mkt = MktPair( dst=Asset( name=pair.baseAsset,