fix: WAL-inclusive backup + reachable scorecard GO + complete run log
Browse files
trading/performance_scorecard.py
CHANGED
|
@@ -355,12 +355,42 @@ def evaluate_readiness(
|
|
| 355 |
except Exception:
|
| 356 |
pass
|
| 357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
wf_ok = all_positive and len(wf_results) >= 3 # need at least 3 symbols tested
|
| 359 |
neg = [r for r in wf_results if r["return_pct"] <= 0]
|
| 360 |
checks.append(CheckResult(
|
| 361 |
name="Walk-Forward All Periods Positive",
|
| 362 |
passed=wf_ok,
|
| 363 |
-
current=f"{len(wf_results)} symbols tested, {len(neg)} negative",
|
| 364 |
required="All walk-forward test periods positive (≥3 symbols)",
|
| 365 |
detail=f"Negative: {[r['symbol'] for r in neg]}" if neg else "All positive." if wf_results else "No walk-forward data found.",
|
| 366 |
))
|
|
|
|
| 355 |
except Exception:
|
| 356 |
pass
|
| 357 |
|
| 358 |
+
wf_source = "walk_forward_out csv"
|
| 359 |
+
if not wf_results:
|
| 360 |
+
# PRODUCTION FALLBACK: walk_forward_out/*.csv only ever existed on the
|
| 361 |
+
# offline Mac script — HF containers never produce it (and ephemeral fs
|
| 362 |
+
# would wipe it), which made this check permanently un-passable and GO
|
| 363 |
+
# unreachable. The nightly scan runs the SAME walk_forward_backtest
|
| 364 |
+
# engine per symbol, so use its completed stage2 metrics instead: every
|
| 365 |
+
# ELIGIBLE symbol's full-period strategy return must be positive.
|
| 366 |
+
wf_source = "scan stage2"
|
| 367 |
+
try:
|
| 368 |
+
import json as _json2
|
| 369 |
+
from trading.market_registry import get_scan_results_path as _gsrp
|
| 370 |
+
_sp = _gsrp(market_id, completed=True)
|
| 371 |
+
if _sp.exists():
|
| 372 |
+
_scan2 = _json2.loads(_sp.read_text())
|
| 373 |
+
if _scan2.get("completed"):
|
| 374 |
+
for _sym, _v in (_scan2.get("stage2") or {}).items():
|
| 375 |
+
if not isinstance(_v, dict) or not _v.get("eligible"):
|
| 376 |
+
continue
|
| 377 |
+
_ret = float(_v.get("total_return_pct") or 0.0)
|
| 378 |
+
wf_results.append({
|
| 379 |
+
"symbol": _sym,
|
| 380 |
+
"return_pct": round(_ret, 2),
|
| 381 |
+
"trades": int(_v.get("trades") or 0),
|
| 382 |
+
})
|
| 383 |
+
if _ret <= 0:
|
| 384 |
+
all_positive = False
|
| 385 |
+
except Exception:
|
| 386 |
+
pass
|
| 387 |
+
|
| 388 |
wf_ok = all_positive and len(wf_results) >= 3 # need at least 3 symbols tested
|
| 389 |
neg = [r for r in wf_results if r["return_pct"] <= 0]
|
| 390 |
checks.append(CheckResult(
|
| 391 |
name="Walk-Forward All Periods Positive",
|
| 392 |
passed=wf_ok,
|
| 393 |
+
current=f"{len(wf_results)} symbols tested ({wf_source}), {len(neg)} negative",
|
| 394 |
required="All walk-forward test periods positive (≥3 symbols)",
|
| 395 |
detail=f"Negative: {[r['symbol'] for r in neg]}" if neg else "All positive." if wf_results else "No walk-forward data found.",
|
| 396 |
))
|