import logging from typing import Optional, Any, cast, List from pathlib import Path from storage import Book, BookSnapshot from models import MetricCalculator, Metric from repositories.sqlite_metrics_repository import SQLiteMetricsRepository class DefaultStrategy: """Strategy that calculates and analyzes OBI and CVD metrics from stored data.""" def __init__(self, instrument: str): self.instrument = instrument self._db_path: Optional[Path] = None def set_db_path(self, db_path: Path) -> None: """Set the database path for loading stored metrics.""" self._db_path = db_path def compute_OBI(self, book: Book) -> List[float]: """Compute Order Book Imbalance using MetricCalculator. Returns: list: A list of OBI values, one for each snapshot in the book. """ if not book.snapshots: return [] obi_values = [] for snapshot in book.snapshots: obi = MetricCalculator.calculate_obi(snapshot) obi_values.append(obi) return obi_values def load_stored_metrics(self, start_timestamp: int, end_timestamp: int) -> List[Metric]: """Load stored OBI and CVD metrics from database. Args: start_timestamp: Start of time range to load. end_timestamp: End of time range to load. Returns: List of Metric objects with OBI and CVD data. """ if not self._db_path: logging.warning("Database path not set, cannot load stored metrics") return [] try: metrics_repo = SQLiteMetricsRepository(self._db_path) with metrics_repo.connect() as conn: return metrics_repo.load_metrics_by_timerange(conn, start_timestamp, end_timestamp) except Exception as e: logging.error(f"Error loading stored metrics: {e}") return [] def get_metrics_summary(self, metrics: List[Metric]) -> dict: """Get summary statistics for loaded metrics. Args: metrics: List of metric objects. Returns: Dictionary with summary statistics. """ if not metrics: return {} obi_values = [m.obi for m in metrics] cvd_values = [m.cvd for m in metrics] return { "obi_min": min(obi_values), "obi_max": max(obi_values), "obi_avg": sum(obi_values) / len(obi_values), "cvd_start": cvd_values[0], "cvd_end": cvd_values[-1], "cvd_change": cvd_values[-1] - cvd_values[0], "total_snapshots": len(metrics) } def on_booktick(self, book: Book): """Hook called on each book tick; can load and analyze stored metrics.""" # Load stored metrics if database path is available if self._db_path and book.first_timestamp and book.last_timestamp: metrics = self.load_stored_metrics(book.first_timestamp, book.last_timestamp) if metrics: # Analyze stored metrics summary = self.get_metrics_summary(metrics) logging.info(f"Metrics summary: {summary}") # Check for significant imbalances using stored OBI latest_metric = metrics[-1] if abs(latest_metric.obi) > 0.2: # 20% imbalance threshold logging.info(f"Significant imbalance detected: OBI={latest_metric.obi:.3f}, CVD={latest_metric.cvd:.1f}") else: # Fallback to real-time calculation for compatibility obi_values = self.compute_OBI(book) if obi_values: latest_obi = obi_values[-1] if abs(latest_obi) > 0.2: logging.info(f"Significant imbalance detected: {latest_obi:.3f}")