.kraken: start new `.symbols` submod and move symcache and search stuff there

account_tests
Tyler Goodlet 2023-07-17 16:20:11 -04:00
parent 82fd785646
commit 912f1bc635
3 changed files with 117 additions and 112 deletions

View File

@ -19,23 +19,26 @@ Kraken backend.
Sub-modules within break into the core functionalities: Sub-modules within break into the core functionalities:
- ``broker.py`` part for orders / trading endpoints - .api: for the core API machinery which generally
- ``feed.py`` for real-time data feed endpoints a ``asks``/``trio-websocket`` implemented ``Client``.
- ``api.py`` for the core API machinery which is ``trio``-ized - .broker: part for orders / trading endpoints.
wrapping around ``ib_insync``. - .feed: for real-time and historical data query endpoints.
- .ledger: for transaction processing as it pertains to accounting.
- .symbols: for market (name) search and symbology meta-defs.
''' '''
from .symbols import Pair # for symcache from .symbols import (
Pair, # for symcache
open_symbol_search,
# required by `.accounting`, `.data`
get_mkt_info,
)
# required by `.brokers` # required by `.brokers`
from .api import ( from .api import (
get_client, get_client,
) )
from .feed import ( from .feed import (
# required by `.accounting`, `.data`
get_mkt_info,
# required by `.data` # required by `.data`
open_symbol_search,
stream_quotes, stream_quotes,
open_history_client, open_history_client,
) )
@ -66,6 +69,7 @@ __all__ = [
# tractor RPC enable arg # tractor RPC enable arg
__enable_modules__: list[str] = [ __enable_modules__: list[str] = [
'api', 'api',
'feed',
'broker', 'broker',
'feed',
'symbols',
] ]

View File

@ -30,24 +30,16 @@ from typing import (
) )
import time import time
from fuzzywuzzy import process as fuzzy
import numpy as np import numpy as np
import pendulum import pendulum
from trio_typing import TaskStatus from trio_typing import TaskStatus
import tractor
import trio import trio
from piker.accounting._mktinfo import ( from piker.accounting._mktinfo import (
Asset,
MktPair, MktPair,
unpack_fqme,
) )
from piker.brokers import ( from piker.brokers import (
open_cached_client, open_cached_client,
SymbolNotFound,
)
from piker._cacheables import (
async_lifo_cache,
) )
from piker.brokers._util import ( from piker.brokers._util import (
BrokerError, BrokerError,
@ -59,9 +51,8 @@ from piker.data.validate import FeedInit
from piker.data._web_bs import open_autorecon_ws, NoBsWs from piker.data._web_bs import open_autorecon_ws, NoBsWs
from .api import ( from .api import (
log, log,
Client,
Pair,
) )
from .symbols import get_mkt_info
class OHLC(Struct, frozen=True): class OHLC(Struct, frozen=True):
@ -267,70 +258,6 @@ async def open_history_client(
yield get_ohlc, {'erlangs': 1, 'rate': 1} yield get_ohlc, {'erlangs': 1, 'rate': 1}
@async_lifo_cache()
async def get_mkt_info(
fqme: str,
) -> tuple[MktPair, Pair]:
'''
Query for and return a `MktPair` and backend-native `Pair` (or
wtv else) info.
If more then one fqme is provided return a ``dict`` of native
key-strs to `MktPair`s.
'''
venue: str = 'spot'
expiry: str = ''
if '.kraken' not in fqme:
fqme += '.kraken'
broker, pair, venue, expiry = unpack_fqme(fqme)
venue: str = venue or 'spot'
if venue.lower() != 'spot':
raise SymbolNotFound(
'kraken only supports spot markets right now!\n'
f'{fqme}\n'
)
async with open_cached_client('kraken') as client:
# uppercase since kraken bs_mktid is always upper
# bs_fqme, _, broker = fqme.partition('.')
# pair_str: str = bs_fqme.upper()
pair_str: str = f'{pair}.{venue}'
pair: Pair | None = client._pairs.get(pair_str.upper())
if not pair:
bs_fqme: str = Client.to_bs_fqme(pair_str)
pair: Pair = client._pairs[bs_fqme]
if not (assets := client._assets):
assets: dict[str, Asset] = await client.get_assets()
dst_asset: Asset = assets[pair.bs_dst_asset]
src_asset: Asset = assets[pair.bs_src_asset]
mkt = MktPair(
dst=dst_asset,
src=src_asset,
price_tick=pair.price_tick,
size_tick=pair.size_tick,
bs_mktid=pair.bs_mktid,
expiry=expiry,
venue=venue or 'spot',
# TODO: futes
# _atype=_atype,
broker='kraken',
)
return mkt, pair
async def stream_quotes( async def stream_quotes(
send_chan: trio.abc.SendChannel, send_chan: trio.abc.SendChannel,
@ -486,30 +413,3 @@ async def stream_quotes(
log.warning(f'Unknown WSS message: {typ}, {quote}') log.warning(f'Unknown WSS message: {typ}, {quote}')
await send_chan.send({topic: quote}) await send_chan.send({topic: quote})
@tractor.context
async def open_symbol_search(
ctx: tractor.Context,
) -> Client:
async with open_cached_client('kraken') as client:
# load all symbols locally for fast search
cache = await client.get_mkt_pairs()
await ctx.started(cache)
async with ctx.open_stream() as stream:
async for pattern in stream:
matches = fuzzy.extractBests(
pattern,
client._pairs,
score_cutoff=50,
)
# repack in dict form
await stream.send({
pair[0].altname: pair[0]
for pair in matches
})

View File

@ -15,15 +15,30 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
Symbology defs and deats! Symbology defs and search.
''' '''
from decimal import Decimal from decimal import Decimal
import tractor
from fuzzywuzzy import process as fuzzy
from piker._cacheables import (
async_lifo_cache,
)
from piker.accounting._mktinfo import ( from piker.accounting._mktinfo import (
digits_to_dec, digits_to_dec,
) )
from piker.brokers import (
open_cached_client,
SymbolNotFound,
)
from piker.data.types import Struct from piker.data.types import Struct
from piker.accounting._mktinfo import (
Asset,
MktPair,
unpack_fqme,
)
# https://www.kraken.com/features/api#get-tradable-pairs # https://www.kraken.com/features/api#get-tradable-pairs
@ -112,3 +127,89 @@ class Pair(Struct):
return f'{dst}{src}.SPOT' return f'{dst}{src}.SPOT'
@tractor.context
async def open_symbol_search(ctx: tractor.Context) -> None:
async with open_cached_client('kraken') as client:
# load all symbols locally for fast search
cache = await client.get_mkt_pairs()
await ctx.started(cache)
async with ctx.open_stream() as stream:
async for pattern in stream:
matches = fuzzy.extractBests(
pattern,
client._pairs,
score_cutoff=50,
)
# repack in dict form
await stream.send({
pair[0].altname: pair[0]
for pair in matches
})
@async_lifo_cache()
async def get_mkt_info(
fqme: str,
) -> tuple[MktPair, Pair]:
'''
Query for and return a `MktPair` and backend-native `Pair` (or
wtv else) info.
If more then one fqme is provided return a ``dict`` of native
key-strs to `MktPair`s.
'''
venue: str = 'spot'
expiry: str = ''
if '.kraken' not in fqme:
fqme += '.kraken'
broker, pair, venue, expiry = unpack_fqme(fqme)
venue: str = venue or 'spot'
if venue.lower() != 'spot':
raise SymbolNotFound(
'kraken only supports spot markets right now!\n'
f'{fqme}\n'
)
async with open_cached_client('kraken') as client:
# uppercase since kraken bs_mktid is always upper
# bs_fqme, _, broker = fqme.partition('.')
# pair_str: str = bs_fqme.upper()
pair_str: str = f'{pair}.{venue}'
pair: Pair | None = client._pairs.get(pair_str.upper())
if not pair:
bs_fqme: str = client.to_bs_fqme(pair_str)
pair: Pair = client._pairs[bs_fqme]
if not (assets := client._assets):
assets: dict[str, Asset] = await client.get_assets()
dst_asset: Asset = assets[pair.bs_dst_asset]
src_asset: Asset = assets[pair.bs_src_asset]
mkt = MktPair(
dst=dst_asset,
src=src_asset,
price_tick=pair.price_tick,
size_tick=pair.size_tick,
bs_mktid=pair.bs_mktid,
expiry=expiry,
venue=venue or 'spot',
# TODO: futes
# _atype=_atype,
broker='kraken',
)
return mkt, pair