backtest cleanup: drop four research/one-time scripts; books and stale cache moved out (owner decisions 2026-09-15)

Discussion-first cleanup of backtest/ and scripts/. Nothing in the signal
core or the backtester changed.

Removed (last commit containing them: 931b265):
- backtest/diagnose_filters.py + its two Module 18 tests
- scripts/shadow_scan.py (Phase 4 shadow scan, never run)
- scripts/backfill_news_archive.py, scripts/migrate_signal_log_news.py
  (one-time scripts; the interning test keeps its live-path half, the
  prune test goes)

Kept: the replay-recording stack (replay_record.py, replay_scorecard.py,
ff_calendar_scraper.py, cache/calendar.parquet, Module 33).

Local gitignored data was moved to ~/Development/ForexBot2_trash_2026-09-15
(346 MB) for the owner to delete: all 35 pinned backtest/*.csv books, the
three research output folders, the BTC/ETH cache snapshots, the Tiingo
parquets and 13 uncited Oanda windows. The three research-folder ignore
rules are dropped with the folders.

Verification: all five gate books regenerate offline from the pruned cache
with the recorded MD5s (M5 W2 29120a1e, M15 W2 d185f099, M15 OOS 6f8f24b4,
H1 W3 3b45d12b, H4 W3 e75adae1; NumPy CPU, 0 cache fallbacks). Suite
506 passed, 0 failed, 33 modules.
This commit is contained in:
Harwinder Sekhon
2026-09-15 20:15:06 -04:00
parent c916ecf213
commit 9adaee65d2
7 changed files with 9 additions and 1327 deletions
+2 -92
View File
@@ -4544,10 +4544,10 @@ def _():
# ══════════════════════════════════════════════════════════════════════
# MODULE 18: --set research override + diagnose_filters tag freshness
# MODULE 18: --set research override
# ══════════════════════════════════════════════════════════════════════
print("\n═══ Module 18: --set override + diagnose tags ═══")
print("\n═══ Module 18: --set override ═══")
@test("--set: nested float/bool/JSON-list overrides apply with typing")
@@ -4603,42 +4603,6 @@ def _():
assert _parse_args(["--pair", "XAUUSD"]).set == []
@test("diagnose_filters: every filter tag has a live emitter (staleness guard)")
def _():
import inspect
import diagnose_filters
import signal_aggregator as sa
src = inspect.getsource(sa)
tag_src = inspect.getsource(diagnose_filters.classify_bar)
# Extract the tag strings from the ordered list in classify_bar.
import re
tags = re.findall(r'\("([^"]+)",\s+"[A-Z0-9_]+"\)', tag_src)
assert len(tags) >= 25, f"tag extraction broke: found {len(tags)}"
for tag in tags:
assert tag in src, f"filter tag '{tag}' has no emitter in signal_aggregator.py"
@test("diagnose_filters: one tag per warning, specific prefix wins")
def _():
import diagnose_filters as d
from signal_aggregator import SignalReport
class _R:
pass
r = _R()
r.warnings = [
"M5 FILTER: SELL quality A capped — high-conviction M5 shorts enter at extremes",
"SELL FILTER: 15:00 UTC entry blocked for shorts",
"TREND EXHAUSTION — price extended >3.5 ATR past swing high",
]
r.final_signal = SignalStrength.SELL
r.signal_quality = "D"
r.trade_setup = None
outcome, hits = d.classify_bar(r, True)
assert outcome == "LOW_QUALITY"
assert hits == ["M5_SELL_QUALITY", "SELL_HOUR", "TREND_EXHAUSTION"], hits
# ══════════════════════════════════════════════════════════════════════
# MODULE 19: DeepSeek news enrichment (llm_client + news_engine seams)
# ══════════════════════════════════════════════════════════════════════
@@ -8827,7 +8791,6 @@ def _():
def _():
import sqlite3
import signal_log as slog
from scripts.migrate_signal_log_news import migrate, prune_orphans
fd, path = tempfile.mkstemp(suffix=".db")
os.close(fd)
try:
@@ -8859,19 +8822,6 @@ def _():
"SELECT id, headlines_resolved FROM signals_with_news").fetchall())
assert json.loads(view[legacy_id])[0]["headline"] == "legacy"
assert json.loads(view[r2])[0]["headline"] == "Fed signals rate hike"
# migration moves the legacy blob and is idempotent
stats = migrate(lg._conn)
assert stats["rows"] == 1 and stats["headlines_interned"] == 1
assert migrate(lg._conn)["rows"] == 0
row = lg._conn.execute(
"SELECT headlines_json, headlines_hash FROM signals WHERE id=?",
(legacy_id,)).fetchone()
assert row[0] is None and row[1]
assert json.loads(slog.read_news(lg._conn, legacy_id)[1])[0][
"headline"] == "legacy"
lg._conn.execute("DELETE FROM signals WHERE id=?", (legacy_id,))
lg._conn.commit()
assert prune_orphans(lg._conn) == 2, "legacy headline + event blobs"
lg.close()
finally:
slog.reset_loggers_for_tests()
@@ -9127,46 +9077,6 @@ def _():
"a real evaluator fault must be visible in the log"
@test("migrate: prune_news_older_than prunes the cutoff calendar day")
def _():
import sqlite3
import importlib.util
spec = importlib.util.spec_from_file_location(
"_mig_test", os.path.join(os.path.dirname(os.path.abspath(__file__)),
"scripts", "migrate_signal_log_news.py"))
mig = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mig)
fd, path = tempfile.mkstemp(suffix=".db")
os.close(fd)
try:
con = sqlite3.connect(path)
con.execute("CREATE TABLE signals (id INTEGER PRIMARY KEY,"
" logged_at TEXT, headlines_hash TEXT, events_hash TEXT)")
con.execute("CREATE TABLE news_snapshots (hash TEXT PRIMARY KEY,"
" body TEXT)")
now = datetime.now(timezone.utc)
# Genuinely older than the 30-day cutoff, but on the SAME calendar
# day as it — the case the raw string compare put on the wrong side
# ('T' sorts after ' ').
boundary = (now - timedelta(days=30)).replace(
hour=0, minute=0, second=1, microsecond=0).isoformat()
con.executemany(
"INSERT INTO signals VALUES (?,?,?,?)",
[(1, boundary, "h1", "e1"), (2, now.isoformat(), "h2", "e2")])
con.executemany("INSERT INTO news_snapshots VALUES (?,?)",
[("h1", "{}"), ("e1", "{}"), ("h2", "{}"), ("e2", "{}")])
con.commit()
n = mig.prune_news_older_than(con, 30)
assert n == 1, f"the cutoff-day row must prune, got {n}"
kept = con.execute(
"SELECT headlines_hash FROM signals ORDER BY id").fetchall()
assert kept == [(None,), ("h2",)], kept
con.close()
finally:
os.unlink(path)
# ══════════════════════════════════════════════════════════════════════
# MODULE 29: stake-multiplier sizing — features + record-keeping
# ══════════════════════════════════════════════════════════════════════