Deliver and utilise broker backend OHLC sample rate in init msg

cached_feeds
Tyler Goodlet 2021-04-03 01:23:18 -04:00
parent c05fc8991a
commit ce4144aace
1 changed files with 49 additions and 25 deletions

View File

@ -53,9 +53,10 @@ from ._sharedmem import (
) )
from ._source import base_iohlc_dtype, Symbol from ._source import base_iohlc_dtype, Symbol
from ._buffer import ( from ._buffer import (
_shms,
_incrementers,
increment_ohlc_buffer, increment_ohlc_buffer,
subscribe_ohlc_for_increment, iter_ohlc_periods,
shm_incrementing,
) )
__all__ = [ __all__ = [
@ -64,7 +65,7 @@ __all__ = [
'attach_shm_array', 'attach_shm_array',
'open_shm_array', 'open_shm_array',
'get_shm_token', 'get_shm_token',
'subscribe_ohlc_for_increment', # 'subscribe_ohlc_for_increment',
] ]
@ -181,10 +182,10 @@ async def allocate_persistent_feed(
readonly=False, readonly=False,
) )
# assert opened # do history validation?
if not opened: assert opened, "Persistent shm for sym was already open?!"
# do history validation? # if not opened:
pass # raise RuntimeError("Persistent shm for sym was already open?!")
send, quote_stream = trio.open_memory_channel(2**8) send, quote_stream = trio.open_memory_channel(2**8)
feed_is_live = trio.Event() feed_is_live = trio.Event()
@ -204,34 +205,48 @@ async def allocate_persistent_feed(
init_msg[symbol]['shm_token'] = shm.token init_msg[symbol]['shm_token'] = shm.token
cs = trio.CancelScope() cs = trio.CancelScope()
# TODO: make this into a composed type which also
# contains the backfiller cs for individual super-based
# resspawns when needed.
bus.feeds[symbol] = (cs, init_msg, first_quote) bus.feeds[symbol] = (cs, init_msg, first_quote)
with cs: with cs:
if opened: if opened:
# start history backfill task
# ``backfill_bars()`` is a required backend func
await bus.nursery.start(mod.backfill_bars, symbol, shm)
# yield back control to starting nursery # start history backfill task ``backfill_bars()`` is
task_status.started((init_msg, first_quote)) # a required backend func this must block until shm is
# filled with first set of ohlc bars
await bus.nursery.start(mod.backfill_bars, symbol, shm)
times = shm.array['time'] times = shm.array['time']
delay_s = times[-1] - times[times != times[-1]][-1] delay_s = times[-1] - times[times != times[-1]][-1]
# pass OHLC sample rate in seconds
init_msg[symbol]['sample_rate'] = delay_s
# yield back control to starting nursery
task_status.started((init_msg, first_quote))
await feed_is_live.wait() await feed_is_live.wait()
# tell incrementer task it can start # # tell incrementer task it can start
shm_incrementing(shm.token['shm_name']).set() # shm_incrementing(shm.token['shm_name']).set()
# start shm incrementingn for OHLC sampling # start shm incrementingn for OHLC sampling
subscribe_ohlc_for_increment(shm, delay_s) # subscribe_ohlc_for_increment(shm, delay_s)
# begin shm write loop and broadcast to subscribers if opened:
_shms.setdefault(delay_s, []).append(shm)
if _incrementers.get(delay_s) is None:
cs = await bus.nursery.start(increment_ohlc_buffer, delay_s)
sum_tick_vlm: bool = init_msg.get( sum_tick_vlm: bool = init_msg.get(
'shm_write_opts', {} 'shm_write_opts', {}
).get('sum_tick_vlm', True) ).get('sum_tick_vlm', True)
# begin shm write loop and broadcast to subscribers
async with quote_stream: async with quote_stream:
log.info("Started shared mem bar writer") log.info("Started shared mem bar writer")
@ -372,6 +387,7 @@ class Feed:
_brokerd_portal: tractor._portal.Portal _brokerd_portal: tractor._portal.Portal
_index_stream: Optional[AsyncIterator[int]] = None _index_stream: Optional[AsyncIterator[int]] = None
_trade_stream: Optional[AsyncIterator[Dict[str, Any]]] = None _trade_stream: Optional[AsyncIterator[Dict[str, Any]]] = None
_max_sample_rate: int = 0
# cache of symbol info messages received as first message when # cache of symbol info messages received as first message when
# a stream startsc. # a stream startsc.
@ -380,15 +396,19 @@ class Feed:
async def receive(self) -> dict: async def receive(self) -> dict:
return await self.stream.__anext__() return await self.stream.__anext__()
async def index_stream(self) -> AsyncIterator[int]: async def index_stream(
self,
delay_s: Optional[int] = None
) -> AsyncIterator[int]:
if not self._index_stream: if not self._index_stream:
# XXX: this should be singleton on a host, # XXX: this should be singleton on a host,
# a lone broker-daemon per provider should be # a lone broker-daemon per provider should be
# created for all practical purposes # created for all practical purposes
self._index_stream = await self._brokerd_portal.run( self._index_stream = await self._brokerd_portal.run(
increment_ohlc_buffer, iter_ohlc_periods,
shm_token=self.shm.token, delay_s=delay_s or self._max_sample_rate,
topics=['index'],
) )
return self._index_stream return self._index_stream
@ -459,9 +479,9 @@ async def open_feed(
loglevel=loglevel, loglevel=loglevel,
) )
# TODO: we can't do this **and** be compate with # TODO: can we make this work better with the proposed
# ``tractor.msg.pub``, should we maybe just drop this after # context based bidirectional streaming style api proposed in:
# tests are in? # https://github.com/goodboy/tractor/issues/53
init_msg = await stream.receive() init_msg = await stream.receive()
shm = attach_shm_array( shm = attach_shm_array(
@ -478,10 +498,12 @@ async def open_feed(
mod=mod, mod=mod,
_brokerd_portal=portal, _brokerd_portal=portal,
) )
ohlc_sample_rates = []
for sym, data in init_msg.items(): for sym, data in init_msg.items():
si = data['symbol_info'] si = data['symbol_info']
ohlc_sample_rates.append(data['sample_rate'])
symbol = Symbol( symbol = Symbol(
key=sym, key=sym,
@ -493,9 +515,11 @@ async def open_feed(
feed.symbols[sym] = symbol feed.symbols[sym] = symbol
# cast shm dtype to list... can't member why we need this
shm_token = data['shm_token'] shm_token = data['shm_token']
shm_token['dtype_descr'] = list(shm_token['dtype_descr'])
assert shm_token == shm.token # sanity
shm_token['dtype_descr'] = list(shm_token['dtype_descr']) feed._max_sample_rate = max(ohlc_sample_rates)
assert shm_token == shm.token # sanity
yield feed yield feed