Add kraken fuzzy symbol search

symbol_search
Tyler Goodlet 2021-04-22 21:23:43 -04:00
parent 157f6ab02b
commit c26f4d9877
1 changed files with 62 additions and 11 deletions

View File

@ -21,7 +21,7 @@ Kraken backend.
from contextlib import asynccontextmanager, AsyncExitStack from contextlib import asynccontextmanager, AsyncExitStack
from dataclasses import asdict, field from dataclasses import asdict, field
from types import ModuleType from types import ModuleType
from typing import List, Dict, Any, Tuple from typing import List, Dict, Any, Tuple, Optional
import json import json
import time import time
@ -37,6 +37,7 @@ from trio_websocket._impl import (
import arrow import arrow
import asks import asks
from fuzzywuzzy import process as fuzzy
import numpy as np import numpy as np
import trio import trio
import tractor import tractor
@ -147,6 +148,17 @@ class Client:
'User-Agent': 'User-Agent':
'krakenex/2.1.0 (+https://github.com/veox/python3-krakenex)' 'krakenex/2.1.0 (+https://github.com/veox/python3-krakenex)'
}) })
self._pairs = None
@property
def pairs(self) -> Dict[str, Any]:
if self._pairs is None:
raise RuntimeError(
"Make sure to run `cache_symbols()` on startup!"
)
# retreive and cache all symbols
return self._pairs
async def _public( async def _public(
self, self,
@ -162,14 +174,48 @@ class Client:
async def symbol_info( async def symbol_info(
self, self,
pair: str = 'all', pair: Optional[str] = None,
): ):
resp = await self._public('AssetPairs', {'pair': pair}) if pair is not None:
pairs = {'pair': pair}
else:
pairs = None # get all pairs
resp = await self._public('AssetPairs', pairs)
err = resp['error'] err = resp['error']
if err: if err:
raise BrokerError(err) raise BrokerError(err)
true_pair_key, data = next(iter(resp['result'].items()))
pairs = resp['result']
if pair is not None:
_, data = next(iter(pairs.items()))
return data return data
else:
return pairs
async def cache_symbols(
self,
) -> None:
self._pairs = await self.symbol_info()
async def search_stocks(
self,
pattern: str,
limit: int = None,
) -> Dict[str, Any]:
if self._pairs is not None:
data = self._pairs
else:
data = await self.symbol_info()
matches = fuzzy.extractBests(
pattern,
data,
score_cutoff=50,
)
# repack in dict form
return {item[0]['altname']: item[0] for item in matches}
async def bars( async def bars(
self, self,
@ -232,7 +278,9 @@ class Client:
@asynccontextmanager @asynccontextmanager
async def get_client() -> Client: async def get_client() -> Client:
yield Client() client = Client()
await client.cache_symbols()
yield client
async def stream_messages(ws): async def stream_messages(ws):
@ -249,7 +297,7 @@ async def stream_messages(ws):
too_slow_count += 1 too_slow_count += 1
if too_slow_count > 10: if too_slow_count > 20:
log.warning( log.warning(
"Heartbeat is too slow, resetting ws connection") "Heartbeat is too slow, resetting ws connection")
@ -368,10 +416,13 @@ class AutoReconWs:
self, self,
tries: int = 10000, tries: int = 10000,
) -> None: ) -> None:
while True:
try: try:
await self._stack.aclose() await self._stack.aclose()
except (DisconnectionTimeout, RuntimeError): except (DisconnectionTimeout, RuntimeError):
await trio.sleep(1) await trio.sleep(1)
else:
break
last_err = None last_err = None
for i in range(tries): for i in range(tries):