""" Indicators Data Fetcher A standalone process that runs in a loop to compute financial indicators (ratios, prices, MAs, RSI, custom) from SQLite candle data and save the results to a JSON status file for the main dashboard to display. Follows the same pattern as dashboard_data_fetcher.py. """ import logging import os import sys import json import time import argparse from datetime import datetime, timezone from logging_utils import setup_logging from indicators import IndicatorCalculator class IndicatorsFetcher: """ Periodically computes all configured indicators and saves them to a JSON file. """ def __init__(self, log_level: str): setup_logging(log_level, 'IndicatorsFetcher') project_root = os.path.dirname(os.path.abspath(__file__)) self.db_path = os.environ.get("PG_CONN_STR", "postgresql://hyper:hyper@localhost:5432/hyper") self.config_path = os.path.join(project_root, "_data", "indicators.json") self.status_file_path = os.path.join(project_root, "_logs", "indicators_status.json") self.calculator = IndicatorCalculator( config_path=self.config_path, db_path=self.db_path ) logging.info(f"Indicators Fetcher initialized. DB: {self.db_path}, Config: {self.config_path}") def fetch_and_save_indicators(self): """Compute all indicators and save to JSON status file.""" try: results = self.calculator.calculate_all() status = { "last_updated_utc": datetime.now(timezone.utc).isoformat(), "indicators": results } logs_dir = os.path.dirname(self.status_file_path) os.makedirs(logs_dir, exist_ok=True) temp_file_path = self.status_file_path + ".tmp" with open(temp_file_path, 'w', encoding='utf-8') as f: json.dump(status, f, indent=4, default=str) os.replace(temp_file_path, self.status_file_path) logging.debug(f"Successfully updated indicators status file with {len(results)} indicators.") except Exception as e: logging.error(f"Failed to fetch or save indicators: {e}", exc_info=True) def run(self): """Main loop to periodically compute and save indicators.""" logging.info("Starting Indicators Fetcher loop (update interval: 30s)") while True: try: self.fetch_and_save_indicators() except Exception as e: logging.error(f"Indicators Fetcher loop error: {e}", exc_info=True) time.sleep(30) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Run the Indicators Data Fetcher.") parser.add_argument("--log-level", default="normal", choices=['off', 'normal', 'debug']) args = parser.parse_args() fetcher = IndicatorsFetcher(log_level=args.log_level) try: fetcher.run() except KeyboardInterrupt: logging.info("Indicators Data Fetcher stopped.")