Change `piker symbol-info` -> `mkt-info`

As part of bringing the brokerd agnostic APIs up to date and modernizing
wrapping CLIs, this adds a new sub-cmd to allow more or less directly
calling the `.get_mkt_info()` broker mod endpoint and dumping the both
the backend specific `Pair`-ish and `.accounting.MktPair` normalized
version to console.

Deatz:
- make the click config's `brokermods` entry a `dict`
- make `.brokers.core.mkt_info()` strip the broker name part from the
  input fqme before calling the backend.
basic_buy_bot
Tyler Goodlet 2023-06-12 20:19:18 -04:00
parent cc3037149c
commit b15e736e3e
3 changed files with 76 additions and 24 deletions

View File

@ -21,6 +21,7 @@ import os
from functools import partial from functools import partial
from operator import attrgetter from operator import attrgetter
from operator import itemgetter from operator import itemgetter
from types import ModuleType
import click import click
import trio import trio
@ -241,7 +242,7 @@ def quote(config, tickers):
''' '''
# global opts # global opts
brokermod = config['brokermods'][0] brokermod = list(config['brokermods'].values())[0]
quotes = trio.run(partial(core.stocks_quote, brokermod, tickers)) quotes = trio.run(partial(core.stocks_quote, brokermod, tickers))
if not quotes: if not quotes:
@ -268,7 +269,7 @@ def bars(config, symbol, count):
''' '''
# global opts # global opts
brokermod = config['brokermods'][0] brokermod = list(config['brokermods'].values())[0]
# broker backend should return at the least a # broker backend should return at the least a
# list of candle dictionaries # list of candle dictionaries
@ -303,7 +304,7 @@ def record(config, rate, name, dhost, filename):
''' '''
# global opts # global opts
brokermod = config['brokermods'][0] brokermod = list(config['brokermods'].values())[0]
loglevel = config['loglevel'] loglevel = config['loglevel']
log = config['log'] log = config['log']
@ -368,7 +369,7 @@ def optsquote(config, symbol, date):
''' '''
# global opts # global opts
brokermod = config['brokermods'][0] brokermod = list(config['brokermods'].values())[0]
quotes = trio.run( quotes = trio.run(
partial( partial(
@ -385,26 +386,70 @@ def optsquote(config, symbol, date):
@cli.command() @cli.command()
@click.argument('tickers', nargs=-1, required=True) @click.argument('tickers', nargs=-1, required=True)
@click.pass_obj @click.pass_obj
def symbol_info(config, tickers): def mkt_info(
config: dict,
tickers: list[str],
):
''' '''
Print symbol quotes to the console Print symbol quotes to the console
''' '''
# global opts from msgspec.json import encode, decode
brokermod = config['brokermods'][0] from ..accounting import MktPair
from ..service import (
open_piker_runtime,
)
quotes = trio.run(partial(core.symbol_info, brokermod, tickers)) # global opts
if not quotes: brokermods: dict[str, ModuleType] = config['brokermods']
log.error(f"No quotes could be found for {tickers}?")
mkts: list[MktPair] = []
async def main():
async with open_piker_runtime(
name='mkt_info_query',
# loglevel=loglevel,
# debug_mode=True,
) as (_, _):
for fqme in tickers:
bs_fqme, _, broker = fqme.partition('.')
brokermod: ModuleType = brokermods[broker]
mkt, bs_pair = await core.mkt_info(
brokermod,
bs_fqme,
)
mkts.append((mkt, bs_pair))
trio.run(main)
if not mkts:
log.error(
f'No market info could be found for {tickers}'
)
return return
if len(quotes) < len(tickers): if len(mkts) < len(tickers):
syms = tuple(map(itemgetter('symbol'), quotes)) syms = tuple(map(itemgetter('fqme'), mkts))
for ticker in tickers: for ticker in tickers:
if ticker not in syms: if ticker not in syms:
brokermod.log.warn(f"Could not find symbol {ticker}?") log.warn(f"Could not find symbol {ticker}?")
click.echo(colorize_json(quotes))
# TODO: use ``rich.Table`` intead here!
for mkt, bs_pair in mkts:
click.echo(
'\n'
'----------------------------------------------------\n'
f'{type(bs_pair)}\n'
'----------------------------------------------------\n'
f'{colorize_json(bs_pair.to_dict())}\n'
'----------------------------------------------------\n'
f'as piker `MktPair` with fqme: {mkt.fqme}\n'
'----------------------------------------------------\n'
# NOTE: roundtrip to json codec for console print
f'{colorize_json(decode(encode(mkt)))}'
)
@cli.command() @cli.command()
@ -416,7 +461,7 @@ def search(config, pattern):
''' '''
# global opts # global opts
brokermods = config['brokermods'] brokermods = list(config['brokermods'].values())
# define tractor entrypoint # define tractor entrypoint
async def main(func): async def main(func):

View File

@ -30,6 +30,7 @@ from ._util import log
from . import get_brokermod from . import get_brokermod
from ..service import maybe_spawn_brokerd from ..service import maybe_spawn_brokerd
from .._cacheables import open_cached_client from .._cacheables import open_cached_client
from ..accounting import MktPair
async def api(brokername: str, methname: str, **kwargs) -> dict: async def api(brokername: str, methname: str, **kwargs) -> dict:
@ -116,15 +117,19 @@ async def bars(
return await client.bars(symbol, **kwargs) return await client.bars(symbol, **kwargs)
async def symbol_info( async def mkt_info(
brokermod: ModuleType, brokermod: ModuleType,
symbol: str, fqme: str,
**kwargs, **kwargs,
) -> Dict[str, Dict[str, Dict[str, Any]]]:
"""Return symbol info from broker. ) -> MktPair:
""" '''
async with brokermod.get_client() as client: Return MktPair info from broker including src and dst assets.
return await client.symbol_info(symbol, **kwargs)
'''
return await brokermod.get_mkt_info(
fqme.replace(brokermod.name, '')
)
async def search_w_brokerd(name: str, pattern: str) -> dict: async def search_w_brokerd(name: str, pattern: str) -> dict:

View File

@ -20,6 +20,7 @@ CLI commons.
''' '''
import os import os
from contextlib import AsyncExitStack from contextlib import AsyncExitStack
from types import ModuleType
import click import click
import trio import trio
@ -100,7 +101,6 @@ def pikerd(
registry_addr=reg_addr, registry_addr=reg_addr,
) as service_mngr, # normally delivers a ``Services`` handle ) as service_mngr, # normally delivers a ``Services`` handle
trio.open_nursery() as n,
AsyncExitStack() as stack, AsyncExitStack() as stack,
): ):
@ -163,7 +163,9 @@ def cli(
from piker.brokers import __brokers__ from piker.brokers import __brokers__
brokers = __brokers__ brokers = __brokers__
brokermods = [get_brokermod(broker) for broker in brokers] brokermods: dict[str, ModuleType] = {
broker: get_brokermod(broker) for broker in brokers
}
assert brokermods assert brokermods
reg_addr: None | tuple[str, int] = None reg_addr: None | tuple[str, int] = None