Deliver symbol info from kraken; start using pydantic

basic_orders
Tyler Goodlet 2021-02-06 14:23:27 -05:00
parent a8c4829cb6
commit 69df73afc3
2 changed files with 74 additions and 35 deletions

View File

@ -18,7 +18,7 @@
Kraken backend. Kraken backend.
""" """
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from dataclasses import dataclass, asdict, field from dataclasses import asdict, field
from typing import List, Dict, Any, Tuple, Optional from typing import List, Dict, Any, Tuple, Optional
import json import json
import time import time
@ -30,6 +30,8 @@ import asks
import numpy as np import numpy as np
import trio import trio
import tractor import tractor
from pydantic.dataclasses import dataclass
from pydantic import BaseModel
from ._util import resproc, SymbolNotFound, BrokerError from ._util import resproc, SymbolNotFound, BrokerError
from ..log import get_logger, get_console_log from ..log import get_logger, get_console_log
@ -68,6 +70,68 @@ ohlc_dtype = np.dtype(_ohlc_dtype)
_show_wap_in_history = True _show_wap_in_history = True
_symbol_info_translation: Dict[str, str] = {
'tick_decimals': 'pair_decimals',
}
# https://www.kraken.com/features/api#get-tradable-pairs
class Pair(BaseModel):
altname: str # alternate pair name
wsname: str # WebSocket pair name (if available)
aclass_base: str # asset class of base component
base: str # asset id of base component
aclass_quote: str # asset class of quote component
quote: str # asset id of quote component
lot: str # volume lot size
pair_decimals: int # scaling decimal places for pair
lot_decimals: int # scaling decimal places for volume
# amount to multiply lot volume by to get currency volume
lot_multiplier: float
# array of leverage amounts available when buying
leverage_buy: List[int]
# array of leverage amounts available when selling
leverage_sell: List[int]
# fee schedule array in [volume, percent fee] tuples
fees: List[Tuple[int, float]]
# maker fee schedule array in [volume, percent fee] tuples (if on
# maker/taker)
fees_maker: List[Tuple[int, float]]
fee_volume_currency: str # volume discount currency
margin_call: str # margin call level
margin_stop: str # stop-out/liquidation margin level
ordermin: float # minimum order volume for pair
@dataclass
class OHLC:
"""Description of the flattened OHLC quote format.
For schema details see:
https://docs.kraken.com/websockets/#message-ohlc
"""
chan_id: int # internal kraken id
chan_name: str # eg. ohlc-1 (name-interval)
pair: str # fx pair
time: float # Begin time of interval, in seconds since epoch
etime: float # End time of interval, in seconds since epoch
open: float # Open price of interval
high: float # High price within interval
low: float # Low price within interval
close: float # Close price of interval
vwap: float # Volume weighted average price within interval
volume: float # Accumulated volume **within interval**
count: int # Number of trades within interval
# (sampled) generated tick data
ticks: List[Any] = field(default_factory=list)
class Client: class Client:
def __init__(self) -> None: def __init__(self) -> None:
@ -165,36 +229,6 @@ async def get_client() -> Client:
yield Client() yield Client()
@dataclass
class OHLC:
"""Description of the flattened OHLC quote format.
For schema details see:
https://docs.kraken.com/websockets/#message-ohlc
"""
chan_id: int # internal kraken id
chan_name: str # eg. ohlc-1 (name-interval)
pair: str # fx pair
time: float # Begin time of interval, in seconds since epoch
etime: float # End time of interval, in seconds since epoch
open: float # Open price of interval
high: float # High price within interval
low: float # Low price within interval
close: float # Close price of interval
vwap: float # Volume weighted average price within interval
volume: float # Accumulated volume **within interval**
count: int # Number of trades within interval
# (sampled) generated tick data
ticks: List[Any] = field(default_factory=list)
# XXX: ugh, super hideous.. needs built-in converters.
def __post_init__(self):
for f, val in self.__dataclass_fields__.items():
if f == 'ticks':
continue
setattr(self, f, val.type(getattr(self, f)))
async def recv_msg(recv): async def recv_msg(recv):
too_slow_count = last_hb = 0 too_slow_count = last_hb = 0
@ -317,8 +351,12 @@ async def stream_quotes(
# keep client cached for real-time section # keep client cached for real-time section
for sym in symbols: for sym in symbols:
si = sym_infos[sym] = await client.symbol_info(sym) si = Pair(**await client.symbol_info(sym)) # validation
ws_pairs[sym] = si['wsname'] syminfo = si.dict()
syminfo['price_tick_size'] = 1/10**si.pair_decimals
syminfo['lot_tick_size'] = 1/10**si.lot_decimals
sym_infos[sym] = syminfo
ws_pairs[sym] = si.wsname
# maybe load historical ohlcv in to shared mem # maybe load historical ohlcv in to shared mem
# check if shm has already been created by previous # check if shm has already been created by previous
@ -349,9 +387,9 @@ async def stream_quotes(
symbol: { symbol: {
'is_shm_writer': not writer_exists, 'is_shm_writer': not writer_exists,
'shm_token': shm_token, 'shm_token': shm_token,
'symbol_info': sym_infos[symbol], 'symbol_info': sym_infos[sym],
} }
for sym in symbols # for sym in symbols
} }
yield init_msgs yield init_msgs

View File

@ -45,6 +45,7 @@ setup(
'attrs', 'attrs',
'pygments', 'pygments',
'colorama', # numba traceback coloring 'colorama', # numba traceback coloring
'pydantic', # structured data
# async # async
'trio', 'trio',