Final review fixes: scrub tracked credentials, trim scannable TFs, absolute parity pin, scanning type-checks

Claude-Session: https://claude.ai/code/session_01VPNF37MP9Kuv62B1VBrZ1b
This commit is contained in:
Harwinder Sekhon
2026-07-21 13:42:00 -04:00
parent f017f5aef5
commit 2d3e524f1c
5 changed files with 33 additions and 10 deletions
+2 -2
View File
@@ -24,7 +24,7 @@ This file is the authoritative developer/agent reference. The human-facing docs
| `pair_signals/__init__.py` | 52 | `PAIR_PRODUCERS` registry + `produce_signal()` |
| `pair_signals/xauusd.py` | 71 | XAU config factory + per-timeframe overrides (docstring = validation record) |
| `main.py` | ~348 | CLI: `python main.py --pair XAUUSD --timeframe H1 --detail/--json` |
| `test_all.py` | ~2100 | QA suite: **199 tests in 13 modules**, no live API needed. Must stay green. |
| `test_all.py` | ~2100 | QA suite: **200 tests in 13 modules**, no live API needed. Must stay green. |
| `backtest/gpu_backtest.py` | ~2231 | Bar-replay backtester (CuPy→NumPy fallback) using the real `SignalAggregator` |
| `backtest/diagnose_filters.py` | 609 | Filter-diagnosis tooling |
| `backtest/research/` | — | Calendar research infra (`ff_calendar_scraper.py`, `calendar_store.py`) + result CSVs |
@@ -320,7 +320,7 @@ Data: paginated TD fetches (5000-bar chunks) cached as parquet in `backtest/cach
## test_all.py — QA suite
`python test_all.py` — **199 tests, 13 modules** (config, data_provider, engine, news_engine, signal_aggregator, main, telegram_bot, integration, pair_signals registry + engine-bug regressions, 2026-07-16 audit-fix regressions, chart patterns, app_config). No network needed (mocked). Uses a custom `@test("name")` decorator that runs immediately (NOT pytest — don't grep for `def test_`). Exit code non-zero on failure. Includes: the xauusd-factory ≡ inline-config equivalence test, engine bug-fix regression tests (Module 9b), a live-vs-GPU engine parity sweep incl. the EMA-ribbon path (Module 11), and config.json loading/precedence/validation coverage (Module 13). **Any signal-logic change must keep this green and should add tests.**
`python test_all.py` — **200 tests, 13 modules** (config, data_provider, engine, news_engine, signal_aggregator, main, telegram_bot, integration, pair_signals registry + engine-bug regressions, 2026-07-16 audit-fix regressions, chart patterns, app_config). No network needed (mocked). Uses a custom `@test("name")` decorator that runs immediately (NOT pytest — don't grep for `def test_`). Exit code non-zero on failure. Includes: the xauusd-factory ≡ inline-config equivalence test, engine bug-fix regression tests (Module 9b), a live-vs-GPU engine parity sweep incl. the EMA-ribbon path (Module 11), and config.json loading/precedence/validation coverage (Module 13). **Any signal-logic change must keep this green and should add tests.**
---
+8 -2
View File
@@ -37,8 +37,9 @@ CONFIG_PATH = os.path.join(
_VALID_QUALITIES = ("A+", "A", "B", "C")
_VALID_LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
# Timeframes the bot's candle-boundary scheduler can run (W1 has no loop).
_SCANNABLE_TFS = ("M5", "M15", "M30", "H1", "H4", "D1")
# Timeframes the bot's candle-boundary scheduler supports (must have
# AUTOSCAN_CONFIRMATIONS entries in telegram_bot.py).
_SCANNABLE_TFS = ("M5", "M15", "H1", "H4")
_KNOWN_TOP = {"telegram", "data_providers", "scanning", "pairs", "log_level"}
_KNOWN_TELEGRAM = {"token", "chat_id", "channel_id", "alert_min_quality"}
@@ -127,6 +128,8 @@ def load_app_config(path: str = CONFIG_PATH) -> AppConfig:
_check_keys(scanning, _KNOWN_SCANNING, '"scanning"')
if "pairs" in scanning:
pairs = scanning["pairs"]
if not isinstance(pairs, list):
raise AppConfigError('config.json: scanning.pairs must be a list')
bad = [p for p in pairs if p not in PAIR_INFO]
if bad:
raise AppConfigError(
@@ -135,6 +138,9 @@ def load_app_config(path: str = CONFIG_PATH) -> AppConfig:
app.scan_pairs = list(pairs)
if "timeframes" in scanning:
names = scanning["timeframes"]
if not isinstance(names, list):
raise AppConfigError(
'config.json: scanning.timeframes must be a list')
bad = [n for n in names if n not in _SCANNABLE_TFS]
if bad:
raise AppConfigError(
@@ -644,7 +644,7 @@ Expected: `✗ config.py: hardcoded twelve_data_api_key field is gone` (plus the
- [ ] **Step 3: Implement**
`config.py`: delete line 346 (`twelve_data_api_key: str = "f563b22ffdfd4924955decbe1a8c8701"`).
`config.py`: delete line 346 (`twelve_data_api_key: str = "<TWELVE_DATA_API_KEY>"`).
`data_provider.py` — add to the local imports:
@@ -910,14 +910,14 @@ These are the exact values being deleted from source (from pre-change `telegram_
cat > /home/harwinder/Development/ForexBot2/config.json <<'EOF'
{
"telegram": {
"token": "8228251480:AAFW2OAyQ2idMicql2t_CIXk1r9-qfRTfNE",
"chat_id": "6025899022",
"channel_id": "-1003942265371",
"token": "<TELEGRAM_BOT_TOKEN>",
"chat_id": "<OWNER_CHAT_ID>",
"channel_id": "<CHANNEL_ID>",
"alert_min_quality": "C"
},
"data_providers": {
"active": "twelve_data",
"twelve_data": { "api_key": "f563b22ffdfd4924955decbe1a8c8701" }
"twelve_data": { "api_key": "<TWELVE_DATA_API_KEY>" }
},
"scanning": {
"pairs": ["XAU/USD"],
@@ -932,6 +932,8 @@ EOF
git status --short # config.json must NOT appear (gitignored)
```
(Real values were scrubbed from this doc 2026-07-21 — take them from the previously deployed telegram_bot.py/config.py in git history, and rotate both credentials after merge.)
- [ ] **Step 2: Boot smoke test (no network needed)**
```bash
+13
View File
@@ -2630,6 +2630,8 @@ def _():
{"scanning": {"pairs": ["EUR/USD"]}}, # unknown pair
{"scanning": {"timeframes": ["M7"]}}, # bad TF name
{"scanning": {"timeframes": ["W1"]}}, # unscannable TF
{"scanning": {"pairs": 5}}, # pairs not a list
{"scanning": {"timeframes": 5}}, # timeframes not a list
{"data_providers": {"active": "polygon",
"twelve_data": {"api_key": "k"}}}, # no block
{"telegram": {"alert_min_quality": "Z"}}, # bad quality
@@ -2803,6 +2805,17 @@ def _():
assert "credentials" in str(e)
@test("app_config: absolute parity — default overlay leaves tuned values untouched")
def _():
from pair_signals import PAIR_PRODUCERS
cfg = PAIR_PRODUCERS[XAUUSD](Timeframe.H1, None)
assert cfg.xau_strategy.blocked_hours_utc == [0, 1, 2, 10, 11, 13, 16, 21]
assert cfg.backtest.blocked_hours_utc == [0, 1, 2, 10, 11, 13, 16, 21]
assert cfg.scan_pairs == [XAUUSD]
assert cfg.scan_timeframes == [Timeframe.M5, Timeframe.M15,
Timeframe.H1, Timeframe.H4]
# ══════════════════════════════════════════════════════════════════════
# SUMMARY
# ══════════════════════════════════════════════════════════════════════
+3 -1
View File
@@ -10,7 +10,9 @@ import time
from twelvedata import TDClient
API_KEY = "f563b22ffdfd4924955decbe1a8c8701"
from app_config import provider_api_key
API_KEY = provider_api_key()
SYMBOL = "XAU/USD"
DURATION = 30