You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
57 lines
1.8 KiB
57 lines
1.8 KiB
""" In-memory fast temporary storage
|
|
"""
|
|
import bisect
|
|
from collections import defaultdict, deque
|
|
from time import monotonic
|
|
from typing import List
|
|
|
|
|
|
class Quote:
|
|
""" How much something costs at which time since the process started
|
|
"""
|
|
__slots__ = ["time", "price"]
|
|
|
|
def __init__(self, time: float, price: float):
|
|
self.time = time
|
|
self.price = price
|
|
|
|
|
|
class MemStorage:
|
|
""" In-memory storage and notifier class
|
|
"""
|
|
def __init__(self):
|
|
# FIFO queue where old records get discarded
|
|
self.__time_ordered_queues = defaultdict(deque)
|
|
# Discarded records get looked up in an ordered list with O(log(n)) and value is removed
|
|
# ordered list is maintained ordered
|
|
self.__value_ordered_lists = defaultdict(list)
|
|
# we remember what's hot
|
|
self.__hot_stuff = set()
|
|
|
|
def notify_hot(self, isin: str):
|
|
""" Symbol isin is "hot". Send real-time notifications
|
|
"""
|
|
|
|
def process_quote(self, isin: str, price=float):
|
|
""" Fast in-memory storage of values
|
|
"""
|
|
now = monotonic()
|
|
q: deque[Quote] = self.__time_ordered_queues[isin]
|
|
ol: List[float] = self.__value_ordered_lists[isin]
|
|
while now - q[0].time > 600:
|
|
item = q.popleft()
|
|
index = bisect.bisect_left(ol, item.price)
|
|
ol.pop(index)
|
|
q.append(Quote(now, price))
|
|
insert_at = bisect.bisect_left(ol, price)
|
|
ol.insert(insert_at, price)
|
|
|
|
min_val = ol[0]
|
|
max_val = ol[-1]
|
|
is_hot = (max_val - min_val) / min_val > 0.1
|
|
if is_hot and isin not in self.__hot_stuff:
|
|
self.__hot_stuff.add(isin)
|
|
self.notify_hot(isin)
|
|
elif not is_hot and isin in self.__hot_stuff:
|
|
self.__hot_stuff.remove(isin)
|