Files
ForexBot2/config.py
T
Harwinder 405ddffc9c Remove yfinance/XAU/XAG fallback — focus on currency pairs only
- data_provider: strip yfinance imports, _YF_FALLBACK_MAP, _YF_INTERVALS,
  _YF_SESSION, _fetch_yfinance_fallback, _resample_h1_to_h4. Twelve Data
  is the sole data source. Raises DataUnavailableError if a pair isn't
  on the configured plan.
- config: remove XAU/USD and XAG/USD from SYMBOL_DISPLAY and PIP_VALUES.
  PIP_VALUES is now empty (defaults: 0.01 JPY pairs, 0.0001 forex).
- signal_aggregator: clear _PER_SYMBOL_TFS overrides (was XAU/XAG-only).
- telegram_bot: replace XAUUSD with AUDUSD in SCAN_PAIRS. Auto-load .env
  via python-dotenv so TELEGRAM_BOT_TOKEN/GEMINI_API_KEY are picked up.
- requirements: drop yfinance and curl_cffi dependencies.

End-to-end pipeline test passes: data freshness, news engine (Gemini live),
signal aggregator, and the /signal+/scan code paths in telegram_bot.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 12:13:09 -04:00

218 lines
6.4 KiB
Python

"""
Forex Signal Intelligence Platform - Configuration
===================================================
Central configuration for all signal analysis parameters.
Tuned by market regime and validated against historical performance.
"""
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"
# ── Major Forex Pairs ──────────────────────────────────────────────
MAJOR_PAIRS = [
"EURUSD=X", "GBPUSD=X", "USDJPY=X", "USDCHF=X",
"AUDUSD=X", "USDCAD=X", "NZDUSD=X",
]
CROSS_PAIRS = [
"EURGBP=X", "EURJPY=X", "GBPJPY=X", "AUDJPY=X",
"EURCHF=X", "CADJPY=X",
]
# Symbol display names
SYMBOL_DISPLAY = {
"EURUSD=X": "EUR/USD", "GBPUSD=X": "GBP/USD",
"USDJPY=X": "USD/JPY", "USDCHF=X": "USD/CHF",
"AUDUSD=X": "AUD/USD", "USDCAD=X": "USD/CAD",
"NZDUSD=X": "NZD/USD", "EURGBP=X": "EUR/GBP",
"EURJPY=X": "EUR/JPY", "GBPJPY=X": "GBP/JPY",
"AUDJPY=X": "AUD/JPY", "EURCHF=X": "EUR/CHF",
"CADJPY=X": "CAD/JPY",
}
# Pip values per symbol (used for trade setup risk/reward in pips)
# Forex defaults: 0.01 for JPY pairs, 0.0001 for everything else.
# Override here for any pair that doesn't follow that rule.
PIP_VALUES: Dict[str, float] = {}
@dataclass
class TechnicalConfig:
"""Technical indicator parameters - carefully tuned for Forex."""
# EMA periods (fast/medium/slow for trend detection)
ema_fast: int = 9
ema_medium: int = 21
ema_slow: int = 50
ema_trend: int = 200
# RSI
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 (12, 26, 9 is standard)
macd_fast: int = 12
macd_slow: int = 26
macd_signal: int = 9
# Bollinger Bands
bb_period: int = 20
bb_std: float = 2.0
# ATR for volatility measurement
atr_period: int = 14
# Stochastic
stoch_k: int = 14
stoch_d: int = 3
stoch_overbought: float = 80.0
stoch_oversold: float = 20.0
# ADX for trend strength
adx_period: int = 14
adx_strong_trend: float = 25.0
adx_very_strong: float = 50.0
# Ichimoku
ichimoku_tenkan: int = 9
ichimoku_kijun: int = 26
ichimoku_senkou_b: int = 52
# Volume profile
volume_ma_period: int = 20
# 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:
"""Signal scoring and filtering parameters."""
# Minimum confidence to emit a signal (0-100)
min_confidence: float = 55.0
# Weight allocation for composite score
weights: Dict[str, float] = field(default_factory=lambda: {
"trend": 0.25, # EMA alignment, ADX
"momentum": 0.20, # RSI, Stochastic, MACD
"volatility": 0.15, # BB position, ATR regime
"price_action": 0.15, # Candlestick patterns, S/R
"multi_timeframe": 0.15,# Higher TF confirmation
"sentiment": 0.10, # News/calendar events
})
# Multi-timeframe confirmation requirements
mtf_agreement_threshold: int = 2 # out of 3 timeframes must agree
# Signal cooldown (prevent over-signalling same direction)
cooldown_bars: int = 5
# Risk management defaults
default_risk_pct: float = 1.0 # risk 1% per trade
default_rr_ratio: float = 2.0 # 1:2 risk-reward minimum
@dataclass
class NewsConfig:
"""Economic calendar and sentiment configuration."""
# High-impact event currencies
tracked_currencies: List[str] = field(default_factory=lambda: [
"USD", "EUR", "GBP", "JPY", "CHF", "AUD", "CAD", "NZD"
])
# Event impact levels to monitor
min_impact: str = "medium" # "low", "medium", "high"
# Pre-event buffer (minutes before high-impact event = no new signals)
pre_event_buffer_minutes: int = 30
# Post-event volatility window (minutes after event = cautious signals)
post_event_buffer_minutes: int = 15
# News sentiment sources
rss_feeds: List[str] = field(default_factory=lambda: [
"https://www.forexlive.com/feed/",
"https://www.fxstreet.com/rss",
])
@dataclass
class PlatformConfig:
"""Overall platform configuration."""
technical: TechnicalConfig = field(default_factory=TechnicalConfig)
signals: SignalConfig = field(default_factory=SignalConfig)
news: NewsConfig = field(default_factory=NewsConfig)
# Default pairs to monitor
watch_pairs: List[str] = field(default_factory=lambda: MAJOR_PAIRS)
# Analysis timeframes (primary + confirmation)
primary_timeframe: Timeframe = Timeframe.H1
confirmation_timeframes: List[Timeframe] = field(
default_factory=lambda: [Timeframe.M15, Timeframe.D1]
)
# 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) — used as a fallback when a
# timeframe isn't covered by cache_ttl_per_tf below.
refresh_interval: int = 300 # 5 minutes
# Per-timeframe cache TTL (seconds). A 1-week candle changes less
# often than a 15-minute candle, so caching them all for the same
# 5 minutes wastes API credits. Tuned to roughly match each TF's
# bar interval so we re-fetch about once per new bar.
cache_ttl_per_tf: Dict[Timeframe, int] = field(default_factory=lambda: {
Timeframe.M1: 60, # 1 minute
Timeframe.M5: 150, # 2.5 minutes
Timeframe.M15: 300, # 5 minutes
Timeframe.M30: 600, # 10 minutes
Timeframe.H1: 1800, # 30 minutes
Timeframe.H4: 7200, # 2 hours
Timeframe.D1: 14400, # 4 hours
Timeframe.W1: 86400, # 24 hours
})
# Logging
log_level: str = "INFO"
log_signals_to_file: bool = True
signal_log_path: str = "signals.log"