from __future__ import annotations import math from collections.abc import Sequence from app.market.base import MarketData from app.schemas import Candle class FakeMarketData(MarketData): """In-memory market data for tests and offline demos.""" def __init__(self, candles: Sequence[Candle] | None = None) -> None: self.candles: list[Candle] = list(candles or []) @classmethod def from_closes(cls, closes: Sequence[float]) -> FakeMarketData: candles = [ Candle( ts=1_700_000_000_000 + i * 60_000, open=close, high=close, low=close, close=close, volume=1.0, ) for i, close in enumerate(closes) ] return cls(candles) @classmethod def sine_wave(cls, n: int = 200, amplitude: float = 100.0, period: int = 20) -> FakeMarketData: base = 1000.0 closes = [base + amplitude * math.sin(2 * math.pi * i / period) for i in range(n)] return cls.from_closes(closes) def append(self, candle: Candle) -> None: self.candles.append(candle) async def fetch_candles(self, symbol: str, timeframe: str, limit: int) -> list[Candle]: return self.candles[-limit:] async def fetch_price(self, symbol: str) -> float: if not self.candles: raise ValueError("no candles available") return self.candles[-1].close