Add `Client.search_symbols()` to all backends, use it in `piker search`
parent
c56c7b8540
commit
7fa9f3f542
|
@ -142,8 +142,14 @@ async def maybe_open_runtime(
|
||||||
Start the ``tractor`` runtime (a root actor) if none exists.
|
Start the ``tractor`` runtime (a root actor) if none exists.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
settings = _tractor_kwargs
|
||||||
|
settings.update(kwargs)
|
||||||
|
|
||||||
if not tractor.current_actor(err_on_no_runtime=False):
|
if not tractor.current_actor(err_on_no_runtime=False):
|
||||||
async with tractor.open_root_actor(loglevel=loglevel, **kwargs):
|
async with tractor.open_root_actor(
|
||||||
|
loglevel=loglevel,
|
||||||
|
**settings,
|
||||||
|
):
|
||||||
yield
|
yield
|
||||||
else:
|
else:
|
||||||
yield
|
yield
|
||||||
|
|
|
@ -207,6 +207,25 @@ class Client:
|
||||||
|
|
||||||
return self._pairs
|
return self._pairs
|
||||||
|
|
||||||
|
async def search_symbols(
|
||||||
|
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]['symbol']: item[0]
|
||||||
|
for item in matches}
|
||||||
|
|
||||||
async def bars(
|
async def bars(
|
||||||
self,
|
self,
|
||||||
symbol: str,
|
symbol: str,
|
||||||
|
|
|
@ -30,7 +30,7 @@ import tractor
|
||||||
from ..cli import cli
|
from ..cli import cli
|
||||||
from .. import watchlists as wl
|
from .. import watchlists as wl
|
||||||
from ..log import get_console_log, colorize_json, get_logger
|
from ..log import get_console_log, colorize_json, get_logger
|
||||||
from .._daemon import maybe_spawn_brokerd
|
from .._daemon import maybe_spawn_brokerd, maybe_open_pikerd
|
||||||
from ..brokers import core, get_brokermod, data
|
from ..brokers import core, get_brokermod, data
|
||||||
|
|
||||||
log = get_logger('cli')
|
log = get_logger('cli')
|
||||||
|
@ -273,13 +273,25 @@ def search(config, pattern):
|
||||||
"""Search for symbols from broker backend(s).
|
"""Search for symbols from broker backend(s).
|
||||||
"""
|
"""
|
||||||
# global opts
|
# global opts
|
||||||
brokermod = config['brokermods'][0]
|
brokermods = config['brokermods']
|
||||||
|
|
||||||
quotes = tractor.run(
|
# define tractor entrypoint
|
||||||
partial(core.symbol_search, brokermod, pattern),
|
async def main(func):
|
||||||
start_method='forkserver',
|
|
||||||
loglevel='info',
|
async with maybe_open_pikerd(
|
||||||
|
loglevel=config['loglevel'],
|
||||||
|
):
|
||||||
|
return await func()
|
||||||
|
|
||||||
|
quotes = trio.run(
|
||||||
|
main,
|
||||||
|
partial(
|
||||||
|
core.symbol_search,
|
||||||
|
brokermods,
|
||||||
|
pattern,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if not quotes:
|
if not quotes:
|
||||||
log.error(f"No matches could be found for {pattern}?")
|
log.error(f"No matches could be found for {pattern}?")
|
||||||
return
|
return
|
||||||
|
|
|
@ -24,8 +24,12 @@ import inspect
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
|
import trio
|
||||||
|
|
||||||
from ..log import get_logger
|
from ..log import get_logger
|
||||||
from . import get_brokermod
|
from . import get_brokermod
|
||||||
|
from .._daemon import maybe_spawn_brokerd
|
||||||
|
from .api import open_cached_client
|
||||||
|
|
||||||
|
|
||||||
log = get_logger(__name__)
|
log = get_logger(__name__)
|
||||||
|
@ -126,13 +130,41 @@ async def symbol_info(
|
||||||
return await client.symbol_info(symbol, **kwargs)
|
return await client.symbol_info(symbol, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
async def search_w_brokerd(name: str, pattern: str) -> dict:
|
||||||
|
|
||||||
|
async with open_cached_client(name) as client:
|
||||||
|
|
||||||
|
# TODO: support multiple asset type concurrent searches.
|
||||||
|
return await client.search_symbols(pattern=pattern)
|
||||||
|
|
||||||
|
|
||||||
async def symbol_search(
|
async def symbol_search(
|
||||||
brokermod: ModuleType,
|
brokermods: list[ModuleType],
|
||||||
pattern: str,
|
pattern: str,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> Dict[str, Dict[str, Dict[str, Any]]]:
|
) -> Dict[str, Dict[str, Dict[str, Any]]]:
|
||||||
"""Return symbol info from broker.
|
"""Return symbol info from broker.
|
||||||
"""
|
"""
|
||||||
async with brokermod.get_client() as client:
|
results = []
|
||||||
# TODO: support multiple asset type concurrent searches.
|
|
||||||
return await client.search_stocks(pattern=pattern, **kwargs)
|
async def search_backend(brokername: str) -> None:
|
||||||
|
|
||||||
|
async with maybe_spawn_brokerd(
|
||||||
|
brokername,
|
||||||
|
) as portal:
|
||||||
|
|
||||||
|
results.append((
|
||||||
|
brokername,
|
||||||
|
await portal.run(
|
||||||
|
search_w_brokerd,
|
||||||
|
name=brokername,
|
||||||
|
pattern=pattern,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
|
||||||
|
async with trio.open_nursery() as n:
|
||||||
|
|
||||||
|
for mod in brokermods:
|
||||||
|
n.start_soon(search_backend, mod.name)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
|
@ -52,7 +52,7 @@ from ..log import get_logger, get_console_log
|
||||||
from .._daemon import maybe_spawn_brokerd
|
from .._daemon import maybe_spawn_brokerd
|
||||||
from ..data._source import from_df
|
from ..data._source import from_df
|
||||||
from ..data._sharedmem import ShmArray
|
from ..data._sharedmem import ShmArray
|
||||||
from ._util import SymbolNotFound
|
from ._util import SymbolNotFound, NoData
|
||||||
|
|
||||||
|
|
||||||
log = get_logger(__name__)
|
log = get_logger(__name__)
|
||||||
|
@ -311,6 +311,18 @@ class Client:
|
||||||
else:
|
else:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
async def search_symbols(
|
||||||
|
self,
|
||||||
|
pattern: str,
|
||||||
|
# how many contracts to search "up to"
|
||||||
|
upto: int = 3,
|
||||||
|
asdicts: bool = True,
|
||||||
|
) -> Dict[str, ContractDetails]:
|
||||||
|
|
||||||
|
# TODO add search though our adhoc-locally defined symbol set
|
||||||
|
# for futes/cmdtys/
|
||||||
|
return await self.search_stocks(pattern, upto, asdicts)
|
||||||
|
|
||||||
async def search_futes(
|
async def search_futes(
|
||||||
self,
|
self,
|
||||||
pattern: str,
|
pattern: str,
|
||||||
|
@ -862,6 +874,13 @@ async def get_bars(
|
||||||
# throttling despite the rps being low
|
# throttling despite the rps being low
|
||||||
break
|
break
|
||||||
|
|
||||||
|
elif 'No market data permissions for' in err.message:
|
||||||
|
|
||||||
|
# TODO: signalling for no permissions searches
|
||||||
|
raise NoData(f'Symbol: {sym}')
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
log.exception(
|
log.exception(
|
||||||
"Data query rate reached: Press `ctrl-alt-f`"
|
"Data query rate reached: Press `ctrl-alt-f`"
|
||||||
|
@ -1133,8 +1152,10 @@ async def stream_quotes(
|
||||||
# tell caller quotes are now coming in live
|
# tell caller quotes are now coming in live
|
||||||
feed_is_live.set()
|
feed_is_live.set()
|
||||||
|
|
||||||
|
# last = time.time()
|
||||||
async with aclosing(stream):
|
async with aclosing(stream):
|
||||||
async for ticker in stream:
|
async for ticker in stream:
|
||||||
|
# print(f'ticker rate: {1/(time.time() - last)}')
|
||||||
|
|
||||||
# print(ticker.vwap)
|
# print(ticker.vwap)
|
||||||
quote = normalize(
|
quote = normalize(
|
||||||
|
@ -1149,6 +1170,7 @@ async def stream_quotes(
|
||||||
|
|
||||||
# ugh, clear ticks since we've consumed them
|
# ugh, clear ticks since we've consumed them
|
||||||
ticker.ticks = []
|
ticker.ticks = []
|
||||||
|
# last = time.time()
|
||||||
|
|
||||||
|
|
||||||
def pack_position(pos: Position) -> Dict[str, Any]:
|
def pack_position(pos: Position) -> Dict[str, Any]:
|
||||||
|
|
|
@ -207,7 +207,7 @@ class Client:
|
||||||
|
|
||||||
return self._pairs
|
return self._pairs
|
||||||
|
|
||||||
async def search_stocks(
|
async def search_symbols(
|
||||||
self,
|
self,
|
||||||
pattern: str,
|
pattern: str,
|
||||||
limit: int = None,
|
limit: int = None,
|
||||||
|
|
|
@ -628,7 +628,7 @@ class Client:
|
||||||
f"Took {time.time() - start} seconds to retreive {len(bars)} bars")
|
f"Took {time.time() - start} seconds to retreive {len(bars)} bars")
|
||||||
return bars
|
return bars
|
||||||
|
|
||||||
async def search_stocks(
|
async def search_symbols(
|
||||||
self,
|
self,
|
||||||
pattern: str,
|
pattern: str,
|
||||||
# how many contracts to return
|
# how many contracts to return
|
||||||
|
|
Loading…
Reference in New Issue