Fixed Bugs
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -76,7 +76,7 @@ class TechnicalConfig:
|
||||
rsi_neutral_upper: float = 60.0
|
||||
rsi_neutral_lower: float = 40.0
|
||||
|
||||
# MACD (12, 26, 9 is standard but we validate)
|
||||
# MACD (12, 26, 9 is standard)
|
||||
macd_fast: int = 12
|
||||
macd_slow: int = 26
|
||||
macd_signal: int = 9
|
||||
@@ -110,6 +110,9 @@ class TechnicalConfig:
|
||||
# Pivot points lookback
|
||||
pivot_lookback: int = 1
|
||||
|
||||
# Divergence detection — how many bars back to scan for swing points
|
||||
divergence_lookback: int = 14
|
||||
|
||||
|
||||
@dataclass
|
||||
class SignalConfig:
|
||||
@@ -130,10 +133,6 @@ class SignalConfig:
|
||||
# Multi-timeframe confirmation requirements
|
||||
mtf_agreement_threshold: int = 2 # out of 3 timeframes must agree
|
||||
|
||||
# Divergence detection sensitivity
|
||||
divergence_lookback: int = 14
|
||||
divergence_min_swing: float = 0.001 # minimum price swing for valid divergence
|
||||
|
||||
# Signal cooldown (prevent over-signalling same direction)
|
||||
cooldown_bars: int = 5
|
||||
|
||||
@@ -185,6 +184,9 @@ class PlatformConfig:
|
||||
# Data source
|
||||
data_lookback_days: int = 60 # enough for 200 EMA on H1
|
||||
|
||||
# Twelve Data API key (overridden by TWELVE_DATA_API_KEY env var)
|
||||
twelve_data_api_key: str = "f563b22ffdfd4924955decbe1a8c8701"
|
||||
|
||||
# Dashboard refresh interval (seconds)
|
||||
refresh_interval: int = 300 # 5 minutes
|
||||
|
||||
|
||||
+21
-20
@@ -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__)
|
||||
@@ -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()
|
||||
|
||||
@@ -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,13 +402,6 @@ 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}")
|
||||
|
||||
Reference in New Issue
Block a user