from config import DEFAULT_WEIGHTS class SignalEngine: def __init__(self): self.weights = dict(DEFAULT_WEIGHTS) def set_weights(self, weights: dict): total = sum(weights.values()) if abs(total - 1.0) > 0.01: raise ValueError(f"Weights must sum to 1.0, got {total}") self.weights = weights def compute_score(self, technical: float, news: float, social: float, ai: float) -> float: score = ( technical * self.weights["technical"] + news * self.weights["news"] + social * self.weights["social"] + ai * self.weights["ai"] ) return round(score, 1) def classify(self, score: float) -> str: if score >= 70: return "BUY" elif score >= 40: return "HOLD" return "SELL" def rank_coins(self, coins: dict[str, dict]) -> list[dict]: results = [] for symbol, scores in coins.items(): composite = self.compute_score( scores["technical"], scores["news"], scores["social"], scores["ai"] ) results.append({ "symbol": symbol, "technical": scores["technical"], "news": scores["news"], "social": scores["social"], "ai": scores["ai"], "composite": composite, "signal": self.classify(composite), }) results.sort(key=lambda x: x["composite"], reverse=True) return results