Fixed Bugs

This commit is contained in:
Harwinder
2026-05-04 10:24:54 -04:00
parent e4138ee60a
commit 242df24ca7
7 changed files with 32 additions and 29 deletions
+24 -23
View File
@@ -16,16 +16,16 @@ Key principles:
import logging
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Dict, List, Optional, Tuple
from typing import Dict, List, Optional
import pandas as pd
from config import (
PlatformConfig, SignalStrength, Timeframe,
SYMBOL_DISPLAY, MAJOR_PAIRS, CROSS_PAIRS,
SYMBOL_DISPLAY,
)
from data_provider import ForexDataProvider
from technical_engine import TechnicalEngine, TechnicalAnalysis
from engine import TechnicalEngine, TechnicalAnalysis
from news_engine import NewsEngine, FundamentalContext
logger = logging.getLogger(__name__)
@@ -99,7 +99,7 @@ class SignalReport:
class SignalAggregator:
"""
Master signal aggregator.
Orchestrates data fetching, technical analysis across timeframes,
fundamental analysis, and produces final graded signals.
"""
@@ -118,6 +118,12 @@ class SignalAggregator:
reports = []
context = self.news_engine.get_fundamental_context()
# Batch-prefetch all pairs × all needed timeframes (3 API calls instead of 21)
all_timeframes = (
[self.config.primary_timeframe] + self.config.confirmation_timeframes
)
self.data_provider.prefetch_batch(self.config.watch_pairs, all_timeframes)
for symbol in self.config.watch_pairs:
try:
report = self.analyze_pair(symbol, context)
@@ -135,9 +141,7 @@ class SignalAggregator:
symbol: str,
context: Optional[FundamentalContext] = None,
) -> SignalReport:
"""
Complete analysis of a single pair across all layers.
"""
"""Complete analysis of a single pair across all layers."""
if context is None:
context = self.news_engine.get_fundamental_context()
@@ -227,7 +231,7 @@ class SignalAggregator:
def _compute_final_signal(self, report: SignalReport):
"""
Compute the final signal by combining all layers.
Priority:
1. Event risk can downgrade or block signals
2. MTF agreement boosts confidence
@@ -239,9 +243,8 @@ class SignalAggregator:
# ── MTF adjustment ─────────────────────────────────────────
if report.mtf_agreement:
# All timeframes agree — boost confidence
# All timeframes agree — boost confidence and blend scores
confidence = min(confidence + 15, 95)
# Average the MTF scores for more stable signal
all_scores = list(report.mtf_scores.values())
if all_scores:
mtf_avg = sum(all_scores) / len(all_scores)
@@ -251,7 +254,6 @@ class SignalAggregator:
confidence *= 0.7
if len(report.mtf_scores) >= 2:
scores = list(report.mtf_scores.values())
# Check for conflicting directions
has_bull = any(s > 10 for s in scores)
has_bear = any(s < -10 for s in scores)
if has_bull and has_bear:
@@ -259,7 +261,6 @@ class SignalAggregator:
confidence *= 0.6
# ── News sentiment adjustment ──────────────────────────────
sent_weight = self.config.signals.weights.get("sentiment", 0.1)
if abs(report.news_sentiment) > 0.2:
# Sentiment aligns with technical
if (report.news_sentiment > 0 and score > 0) or \
@@ -274,7 +275,7 @@ class SignalAggregator:
# ── Event risk adjustment ──────────────────────────────────
if report.event_risk == "danger":
report.warnings.append(f"EVENT RISK: {report.event_description}")
confidence *= 0.3 # Heavily penalize
confidence *= 0.3 # Heavily penalize — event will disrupt price action
report.action_recommendation = f"WAIT — {report.event_description}"
elif report.event_risk == "caution":
report.warnings.append(f"Upcoming event: {report.event_description}")
@@ -325,7 +326,7 @@ class SignalAggregator:
elif report.signal_quality == "B":
report.action_recommendation = f"{sig_name} — Decent setup, wait for confirmation"
elif report.signal_quality in ("C", "D"):
report.action_recommendation = f"WATCH — Signal present but low confidence"
report.action_recommendation = "WATCH — Signal present but low confidence"
else:
report.action_recommendation = "NO TRADE — No clear signal"
@@ -379,7 +380,14 @@ class SignalAggregator:
)
def _collect_reasons(self, report: SignalReport):
"""Collect bullish/bearish reasons from all indicators."""
"""
Collect bullish/bearish reasons from all indicators.
Each indicator's description is captured once via the indicators
dict. Pattern signals (candlestick) are already included in the
'candlestick' indicator description, so we do NOT re-process
pattern_signals to avoid duplicate entries.
"""
if not report.primary_analysis:
return
@@ -394,15 +402,8 @@ class SignalAggregator:
prefix = "STRONG: " if ind.signal == SignalStrength.STRONG_SELL else ""
report.bearish_reasons.append(f"{prefix}{ind.name}: {ind.description}")
# Add pattern signals
for pattern in report.primary_analysis.pattern_signals:
if any(kw in pattern.lower() for kw in ["bullish", "hammer", "buy"]):
report.bullish_reasons.append(f"Pattern: {pattern}")
elif any(kw in pattern.lower() for kw in ["bearish", "shooting", "sell"]):
report.bearish_reasons.append(f"Pattern: {pattern}")
# Add news context
if report.news_sentiment > 0.1:
report.bullish_reasons.append(f"News: {report.news_description}")
elif report.news_sentiment < -0.1:
report.bearish_reasons.append(f"News: {report.news_description}")
report.bearish_reasons.append(f"News: {report.news_description}")