.data.ticktools: add reverse flag, better docs
Since it may be handy to get the latest ticks first, add a `reverse: bool` to `iterticks()` and add some cleaner logic and a proper doc string to `frame_ticks()`.basic_buy_bot
parent
621634b5a2
commit
ea270d3396
|
@ -1,5 +1,5 @@
|
|||
# piker: trading gear for hackers
|
||||
# Copyright (C) Tyler Goodlet (in stewardship for piker0)
|
||||
# Copyright (C) Tyler Goodlet (in stewardship for pikers)
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
|
@ -15,7 +15,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
'''
|
||||
Stream format enforcement.
|
||||
Tick event stream processing, filter-by-types, format-normalization.
|
||||
|
||||
'''
|
||||
from itertools import chain
|
||||
|
@ -40,6 +40,69 @@ _tick_groups: dict[str, set[str]] = {
|
|||
_auction_ticks: set[str] = set.union(*_tick_groups.values())
|
||||
|
||||
|
||||
def frame_ticks(
|
||||
quote: dict[str, Any],
|
||||
|
||||
ticks_by_type: dict | None = None,
|
||||
ticks_in_order: list[dict[str, Any]] | None = None
|
||||
|
||||
) -> dict[
|
||||
str,
|
||||
list[dict[str, Any]]
|
||||
]:
|
||||
'''
|
||||
XXX: build a tick-by-type table of lists
|
||||
of tick messages. This allows for less
|
||||
iteration on the receiver side by allowing for
|
||||
a single "latest tick event" look up by
|
||||
indexing the last entry in each sub-list.
|
||||
|
||||
tbt = {
|
||||
'types': ['bid', 'asize', 'last', .. '<type_n>'],
|
||||
|
||||
'bid': [tick0, tick1, tick2, .., tickn],
|
||||
'asize': [tick0, tick1, tick2, .., tickn],
|
||||
'last': [tick0, tick1, tick2, .., tickn],
|
||||
...
|
||||
'<type_n>': [tick0, tick1, tick2, .., tickn],
|
||||
}
|
||||
|
||||
If `ticks_in_order` is provided, append any retrieved ticks
|
||||
since last iteration into this array/buffer/list.
|
||||
|
||||
'''
|
||||
# TODO: once we decide to get fancy really we should
|
||||
# have a shared mem tick buffer that is just
|
||||
# continually filled and the UI just ready from it
|
||||
# at it's display rate.
|
||||
|
||||
tbt = ticks_by_type if ticks_by_type is not None else {}
|
||||
if not (ticks := quote.get('ticks')):
|
||||
return tbt
|
||||
|
||||
# append in reverse FIFO order for in-order iteration on
|
||||
# receiver side.
|
||||
tick: dict[str, Any]
|
||||
for tick in ticks:
|
||||
tbt.setdefault(
|
||||
tick['type'],
|
||||
[],
|
||||
).append(tick)
|
||||
|
||||
# TODO: do we need this any more or can we just
|
||||
# expect the receiver to unwind the below
|
||||
# `ticks_by_type: dict`?
|
||||
# => undwinding would potentially require a
|
||||
# `dict[str, set | list]` instead with an
|
||||
# included `'types' field which is an (ordered)
|
||||
# set of tick type fields in the order which
|
||||
# types arrived?
|
||||
if ticks_in_order:
|
||||
ticks_in_order.extend(ticks)
|
||||
|
||||
return tbt
|
||||
|
||||
|
||||
def iterticks(
|
||||
quote: dict,
|
||||
types: tuple[str] = (
|
||||
|
@ -47,10 +110,16 @@ def iterticks(
|
|||
'dark_trade',
|
||||
),
|
||||
deduplicate_darks: bool = False,
|
||||
reverse: bool = False,
|
||||
|
||||
# TODO: should we offer delegating to `frame_ticks()` above
|
||||
# with this?
|
||||
frame_by_type: bool = False,
|
||||
|
||||
) -> AsyncIterator:
|
||||
'''
|
||||
Iterate through ticks delivered per quote cycle.
|
||||
Iterate through ticks delivered per quote cycle, filter and
|
||||
yield any declared in `types`.
|
||||
|
||||
'''
|
||||
if deduplicate_darks:
|
||||
|
@ -93,63 +162,12 @@ def iterticks(
|
|||
# re-insert ticks
|
||||
ticks.extend(list(chain(trades.values(), darks.values())))
|
||||
|
||||
# most-recent-first
|
||||
if reverse:
|
||||
ticks = reversed(ticks)
|
||||
|
||||
for tick in ticks:
|
||||
# print(f"{quote['symbol']}: {tick}")
|
||||
ttype = tick.get('type')
|
||||
if ttype in types:
|
||||
yield tick
|
||||
|
||||
|
||||
def frame_ticks(
|
||||
quote: dict[str, Any],
|
||||
|
||||
ticks_by_type: dict[str, list[dict[str, Any]]] = {},
|
||||
ticks_in_order: list[dict[str, Any]] | None = None
|
||||
|
||||
) -> dict:
|
||||
|
||||
# append quotes since last iteration into the last quote's
|
||||
# tick array/buffer.
|
||||
# TODO: once we decide to get fancy really we should
|
||||
# have a shared mem tick buffer that is just
|
||||
# continually filled and the UI just ready from it
|
||||
# at it's display rate.
|
||||
|
||||
if ticks := quote.get('ticks'):
|
||||
|
||||
# XXX: build a tick-by-type table of lists
|
||||
# of tick messages. This allows for less
|
||||
# iteration on the receiver side by allowing for
|
||||
# a single "latest tick event" look up by
|
||||
# indexing the last entry in each sub-list.
|
||||
# tbt = {
|
||||
# 'types': ['bid', 'asize', 'last', .. '<type_n>'],
|
||||
|
||||
# 'bid': [tick0, tick1, tick2, .., tickn],
|
||||
# 'asize': [tick0, tick1, tick2, .., tickn],
|
||||
# 'last': [tick0, tick1, tick2, .., tickn],
|
||||
# ...
|
||||
# '<type_n>': [tick0, tick1, tick2, .., tickn],
|
||||
# }
|
||||
|
||||
# append in reverse FIFO order for in-order iteration on
|
||||
# receiver side.
|
||||
tick: dict[str, Any]
|
||||
for tick in ticks:
|
||||
ticks_by_type.setdefault(
|
||||
tick['type'],
|
||||
[],
|
||||
).append(tick)
|
||||
|
||||
# TODO: do we need this any more or can we just
|
||||
# expect the receiver to unwind the below
|
||||
# `ticks_by_type: dict`?
|
||||
# => undwinding would potentially require a
|
||||
# `dict[str, set | list]` instead with an
|
||||
# included `'types' field which is an (ordered)
|
||||
# set of tick type fields in the order which
|
||||
# types arrived?
|
||||
if ticks_in_order:
|
||||
ticks_in_order.extend(ticks)
|
||||
|
||||
return ticks_by_type
|
||||
|
|
Loading…
Reference in New Issue