57769967d1
News engine: expand sentiment keywords (18%→60% headline coverage), add MyFXBook RSS as fallback calendar source when Forex Factory returns 429, add retry/backoff on calendar API rate limits, update stale ForexLive URL to investinglive.com, add date formats without seconds for MyFXBook RSS. Telegram bot: remove flood control, rate limiter, and dashboard failure tracking — all sends go directly through bot.send_message/edit_message_text. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
234 lines
6.8 KiB
Python
Executable File
234 lines
6.8 KiB
Python
Executable File
"""
|
||
ForexBot2 — Configuration
|
||
==========================================
|
||
"""
|
||
|
||
from dataclasses import dataclass, field
|
||
from enum import Enum
|
||
from typing import Dict, List
|
||
|
||
|
||
class Timeframe(Enum):
|
||
M1 = "1min"
|
||
M5 = "5min"
|
||
M15 = "15min"
|
||
M30 = "30min"
|
||
H1 = "1h"
|
||
H4 = "4h"
|
||
D1 = "1d"
|
||
W1 = "1wk"
|
||
|
||
|
||
class SignalStrength(Enum):
|
||
STRONG_BUY = 2
|
||
BUY = 1
|
||
NEUTRAL = 0
|
||
SELL = -1
|
||
STRONG_SELL = -2
|
||
|
||
|
||
class MarketSession(Enum):
|
||
SYDNEY = "sydney"
|
||
TOKYO = "tokyo"
|
||
LONDON = "london"
|
||
NEW_YORK = "new_york"
|
||
OVERLAP_LONDON_NY = "london_ny_overlap"
|
||
|
||
|
||
# ── 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:
|
||
"""Technical indicator parameters."""
|
||
ema_fast: int = 9
|
||
ema_medium: int = 21
|
||
ema_slow: int = 50
|
||
ema_trend: int = 200
|
||
|
||
rsi_period: int = 14
|
||
rsi_overbought: float = 70.0
|
||
rsi_oversold: float = 30.0
|
||
rsi_neutral_upper: float = 60.0
|
||
rsi_neutral_lower: float = 40.0
|
||
|
||
macd_fast: int = 12
|
||
macd_slow: int = 26
|
||
macd_signal: int = 9
|
||
|
||
bb_period: int = 20
|
||
bb_std: float = 2.0
|
||
|
||
atr_period: int = 14
|
||
|
||
adx_period: int = 14
|
||
adx_strong_trend: float = 25.0
|
||
adx_very_strong: float = 50.0
|
||
|
||
divergence_lookback: int = 14
|
||
swing_sr_lookback: int = 50
|
||
|
||
disabled_indicators: List[str] = field(default_factory=lambda: ["divergence"])
|
||
|
||
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
|
||
|
||
regime_weights_override: Dict[str, Dict[str, float]] = field(default_factory=dict)
|
||
|
||
|
||
@dataclass
|
||
class SignalConfig:
|
||
"""Signal scoring & filtering."""
|
||
min_confidence: float = 55.0
|
||
|
||
weights: Dict[str, float] = field(default_factory=lambda: {
|
||
"ema_trend": 1.0,
|
||
"rsi": 1.5,
|
||
"bollinger": 1.5,
|
||
"candlestick": 1.0,
|
||
"divergence": 1.5,
|
||
})
|
||
|
||
mtf_agreement_threshold: int = 2 # of 3 timeframes
|
||
cooldown_bars: int = 5
|
||
|
||
default_risk_pct: float = 1.0
|
||
default_rr_ratio: float = 2.0
|
||
atr_sl_multiplier: float = 1.5
|
||
min_rr_ratio: float = 1.2
|
||
|
||
|
||
@dataclass
|
||
class NewsConfig:
|
||
"""Economic calendar & sentiment."""
|
||
tracked_currencies: List[str] = field(default_factory=lambda: ["USD", "JPY", "EUR", "GBP", "XAU"])
|
||
min_impact: str = "medium"
|
||
pre_event_buffer_minutes: int = 30
|
||
post_event_buffer_minutes: int = 15
|
||
|
||
rss_feeds: List[str] = field(default_factory=lambda: [
|
||
"https://investinglive.com/feed/",
|
||
"https://www.fxstreet.com/rss",
|
||
])
|
||
|
||
|
||
@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.
|
||
"""
|
||
enabled: bool = True
|
||
rsi_entry_threshold: float = 38.0 # Wilder RSI scale; equivalent to standard RSI ~30
|
||
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])
|
||
|
||
|
||
@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])
|
||
|
||
|
||
@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])
|
||
|
||
|
||
@dataclass
|
||
class FilterConfig:
|
||
"""Regime and session filters for live signals."""
|
||
regime_filter: bool = False
|
||
regime_filter_timeframe: Timeframe = Timeframe.H4
|
||
regime_filter_min_adx: float = 25.0
|
||
|
||
session_filter: bool = True
|
||
session_start_hour: int = 7
|
||
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])
|
||
|
||
sell_filter: bool = True
|
||
sell_allowed_pairs: List[str] = field(default_factory=lambda: ["XAU/USD"])
|
||
|
||
|
||
@dataclass
|
||
class PlatformConfig:
|
||
"""Top-level configuration."""
|
||
technical: TechnicalConfig = field(default_factory=TechnicalConfig)
|
||
signals: SignalConfig = field(default_factory=SignalConfig)
|
||
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
|
||
|
||
primary_timeframe: Timeframe = Timeframe.H1
|
||
confirmation_timeframes: List[Timeframe] = field(
|
||
default_factory=lambda: [Timeframe.M15, Timeframe.H4]
|
||
)
|
||
|
||
data_lookback_days: int = 60
|
||
|
||
twelve_data_api_key: str = "f563b22ffdfd4924955decbe1a8c8701"
|
||
|
||
refresh_interval: int = 300
|
||
|
||
scan_pairs: List[str] = field(
|
||
default_factory=lambda: [EURUSD, GBPUSD, XAUUSD]
|
||
)
|
||
scan_timeframes: List[Timeframe] = field(
|
||
default_factory=lambda: [Timeframe.M5, Timeframe.M15, Timeframe.H1, Timeframe.H4]
|
||
)
|
||
candle_buffer_seconds: int = 10
|
||
ws_cooldown_seconds: int = 300
|
||
|
||
log_level: str = "INFO"
|