46 lines
1.5 KiB
Python
46 lines
1.5 KiB
Python
|
|
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
|