Files
ForexBot2/CLAUDE.md
T
Harwinder Sekhon 43d9064d1e Telegram: subscriber channel feed, owner lock, full risk disclaimer
- TELEGRAM_CHANNEL_ID mirrors auto-scan signal + breach alerts to a
  subscriber channel (Stars-subscription monetization; Telegram manages
  membership). Feed keeps running even when the owner's DM auto-scan
  is toggled off.
- _owner_only decorator locks all commands/buttons to TELEGRAM_CHAT_ID;
  others get a refusal pointing at the channel.
- Every signal-bearing message (detailed signal, scan summary, all-TF
  summary, breach alerts) now ends with a not-financial-advice /
  educational-use disclaimer via a single _DISCLAIMER constant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 18:37:50 -04:00

8.6 KiB
Raw Blame History

ForexBot2

Multi-pair signal intelligence platform (XAU/USD + EUR/USD). Analyzes each pair across multiple timeframes using 9 technical indicators with regime-adaptive weights, news sentiment, and economic calendar data. Delivers signals via Telegram with full trade setups (entry, SL, TP).

Architecture

Twelve Data REST API + WebSocket
        |
  data_provider.py          (fetch, cache, validate OHLCV; rate-limited 55 calls/min)
        |
    engine.py                (9 indicators per timeframe → composite score)
        |
  signal_aggregator.py       (MTF agreement + news + final signal + trade setup)
        |
  pair_signals/              (per-pair config factories: xauusd.py, eurusd.py)
        |
  +-----+--------+
  |              |
telegram_bot.py  main.py
(Telegram alerts, (CLI per-pair
 auto-scanner,    analysis)
 WS monitor)

Per-pair modularity: each pair registers a make_config(primary_tf, confirmation_tfs) -> PlatformConfig factory in pair_signals/. PlatformConfig.scan_pairs is the single switch for which pairs the bot scans (single- or multi-pair). Market constants (pip value, price precision, backtest default spread) live in PAIR_INFO; strategy knobs live in per-pair dataclasses (XauStrategyConfig, EurUsdStrategyConfig). All XAU-specific gates in the aggregator are display-gated — nothing gold-calibrated touches the EUR path, and vice versa (enforced by pair-isolation tests + a pinned-window XAU regression CSV).

Core Files

File Purpose
config.py All configuration dataclasses, PAIR_INFO registry, per-pair strategy configs
data_provider.py Twelve Data SDK wrapper with in-memory cache and rate limiting
engine.py TechnicalEngine — computes EMA, RSI, BB, ADX, ATR, MACD, ROC, Keltner, divergences, candlestick patterns, swing S/R
signal_aggregator.py SignalAggregator — MTF analysis, news integration, diminishing penalty cap, trade setup generation
news_engine.py Economic calendar (Forex Factory JSON) + RSS sentiment (keyword-based)
telegram_bot.py Async Telegram bot with auto-scanner (M5/M15/H1/H4), WebSocket price monitor
pair_signals/ Per-pair producer registry (PAIR_PRODUCERS) + config factories
main.py CLI entry point (--pair XAUUSD|EURUSD)
test_all.py Comprehensive QA suite (~176 tests, no live API needed)

Key Concepts

Signal Pipeline: OHLCV → indicators → regime classification → regime-weighted composite score → MTF agreement check → news/event adjustment → diminishing penalty cap → final signal (STRONG_BUY/BUY/NEUTRAL/SELL/STRONG_SELL) → quality grade (A+/A/B/C/D/F) → trade setup if grade C+.

Regime-Adaptive Weights: Market classified as trending_up, trending_down, ranging, or transitioning via ADX + EMA + ADX slope. Gold-specific weights per regime:

  • Trending: MACD (2.0), EMA (2.0), Keltner (1.5), ROC (1.5), Divergence (1.0)
  • Ranging: Divergence (2.5), Keltner (2.0), RSI (1.5), BB (1.5), MACD (1.5)
  • Transitioning: Keltner (2.5), MACD (2.5), ROC (2.0), Divergence (2.0), EMA (1.5)

ROC is directionally redundant with MACD/Keltner/EMA (0.8–0.94 correlation) but its weight is load-bearing: composite thresholds are calibrated with it — removing it backtested 13R worse. Don't zero it without retuning thresholds.

RSI (regime-aware, default): In trends RSI buys pullback zones instead of fading strength (classic mode backtested worse for gold). In transitioning only extremes (≥70/≤30) signal.

Divergence: 40-bar lookback; price and indicator swings must align within ±2 bars to count as one divergence observation.

Transitioning Regime: ADX < 25 but ADX slope > 3.0 = trend emerging. Catches trend birth 5-10 bars before ADX crosses 25. Boosts quality grade for early entries.

Diminishing Penalty Cap: Penalties sorted by magnitude, applied with exponential decay (1st at 100%, 2nd at 50%, 3rd at 25%). Hard cap at 30% total. Replaces old additive stacking that could gut 30-50% confidence.

Indicators (9 scored): EMA Trend, RSI, Bollinger Bands, MACD, ADX, Keltner Channels (TTM Squeeze), ROC (Rate of Change), Divergence, Candlestick Patterns.

Trade Setup: SL = nearest swing low/high ± 1×ATR buffer (min 1.5×ATR). TP = nearest swing level if RR≥1.2, else calculated from ATR. Minimum RR 0.5:1.

How to Run

# CLI
python main.py                    # XAU/USD H1 default
python main.py --pair EURUSD --timeframe M5 --detail

# Telegram bot (auto-scanner)
TELEGRAM_TOKEN=<token> TELEGRAM_CHAT_ID=<id> python telegram_bot.py

# Tests
python test_all.py

# Backtest (spread defaults per pair: XAU $0.30, EUR 0.0001 — see PAIR_INFO)
python backtest/gpu_backtest.py --pair XAUUSD --days 365
python backtest/gpu_backtest.py --pair EURUSD --primary-tf 5min --confirm-tfs 15min,1h --days 365

Environment Variables

Variable Purpose Default
TWELVE_DATA_API_KEY Market data API key Hardcoded fallback in config
TELEGRAM_TOKEN Telegram bot token Hardcoded fallback
TELEGRAM_CHAT_ID Owner chat ID (enables boot auto-scan; only this user can drive the bot) Hardcoded fallback
TELEGRAM_CHANNEL_ID Subscriber channel ID (-100…); signal + breach alerts mirror there; "" disables Hardcoded fallback

Dependencies

numpy, pandas, requests, twelvedata, python-telegram-bot, websockets — see requirements.txt.

Data Provider

  • Source: Twelve Data REST API via twelvedata SDK
  • Rate limit: 55 credits/min (Grow plan), enforced by sliding-window throttle
  • Cache: In-memory dict, TTL = candle duration of the timeframe
  • Validation: Drops NaN rows, forward-fills gaps (limit 3), fixes OHLC inconsistencies, removes outliers (>10σ), strips future timestamps, deduplicates
  • WebSocket: subscribes every pair in scan_pairs

Telegram Bot

  • Auto-scan: M5, M15, H1, H4 at candle boundaries + 10s buffer (all timeframes alert)
  • Manual scan: Buttons for M15/H1/H4 individual scans + "Scan All TFs" multi-timeframe summary
  • WebSocket: Streams live ticks for XAU/USD; triggers immediate M15 scan on key level breach (swing S/R, BB, KC, EMA200) with 5-min cooldown
  • Commands: /start, /scan, /autoscan, /status, /cache, /clearcache, /help
  • Owner lock: all commands/buttons respond only to TELEGRAM_CHAT_ID; others get a refusal message
  • Subscriber channel: with TELEGRAM_CHANNEL_ID set, auto-scan + breach alerts also post to the channel (bot must be channel admin). Monetized via Telegram Stars subscription invite links — Telegram handles membership; the bot has no payment code. Channel feed keeps running even if the owner's DM auto-scan is off

Backtesting

The backtest/ directory contains gpu_backtest.py — a GPU-accelerated backtester (CuPy with NumPy fallback) that replays historical OHLCV through the real SignalAggregator. Pre-computes all indicator series including ROC, Keltner, ADX slope for 100x+ speedup. Uses parquet caching for data persistence.

Fill realism: charges a round-trip spread per trade (--spread; defaults to the pair's default_spread in PAIR_INFO), fills gap-through SL/TP at the bar open, and resolves trades against the RAW price path (the parquet cache stores raw bars; validation/cleaning runs on load — signals see cleaned data, trade resolution sees real spikes). Entry is at the next bar's open after the signal bar. Weekend/session filters evaluate bar-close (decision) time to match the live bot's wall clock.

GPU note: CuPy needs the NVIDIA runtime pip wheels (nvidia-cuda-runtime-cu12, nvidia-cuda-nvrtc-cu12, nvidia-curand-cu12, nvidia-nvjitlink-cu12) or it silently falls back to NumPy — check the "Backend:" line in the run log. The bar-replay loop itself is single-threaded Python either way (~340 bars/s); GPU only accelerates indicator precompute and SL/TP scanning.

Code Conventions

  • Python 3.12, type hints on public methods
  • Dataclasses for all config and output structures
  • SignalStrength enum (-2 to +2) is the universal signal currency
  • Indicators stored as Dict[str, IndicatorSignal] in TechnicalAnalysis
  • Key levels stored as Dict[str, float] — prefixed swing_high_, swing_low_, ema_, bb_, kc_, atr
  • Private indicator data attached as result._rsi_series, result._macd_histogram, result._adx_slope, result._kc_squeeze (underscore prefix, skipped by composite scorer)
  • Blocking signal computation runs in ThreadPoolExecutor(max_workers=4) to avoid blocking the async Telegram event loop
  • Shared ForexDataProvider instance across all scans for cache reuse