Refocus on XAU/USD: add momentum indicators, tune TP, exhaustion block

Strip EUR/USD, GBP/USD, USD/JPY pairs and strategies from entire codebase.
Add 3 new scored indicators (ROC, Keltner/TTM Squeeze, ADX slope) and
enable MACD-as-pillar + divergence detection for early trend entry.
Introduce "transitioning" regime (ADX < 25, slope > 3.0) to catch trend
births before ADX confirms. Gold-specific composite weights per regime.

Tune TP multipliers: quality-tiered scaling (A+/A get 1.5-2.0x ATR via
XAU ATR method, B/C use swing-level targeting). Backtest: +24R total,
65% WR, PF 1.12 over 365 days.

Add momentum-confirmed exhaustion block: hard-reject trades when 2+
static exhaustion signals fire AND ROC/MACD confirm fading momentum.
Prevents late trend entries without killing strong trend trades.

Telegram: simplify buttons to timeframe-only labels, add "Scan All TFs"
multi-timeframe summary, add /scan command, fix BB/KC level breach keys,
fix price formatting (.2f for gold), fix deprecated asyncio call, fix
"1 pairs" grammar and 60s/30s dashboard refresh mismatch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
harwinder
2026-05-15 10:51:51 -04:00
parent 98daf71a52
commit 8ed6454ea5
15 changed files with 852 additions and 2108 deletions
+32 -89
View File
@@ -1,5 +1,5 @@
"""
ForexBot2 — Configuration
ForexBot2 — Configuration (XAU/USD focused)
==========================================
"""
@@ -36,22 +36,12 @@ class MarketSession(Enum):
# ── Supported pairs ──────────────────────────────────────────────
USDJPY = "USDJPY=X"
EURUSD = "EURUSD=X"
GBPUSD = "GBPUSD=X"
XAUUSD = "XAU/USD"
PAIR_INFO = {
USDJPY: {"display": "USD/JPY", "pip_value": 0.01, "is_jpy_pair": True},
EURUSD: {"display": "EUR/USD", "pip_value": 0.0001, "is_jpy_pair": False},
GBPUSD: {"display": "GBP/USD", "pip_value": 0.0001, "is_jpy_pair": False},
XAUUSD: {"display": "XAU/USD", "pip_value": 0.10, "is_jpy_pair": False},
}
# Defaults (kept for backward compat)
DISPLAY = "USD/JPY"
PIP_VALUE = 0.01
@dataclass
class TechnicalConfig:
@@ -83,11 +73,24 @@ class TechnicalConfig:
divergence_lookback: int = 14
swing_sr_lookback: int = 50
disabled_indicators: List[str] = field(default_factory=lambda: ["divergence"])
disabled_indicators: List[str] = field(default_factory=list)
ema_mode: str = "4ema" # "4ema" (9/21/50/200) or "2ema" (50/200)
rsi_mode: str = "classic" # "classic" or "regime_aware"
macd_as_pillar: bool = False # promote MACD histogram to scored signal
macd_as_pillar: bool = True # MACD histogram is a scored signal
# ROC (Rate of Change)
roc_period: int = 10
roc_threshold: float = 1.0 # % threshold for strong signal
# Keltner Channels
kc_period: int = 20
kc_atr_period: int = 10
kc_multiplier: float = 1.5
# ADX slope (trend acceleration detection)
adx_slope_lookback: int = 5
adx_slope_emerging_threshold: float = 3.0
regime_weights_override: Dict[str, Dict[str, float]] = field(default_factory=dict)
@@ -101,6 +104,9 @@ class SignalConfig:
"ema_trend": 1.0,
"rsi": 1.5,
"bollinger": 1.5,
"macd": 1.5,
"keltner": 1.5,
"roc": 1.5,
"candlestick": 1.0,
"divergence": 1.5,
})
@@ -117,7 +123,7 @@ class SignalConfig:
@dataclass
class NewsConfig:
"""Economic calendar & sentiment."""
tracked_currencies: List[str] = field(default_factory=lambda: ["USD", "JPY", "EUR", "GBP", "XAU"])
tracked_currencies: List[str] = field(default_factory=lambda: ["USD", "XAU"])
min_impact: str = "medium"
pre_event_buffer_minutes: int = 30
post_event_buffer_minutes: int = 15
@@ -130,82 +136,27 @@ class NewsConfig:
@dataclass
class XauStrategyConfig:
"""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.
"""XAU/USD strategy config.
Legacy gates (H4 RSI, H1 MACD, M15 score) removed in favor of
new momentum indicators (ROC, Keltner squeeze, ADX slope).
"""
enabled: bool = True
rsi_entry_threshold: float = 45.0
tp_atr_multiplier: float = 0.9
tp_atr_multiplier: float = 1.0
sl_atr_multiplier: float = 2.0
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
h4_rsi_gate: bool = False
h1_macd_gate: bool = False
rsi_zone: tuple = (40.0, 65.0)
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
class EurStrategyConfig:
"""EUR/USD pullback-buy strategy (BUY only).
Fixes: no entries at BB resistance, no overbought RSI, no chasing.
Entry: M15 RSI 30–55 (pullback zone) + BB position < 0.75
+ price > EMA200 on M15 & H1 + near EMA21 (not chasing).
Exit: TP=0.7×ATR, SL=1.5×ATR.
"""
enabled: bool = True
rsi_lower: float = 30.0
rsi_upper: float = 55.0
bb_max_position: float = 0.75
chase_max_atr_from_ema21: float = 1.5
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
class GbpStrategyConfig:
"""GBP/USD pullback-buy strategy (BUY only).
1-year optimized: hour 17 blocked.
Entry: M15 RSI 30–55 + BB < 0.75 + price > EMA200 on M15 & H1
+ within 1.5×ATR of EMA21.
Exit: TP=0.7×ATR, SL=1.0×ATR.
"""
enabled: bool = True
rsi_lower: float = 30.0
rsi_upper: float = 55.0
bb_min_position: float = 0.0
bb_max_position: float = 0.75
chase_max_atr_from_ema21: float = 1.5
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
sell_min_quality: List[str] = field(default_factory=lambda: ["A+", "A", "B"])
@dataclass
@@ -220,14 +171,8 @@ 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"])
@dataclass
class PlatformConfig:
@@ -237,12 +182,10 @@ class PlatformConfig:
news: NewsConfig = field(default_factory=NewsConfig)
backtest: FilterConfig = field(default_factory=FilterConfig)
xau_strategy: XauStrategyConfig = field(default_factory=XauStrategyConfig)
eur_strategy: EurStrategyConfig = field(default_factory=EurStrategyConfig)
gbp_strategy: GbpStrategyConfig = field(default_factory=GbpStrategyConfig)
symbol: str = USDJPY
display_name: str = DISPLAY
pip_value: float = PIP_VALUE
symbol: str = XAUUSD
display_name: str = "XAU/USD"
pip_value: float = 0.10
primary_timeframe: Timeframe = Timeframe.H1
confirmation_timeframes: List[Timeframe] = field(
@@ -256,7 +199,7 @@ class PlatformConfig:
refresh_interval: int = 300
scan_pairs: List[str] = field(
default_factory=lambda: [EURUSD, GBPUSD, XAUUSD]
default_factory=lambda: [XAUUSD]
)
scan_timeframes: List[Timeframe] = field(
default_factory=lambda: [Timeframe.M5, Timeframe.M15, Timeframe.H1, Timeframe.H4]