fix: forțează maximize TradeStation la focus + atm debug --canary
Canary drift imediat după /ss, /resume, market_open sau startup când TradeStation nu era maximizat — chart_window_region e absolute, deci orice dimensiune sub full-screen capturează alt conținut și phash-ul diverge. SW_RESTORE pe fereastră zoomed o de-maximiza; acum IsIconic-unminimize + SW_SHOWMAXIMIZED necondiționat. Adaugă atm debug --canary: salvează crop-ul canary ROI + distance vs baseline pentru diagnostic rapid când drift-ul apare în teren. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -123,6 +123,10 @@ def main(argv=None) -> None:
|
||||
"--delay", type=float, default=3.0, metavar="SEC",
|
||||
help="Seconds to wait before capture (bring TradeStation to front first). Default 3.",
|
||||
)
|
||||
p_debug.add_argument(
|
||||
"--canary", action="store_true",
|
||||
help="Diagnostic-only: capture canary ROI, compute phash distance vs baseline, save crop.",
|
||||
)
|
||||
|
||||
# report
|
||||
p_report = sub.add_parser("report", help="Print weekly performance report")
|
||||
@@ -208,6 +212,10 @@ def _focus_window_by_title(needle: str) -> str | None:
|
||||
(protecția anti focus-stealing introdusă în Win2000). Trucul standard:
|
||||
trimiți un ALT press/release ca să resetezi lock-ul, apoi restore +
|
||||
SetForegroundWindow prin ctypes pe hwnd direct.
|
||||
|
||||
Forțează maximize dacă fereastra nu e deja zoomed — `chart_window_region`
|
||||
din calibrare presupune fereastra fullscreen, orice altă dimensiune
|
||||
produce canary drift imediat.
|
||||
"""
|
||||
try:
|
||||
import pygetwindow as gw # type: ignore[import-untyped]
|
||||
@@ -232,7 +240,12 @@ def _focus_window_by_title(needle: str) -> str | None:
|
||||
# VK_MENU=0x12 (ALT), KEYEVENTF_KEYUP=0x02 — unlocks focus protection.
|
||||
user32.keybd_event(0x12, 0, 0, 0)
|
||||
user32.keybd_event(0x12, 0, 0x02, 0)
|
||||
user32.ShowWindow(hwnd, 9) # SW_RESTORE
|
||||
# Dacă e minimizată o scoatem; apoi forțăm maximize necondiționat.
|
||||
# SW_RESTORE pe o fereastră maximizată o de-maximizează — niciodată nu-l
|
||||
# folosim aici (chart_window_region presupune fullscreen).
|
||||
if user32.IsIconic(hwnd):
|
||||
user32.ShowWindow(hwnd, 9) # SW_RESTORE (doar unminimize)
|
||||
user32.ShowWindow(hwnd, 3) # SW_SHOWMAXIMIZED
|
||||
user32.BringWindowToTop(hwnd)
|
||||
user32.SetForegroundWindow(hwnd)
|
||||
return win.title
|
||||
@@ -370,9 +383,16 @@ def _cmd_debug(args) -> None:
|
||||
cfg = Config.load_current(Path("configs"))
|
||||
capture = _build_capture(cfg)
|
||||
|
||||
if cfg.window_title:
|
||||
title = _focus_window_by_title(cfg.window_title)
|
||||
if title:
|
||||
print(f"Focused window: {title!r}", flush=True)
|
||||
else:
|
||||
print(f"WARN: no window contains {cfg.window_title!r} — bring TradeStation to front manually", flush=True)
|
||||
|
||||
delay = getattr(args, "delay", 0.0)
|
||||
if delay > 0:
|
||||
print(f"Bring TradeStation to front. Capturing in {delay:.0f}s...", flush=True)
|
||||
print(f"Capturing in {delay:.0f}s...", flush=True)
|
||||
for i in range(int(delay), 0, -1):
|
||||
print(f" {i}...", flush=True)
|
||||
time.sleep(1.0)
|
||||
@@ -391,6 +411,27 @@ def _cmd_debug(args) -> None:
|
||||
cv2.imwrite(str(full_path), frame)
|
||||
print(f"captured frame: {frame.shape} → {full_path}")
|
||||
|
||||
if getattr(args, "canary", False):
|
||||
from atm.vision import phash, hamming_hex
|
||||
try:
|
||||
canary_crop = crop_roi(frame, cfg.canary.roi)
|
||||
except Exception as exc:
|
||||
sys.exit(f"canary ROI crop failed: {exc}")
|
||||
canary_path = out_dir / f"debug_canary_{ts}.png"
|
||||
cv2.imwrite(str(canary_path), canary_crop)
|
||||
live_hash = phash(canary_crop)
|
||||
distance = hamming_hex(live_hash, cfg.canary.baseline_phash)
|
||||
threshold = cfg.canary.drift_threshold
|
||||
verdict = "DRIFT" if distance > threshold else "ok"
|
||||
roi = cfg.canary.roi
|
||||
print("---")
|
||||
print(f"canary ROI: x={roi.x} y={roi.y} w={roi.w} h={roi.h}")
|
||||
print(f"crop: {canary_crop.shape} → {canary_path}")
|
||||
print(f"baseline: {cfg.canary.baseline_phash}")
|
||||
print(f"live phash: {live_hash}")
|
||||
print(f"distance: {distance}/{threshold} → {verdict}")
|
||||
return
|
||||
|
||||
# crop dot_roi + run detector
|
||||
try:
|
||||
dot_crop = crop_roi(frame, cfg.dot_roi)
|
||||
|
||||
Reference in New Issue
Block a user