filtru Prima per Indicator pe grid FERESTRE CANDIDATE x STRATEGIE
- PrimaWin_<idx> helper columns in Trades (per fereastră) - DASH_WIN_COL dict refactor (zero hardcoded litere) - Coloana Filtru (D) în window grid: rânduri Toate/Prima paralele - Score split T (Score_Toate) + U (Score_Prima), ambele hidden - TOP CANDIDATE: 2 sub-secțiuni — TOP 5 Toate + TOP 5 Prima - Config!B17 escape hatch (DA/NU) pentru performanță - 5 sample rows care exercită Prima edge cases - scripts/verify_template.py: 18 aserțiuni smoke test - .gitignore: data/backtest.backup-*.xlsx - sterse 2 backup-uri vechi din git Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
237
scripts/verify_template.py
Normal file
237
scripts/verify_template.py
Normal file
@@ -0,0 +1,237 @@
|
||||
"""Smoke test for data/backtest.xlsx after regeneration.
|
||||
|
||||
Asserts column positions, sample row formula structure, and TOP CANDIDATE
|
||||
formula sources. Run AFTER `python scripts/generate_template.py`.
|
||||
|
||||
Exit codes: 0 = all PASS, 1 = at least one FAIL, 2 = workbook missing.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
# Romanian diacritics in test names — force UTF-8 stdout on Windows cp1252.
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
except (AttributeError, OSError):
|
||||
pass
|
||||
|
||||
OUTPUT = Path(__file__).resolve().parent.parent / "data" / "backtest.xlsx"
|
||||
|
||||
FAILURES: list[str] = []
|
||||
|
||||
|
||||
def _report(name: str, ok: bool, detail: str = "") -> None:
|
||||
tag = "[PASS]" if ok else "[FAIL]"
|
||||
msg = f"{tag} {name}"
|
||||
if detail:
|
||||
msg += f" -- {detail}"
|
||||
print(msg)
|
||||
if not ok:
|
||||
FAILURES.append(name)
|
||||
|
||||
|
||||
def _find_row_with(ws, col_letter: str, needle: str) -> int | None:
|
||||
"""Return 1-based row where ws[col_letter+row].value == needle, else None."""
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val = ws[f"{col_letter}{row}"].value
|
||||
if val == needle:
|
||||
return row
|
||||
return None
|
||||
|
||||
|
||||
def _find_col_for_header(ws, row: int, needle: str) -> str | None:
|
||||
for col_idx in range(1, ws.max_column + 1):
|
||||
if ws.cell(row=row, column=col_idx).value == needle:
|
||||
return get_column_letter(col_idx)
|
||||
return None
|
||||
|
||||
|
||||
def check_window_grid_headers(wb) -> None:
|
||||
ws = wb["Dashboard"]
|
||||
header_row = _find_row_with(ws, "A", "Fereastra")
|
||||
if header_row is None:
|
||||
_report("Dashboard window grid header row", False, "no row with A='Fereastra'")
|
||||
return
|
||||
_report("Dashboard window grid header row", True, f"row {header_row}")
|
||||
|
||||
expected = {
|
||||
"A": "Fereastra",
|
||||
"D": "Filtru",
|
||||
"E": "Strategie",
|
||||
"F": "N",
|
||||
"S": "Status Edge",
|
||||
"T": "Score_Toate",
|
||||
"U": "Score_Prima",
|
||||
}
|
||||
for col, want in expected.items():
|
||||
got = ws[f"{col}{header_row}"].value
|
||||
if got == want:
|
||||
_report(f"Dashboard header {col}={want!r}", True)
|
||||
else:
|
||||
actual_col = _find_col_for_header(ws, header_row, want)
|
||||
detail = (
|
||||
f"got {got!r} at {col}; expected {want!r}. "
|
||||
f"Header {want!r} actually at column {actual_col}"
|
||||
)
|
||||
_report(f"Dashboard header {col}={want!r}", False, detail)
|
||||
|
||||
|
||||
def check_hidden_columns(wb) -> None:
|
||||
ws = wb["Dashboard"]
|
||||
for col in ("T", "U"):
|
||||
hidden = ws.column_dimensions[col].hidden is True
|
||||
_report(
|
||||
f"Dashboard column {col} hidden",
|
||||
hidden,
|
||||
"" if hidden else f"hidden={ws.column_dimensions[col].hidden!r}",
|
||||
)
|
||||
|
||||
|
||||
def check_primawin_headers(wb) -> tuple[str | None, int]:
|
||||
"""Return (column letter of PrimaWin_0, count of PrimaWin_* headers)."""
|
||||
ws = wb["Trades"]
|
||||
win0_col: str | None = None
|
||||
count = 0
|
||||
for col_idx in range(1, ws.max_column + 1):
|
||||
v = ws.cell(row=1, column=col_idx).value
|
||||
if isinstance(v, str) and v.startswith("PrimaWin_"):
|
||||
count += 1
|
||||
if v == "PrimaWin_0":
|
||||
win0_col = get_column_letter(col_idx)
|
||||
if count == 0:
|
||||
_report("Trades has PrimaWin_* headers", False, "none found")
|
||||
else:
|
||||
_report(
|
||||
"Trades has PrimaWin_* headers",
|
||||
True,
|
||||
f"{count} columns; PrimaWin_0 at column {win0_col}",
|
||||
)
|
||||
return win0_col, count
|
||||
|
||||
|
||||
def check_primawin_formula(wb, win0_col: str | None) -> None:
|
||||
if win0_col is None:
|
||||
_report("PrimaWin_0 sample row formula", False, "no PrimaWin_0 column")
|
||||
return
|
||||
ws = wb["Trades"]
|
||||
formula = ws[f"{win0_col}2"].value
|
||||
if not isinstance(formula, str):
|
||||
_report(
|
||||
"PrimaWin_0 sample row formula",
|
||||
False,
|
||||
f"row 2 value is {formula!r}, not a formula",
|
||||
)
|
||||
return
|
||||
must_have = ["TIME(16,30,0)", "Config!$B$17", "COUNTIFS"]
|
||||
missing = [token for token in must_have if token not in formula]
|
||||
if missing:
|
||||
_report(
|
||||
"PrimaWin_0 sample row formula",
|
||||
False,
|
||||
f"missing tokens: {missing}; formula starts: {formula[:120]!r}",
|
||||
)
|
||||
else:
|
||||
_report("PrimaWin_0 sample row formula", True, "TIME(16,30,0) + Config!$B$17 present")
|
||||
|
||||
|
||||
def check_top_candidate_sources(wb) -> None:
|
||||
ws = wb["Dashboard"]
|
||||
title_toate = "TOP 5 FERESTRE — Toate trade-urile"
|
||||
title_prima = "TOP 5 FERESTRE — Prima per Indicator"
|
||||
|
||||
# Fallback: scan loosely if the em-dash doesn't match.
|
||||
def _find_title(prefix: str) -> int | None:
|
||||
for row in range(1, ws.max_row + 1):
|
||||
v = ws.cell(row=row, column=1).value
|
||||
if isinstance(v, str) and v.startswith(prefix):
|
||||
return row
|
||||
return None
|
||||
|
||||
cases = [
|
||||
("TOP 5 Toate", title_toate, "Toate", "LARGE($T$"),
|
||||
("TOP 5 Prima", title_prima, "Prima per Indicator", "LARGE($U$"),
|
||||
]
|
||||
for name, exact_title, fallback_prefix, expected_token in cases:
|
||||
title_row = _find_row_with(ws, "A", exact_title)
|
||||
if title_row is None:
|
||||
title_row = _find_title(f"TOP 5 FERESTRE")
|
||||
# Narrow: must mention the discriminator
|
||||
title_row = None
|
||||
for row in range(1, ws.max_row + 1):
|
||||
v = ws.cell(row=row, column=1).value
|
||||
if isinstance(v, str) and "TOP 5 FERESTRE" in v and fallback_prefix in v:
|
||||
title_row = row
|
||||
break
|
||||
if title_row is None:
|
||||
_report(f"{name} title found", False, f"no row containing 'TOP 5 FERESTRE' + {fallback_prefix!r}")
|
||||
continue
|
||||
_report(f"{name} title found", True, f"row {title_row}")
|
||||
|
||||
# Look at the next few rows for a LARGE() formula in any column.
|
||||
found = False
|
||||
for offset in (1, 2, 3):
|
||||
scan_row = title_row + offset
|
||||
for col_idx in range(1, ws.max_column + 1):
|
||||
cell = ws.cell(row=scan_row, column=col_idx).value
|
||||
if isinstance(cell, str) and expected_token in cell:
|
||||
_report(
|
||||
f"{name} uses {expected_token}",
|
||||
True,
|
||||
f"row {scan_row} col {get_column_letter(col_idx)}",
|
||||
)
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
if not found:
|
||||
# Sample a formula for diagnostics.
|
||||
sample = ws.cell(row=title_row + 1, column=1).value
|
||||
_report(
|
||||
f"{name} uses {expected_token}",
|
||||
False,
|
||||
f"token not found in rows {title_row+1}..{title_row+3}; sample A: {sample!r}",
|
||||
)
|
||||
|
||||
|
||||
def check_config_escape_hatch(wb) -> None:
|
||||
ws = wb["Config"]
|
||||
a17 = ws["A17"].value
|
||||
b17 = ws["B17"].value
|
||||
_report(
|
||||
"Config!A17 = 'Activează filtru Prima'",
|
||||
a17 == "Activează filtru Prima",
|
||||
f"got {a17!r}",
|
||||
)
|
||||
_report("Config!B17 = 'DA'", b17 == "DA", f"got {b17!r}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not OUTPUT.exists():
|
||||
print(f"Workbook not found: {OUTPUT}")
|
||||
print("RUN python scripts/generate_template.py FIRST")
|
||||
return 2
|
||||
|
||||
wb = load_workbook(OUTPUT, data_only=False)
|
||||
|
||||
print(f"Verifying {OUTPUT}")
|
||||
print("-" * 60)
|
||||
check_window_grid_headers(wb)
|
||||
check_hidden_columns(wb)
|
||||
win0_col, _ = check_primawin_headers(wb)
|
||||
check_primawin_formula(wb, win0_col)
|
||||
check_top_candidate_sources(wb)
|
||||
check_config_escape_hatch(wb)
|
||||
print("-" * 60)
|
||||
if FAILURES:
|
||||
print(f"{len(FAILURES)} FAIL: {FAILURES}")
|
||||
return 1
|
||||
print("ALL CHECKS PASSED")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user