- 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>
- New _PER_SYMBOL_TFS map in signal_aggregator routes gold/silver to
M15+H1+H4 confirmation; forex pairs untouched.
- H4 for XAU/XAG is resampled from yfinance H1 bars (yfinance has no
native 4h candle). New _resample_h1_to_h4 helper.
- Batch prefetch unions per-symbol TFs so future per-pair overrides
work without extra plumbing. XAU/XAG still excluded from Twelve Data
batch — H4 resample triggers a single yfinance H1 fetch.
- Telegram SCAN_TIMEFRAMES restored to [M15, H1] so /scan emits both
M15-primary and H1-primary cards. Shared cache means no extra credits.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- XAU/XAG always route to Yahoo Finance and skip Twelve Data entirely
(excluded from batch prefetch, served per-symbol via yfinance).
- Daily chart cleanly skipped for gold/silver — engine drops it from MTF.
- Telegram /scan limited to EURUSD, USDJPY, GBPUSD, XAUUSD.
- SCAN_TIMEFRAMES reduced to single H1 primary; engine still pulls
M15+H1+D1 internally via confirmation TFs (halves API credits per scan).
- Default confirmation TFs swapped H4 -> D1 in config and main.py.
- mtf_agreement_threshold kept at 2-of-3.
- CLAUDE.md cleaned up — old XAUUSD/synthetic-data bug reports removed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- yfinance>=0.2.40 added as a hard dependency
- _fetch_yfinance_fallback(): pulls OHLCV from Yahoo for symbols not on
the Twelve Data free tier (XAUUSD → GC=F, XAGUSD → SI=F)
- Hooked into both batch and single-symbol fetch paths; logs as [yf]
to distinguish from Twelve Data [live]
- Fail-loud: if both providers return nothing, the pair is skipped with
the existing "data unavailable" message
- _analyze_all_tfs accepts an async progress callback; both /signal and
/scan now show coarse milestones via message edits:
"📡 Fetching market data..." → "🧠 Analyzing pairs..." → result
- prefetch_batch is now run in a thread so it doesn't block the event loop
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Trades are intraday (M15/H1) only. D1 stays as a confirmation TF
for both so higher-timeframe trend context still gates A/A+ grades.
W1 is no longer used anywhere — removes one batch call.
Scan now: 3 batch calls (M15, H1, D1) × 7 pairs = 21 credits, ~2 min.
Was: 4 batch calls (M15, H1, D1, W1) = 28 credits, ~3 min.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SCAN_TIMEFRAMES: drop H4, add W1 (4 unique TFs → fewer API calls)
- Confirmations updated to use only the 4 scan TFs (no H4 dependency)
- Add _grade_symbol(): 🔥A+ ✅A 👍B ⚠️C 📉D ❌F
- _GRADE_LEGEND shown on every /signal and /scan message
- 🧠 icon on Signal Analysis and Scan Complete headers
- /help grade guide updated with full symbol legend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Drop _grade_dot() and all colored circle emojis
- Remove raw confidence % from signal and scan output
- Signal card: "M15 · SELL · Grade C"
- Scan row: "EUR/USD · SELL · C · M15"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The warning predated the synthetic fallback removal. Now that the engine
raises DataUnavailableError for unsupported symbols, the flag was always
wrong for XAU/USD and similar pairs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- telegram_bot: one ForexDataProvider shared across all SCAN_TIMEFRAMES;
combined prefetch of all unique TFs up front so the 4 concurrent scans
hit the warm cache instead of firing simultaneous API calls
- data_provider: skip prefetch_batch for timeframes already in cache
- data_provider: deduplicate "no data" warning per symbol (fires once, not once per TF)
- data_provider: [live] info log on successful fetch; outlier-removal downgraded to debug
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
data_provider:
- Remove _generate_synthetic_data entirely — no more fake prices
- Raise DataUnavailableError instead of falling back to synthetic data
(no API key, daily limit hit, API returns no values, fetch failure)
- Move rate limiter to module-level globals (_rate_lock, _rate_request_times,
_rate_daily_credits) so all ForexDataProvider instances running in parallel
threads share the same 8-credit/min and 800-credit/day accounting
- _throttle now raises DataUnavailableError on daily limit (was silent return False)
- Remove _no_api_data tracking, numpy/hashlib imports
telegram_bot:
- Detect F-grade reports caused by data unavailability and show clean
"Data unavailable" line per TF instead of a garbled zero-price card
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/signal: one combined message with all 4 TF sections stacked (────── dividers),
entry/TP/SL always preserved, indicators per TF, MTF folded to one footer line,
disclaimer once at bottom, news/warnings only when relevant
/scan: single compact message — one header+trade line per pair, full entry/TP/SL
kept, no indicator list (use /signal to drill in), danger events shown inline
Both commands show price pull time as EST (e.g. 09:42 AM EST · Mon 04 May 2026)
Scanning progress message no longer shows a single TF in parentheses
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- /signal EURUSD sends one card per timeframe (M15, H1, H4, D1) concurrently
- /scan analyzes all pairs across all TFs, shows best-grade card per pair (B+ only)
- All TFs run in parallel via ThreadPoolExecutor (one worker per TF)
- Remove /tf command and per-chat state — no longer needed
- Executor pool sized to len(SCAN_TIMEFRAMES) for true concurrency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace /scan+/pair commands with /signal (single pair) and /scan (all pairs, B+ only)
- Implement exact visual template: grade dot (🟢/🟡/🔴), TRADE ALERT header, Entry/TP/SL/R:R block, full indicator list with value + condition
- Grade dot enforced: A/A+=🟢, B=🟡, C/D/F=🔴
- /scan filters to minimum Grade B confidence before sending alerts
- HTML parse mode with html.escape() on all dynamic content
- Per-chat default timeframe state preserved
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
data_provider:
- Switch to Authorization header (recommended over apikey query param)
- Enforce 800 credits/day daily limit with warning at 80%
- Fall back to synthetic data when daily limit is reached
- Fix null OHLC field handling (API can return null for any field)
telegram_bot:
- Register commands with set_my_commands so Telegram shows / menu
- Add /credits command to show daily API credit usage and limits
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add telegram_bot.py: full bot interface with /scan, /signals, /pair,
/all, /tf, /watch, /unwatch, /status, /help commands; per-chat state;
background thread pool for analysis; auto message splitting
- Fix data_provider: warn once per symbol with no API data and cache
synthetic fallback to prevent redundant individual API calls
- Fix signal_aggregator: derive spread estimate from already-fetched
primary DataFrame instead of making a separate M5 API call per pair
- Add python-telegram-bot[job-queue]>=20.0 to requirements.txt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>