Add quote polling; pseudo-streaming

Add a ``poll_tickers`` coro which can be used to "stream" quotes at
a requested rate. Expose through a cli subcommand `piker stream`.
Drop the `pikerd` command for now.
kivy_mainline_and_py3.8
Tyler Goodlet 2018-01-29 12:45:48 -05:00
parent 42ec8330f1
commit 797efedf6a
3 changed files with 46 additions and 12 deletions

View File

@ -1,7 +1,6 @@
"""
Console interface to broker client/daemons.
"""
import json
from functools import partial
from importlib import import_module
@ -23,15 +22,6 @@ def run(main, loglevel='info'):
log.debug("Exiting piker")
@click.command()
@click.option('--broker', default='questrade', help='Broker backend to use')
@click.option('--loglevel', '-l', default='info', help='Logging level')
def pikerd(broker, loglevel):
# import broker module daemon entry point
brokermod = import_module('.' + broker, 'piker.brokers')
run(brokermod.serve_forever, loglevel)
@click.group()
def cli():
pass
@ -59,3 +49,18 @@ def api(meth, kwargs, loglevel, broker):
data = run(partial(brokermod.api, meth, **_kwargs), loglevel=loglevel)
if data:
click.echo(colorize_json(data))
@cli.command()
@click.option('--broker', default='questrade', help='Broker backend to use')
@click.option('--loglevel', '-l', default='info', help='Logging level')
@click.argument('tickers', nargs=-1)
def stream(broker, loglevel, tickers):
# import broker module daemon entry point
bm = import_module('.' + broker, 'piker.brokers')
run(
partial(bm.serve_forever, [
partial(bm.poll_tickers, tickers=tickers)
]),
loglevel
)

View File

@ -140,6 +140,17 @@ class Client:
self._prep_sess()
return self.access_data
async def tickers2ids(self, tickers):
"""Helper routine that take a sequence of ticker symbols and returns
their corresponding QT symbol ids.
"""
data = await self.api.symbols(names=','.join(tickers))
symbols2ids = {}
for ticker, symbol in zip(tickers, data['symbols']):
symbols2ids[symbol['symbol']] = symbol['symbolId']
return symbols2ids
class API:
"""Questrade API at its finest.
@ -234,15 +245,34 @@ async def get_client() -> Client:
write_conf(client)
async def serve_forever() -> None:
async def serve_forever(tasks) -> None:
"""Start up a client and serve until terminated.
"""
async with get_client() as client:
# pretty sure this doesn't work
# await client._revoke_auth_token()
async with trio.open_nursery() as nursery:
# launch token manager
nursery.start_soon(token_refresher, client)
# launch children
for task in tasks:
nursery.start_soon(task, client)
async def poll_tickers(client, tickers, rate=2):
"""Auto-poll snap quotes for a sequence of tickers at the given ``rate``
per second.
"""
t2ids = await client.tickers2ids(tickers)
sleeptime = 1. / rate
ids = ','.join(map(str, t2ids.values()))
while True: # use an event here to trigger exit?
quote_data = await client.api.quotes(ids=ids)
await trio.sleep(sleeptime)
async def api(methname, **kwargs) -> dict:
"""Make (proxy) through an api call by name and return its result.

View File

@ -28,7 +28,6 @@ setup(
],
entry_points={
'console_scripts': [
'pikerd = piker.brokers.cli:pikerd',
'piker = piker.brokers.cli:cli',
]
},