Add indicators fetcher, rich dashboard renderer, and remove trade executor/status
This commit is contained in:
86
indicators_fetcher.py
Normal file
86
indicators_fetcher.py
Normal file
@ -0,0 +1,86 @@
|
||||
"""
|
||||
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.path.join(project_root, "_data", "market_data.db")
|
||||
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.")
|
||||
Reference in New Issue
Block a user