Add kraken fuzzy symbol search
parent
157f6ab02b
commit
c26f4d9877
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue