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.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+2
-92
@@ -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
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user