chart/app/runtime.py

42 lines
1.6 KiB
Python

import asyncio
from dataclasses import dataclass, field
from app.bars.models import Bar, Timeframe
from app.bars.aggregator import Aggregator
from app.bars.store import InMemoryBarStore
from app.config import Settings
from app.market.factory import live_source, seed_source
from app.market.stream import StreamService
@dataclass
class Runtime:
settings: Settings
store: InMemoryBarStore = field(init=False)
stream: StreamService = field(init=False)
subscribers: set[asyncio.Queue[Bar]] = field(default_factory=set)
aggregator: Aggregator = field(init=False)
def __post_init__(self) -> None:
self.store = InMemoryBarStore(self.settings.max_bars_per_tf)
self.aggregator = Aggregator(self.settings.enabled_timeframes)
self.stream = StreamService(live_source(self.settings), self.settings.yahoo_symbol)
self.stream.add_handler(self.on_bar)
async def on_bar(self, bar: Bar) -> None:
for aggregated in self.aggregator.update(bar):
self.store.put(aggregated)
for queue in self.subscribers.copy():
if queue.full():
queue.get_nowait()
queue.put_nowait(aggregated)
async def start(self) -> asyncio.Task:
try:
source = seed_source(self.settings)
await self.stream.seed(source, Timeframe.H1, self.settings.seed_1h_range)
await self.stream.seed(source, Timeframe.M1, self.settings.seed_1m_range)
except Exception:
# A transient seed failure must not prevent the live stream or UI starting.
pass
return asyncio.create_task(self.stream.run(), name="market-stream")