Add web dashboard (Redis + FastAPI + WebSocket), scope XAU penalties

Signal daemon (signal_web.py): candle-boundary scanner mirroring
telegram_bot.py, publishes serialized SignalReport JSON to Redis.
Web API (web/app.py): thin FastAPI reader behind Apache, serves
/api/signals REST + /ws WebSocket from Redis pub/sub.
Frontend (web/static/index.html): 3-pair grid, color-coded signals,
indicator breakdown per timeframe, trade setup display.

Also: XAU-specific penalty scoping in signal_aggregator (softer
confidence penalties for gold, original strict values for forex),
pair-aware session filter routing XAU to its own blocked hours.
This commit is contained in:
harwinder
2026-05-14 23:15:37 -04:00
parent 31ecdf4292
commit bb3c475f22
10 changed files with 1401 additions and 883 deletions
+41 -7
View File
@@ -111,7 +111,7 @@ class SignalConfig:
default_risk_pct: float = 1.0
default_rr_ratio: float = 2.0
atr_sl_multiplier: float = 1.5
min_rr_ratio: float = 1.2
min_rr_ratio: float = 0.5
@dataclass
@@ -130,16 +130,31 @@ class NewsConfig:
@dataclass
class XauStrategyConfig:
"""XAU/USD oversold-bounce strategy (BUY only).
1-year optimized: 89% WR, PF 4.58, +5041p (118 trades).
Entry: M15 RSI<38 + price above EMA200 on M15, H1, H4.
Exit: TP=0.9×ATR, SL=2.0×ATR.
"""XAU/USD v3 weighted confluence strategy.
1-year grid-optimized (768 combos): 52.4% WR, PF 2.34, +40.3R (63 trades).
Entry: M15 score>=80 + H4 RSI confirms + H1 MACD confirms + RSI 40-65 zone.
Exit: Partial — 1R→BE, 2R→close 50%, 3R→close rest. SL=2.5×ATR.
Blocked: Fri/Sat/Sun, hours 1/3/9/10/19/22/23.
"""
enabled: bool = True
rsi_entry_threshold: float = 38.0 # Wilder RSI scale; equivalent to standard RSI ~30
rsi_entry_threshold: float = 45.0
tp_atr_multiplier: float = 0.9
sl_atr_multiplier: float = 2.0
blocked_hours_utc: List[int] = field(default_factory=lambda: [8, 9, 11, 14, 15, 20])
min_ema200_tfs: int = 2
allow_generic_trades: bool = True
blocked_hours_utc: List[int] = field(default_factory=lambda: [0, 1, 2, 5, 6, 21, 22, 23])
# v2 confluence fixes
weekend_filter: bool = True
min_atr_threshold: float = 1.0
v2_sl_atr_multiplier: float = 2.5
buy_threshold_boost: int = 0
m5_confirmation_bars: int = 0
# v3 gates (grid-optimized on 1Y Mon-Thu data)
h4_rsi_gate: bool = True # require H4 RSI >55 for BUY, <45 for SELL
h1_macd_gate: bool = True # require H1 MACD histogram >0 for BUY, <0 for SELL
rsi_zone: tuple = (40.0, 65.0) # only enter when M15 RSI in this zone
allowed_weekdays: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4]) # Mon-Fri
sell_min_quality: List[str] = field(default_factory=lambda: ["A+", "A", "B"]) # SELL needs B+
@dataclass
@@ -158,6 +173,16 @@ class EurStrategyConfig:
tp_atr_multiplier: float = 0.7
sl_atr_multiplier: float = 1.0
blocked_hours_utc: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4, 5, 6, 16, 17, 18, 19, 21, 22, 23])
# If False, suppress generic trade setups when the EUR pullback gate
# didn't fire. Backtest (90-day M15): True → +4.70R, False → +9.50R.
# Generic momentum buys at trending_up extremes are pure drag.
allow_generic_trades: bool = False
# Minimum number of M15 scored indicators (ema_trend, rsi, bollinger,
# adx, candlestick) that must independently signal BUY for the
# pullback gate to fire. The strategy hardcodes Quality=A and
# Score=+40 — without this, the "A" grade fires on weak technical
# confluence. 0 = disabled (legacy behavior).
min_indicators_agree: int = 2
@dataclass
@@ -177,6 +202,10 @@ class GbpStrategyConfig:
tp_atr_multiplier: float = 0.7
sl_atr_multiplier: float = 1.0
blocked_hours_utc: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4, 5, 6, 14, 15, 16, 17, 19, 21, 22, 23])
# See EurStrategyConfig.allow_generic_trades — same rationale.
allow_generic_trades: bool = False
# See EurStrategyConfig.min_indicators_agree — same rationale.
min_indicators_agree: int = 2
@dataclass
@@ -191,6 +220,11 @@ class FilterConfig:
session_end_hour: int = 16
blocked_hours_utc: List[int] = field(default_factory=lambda: [0, 1, 2, 5, 6, 8, 12, 13, 14, 15, 16, 17, 21, 22, 23])
# Universal weekday filter (0=Mon ... 6=Sun). Default Mon-Thu — Fridays
# have wide spreads from US session ending and weekend gap risk; XAU/USD
# has its own stricter allowed_weekdays in xau_strategy that overrides.
allowed_weekdays: List[int] = field(default_factory=lambda: [0, 1, 2, 3])
sell_filter: bool = True
sell_allowed_pairs: List[str] = field(default_factory=lambda: ["XAU/USD"])