Output din live loop (auto-capture pe schimbare de culoare) pentru sesiunea de azi. Filename = culoare detectată de FSM (poate fi greșită). Următorul pas manual: review și label-uire în calibration_labels.json pentru atm validate-calibration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ATM — Monitor Automat de Trading
Tool personal pentru strategia M2D. Urmărește banda de puncte colorate M2D MAPS de pe un chart TradeStation, rulează o mașină de stări pe faze (ARMED → PRIMED → FIRE) și trimite alerte pe Discord + Telegram cu screenshot adnotat la fiecare semnal BUY/SELL. Execuția trade-ului o faci tu manual în TradeLocker.
Fără execuție automată. Faza 2 (auto-execute) e blocată de auditul TOS prop-firm — vezi docs/phase2-prop-firm-audit.md.
Cum e organizat proiectul
atm/
├── configs/ # calibrări + current.txt (marcaj care config e activ)
├── calibration/ # corpus auto-suficient pentru validare + regresie
│ ├── calibration_labels.json # etichete per-frame pentru atm validate-calibration
│ ├── scenarios.json # secvențe FSM (arm→prime→trigger etc.) pentru test_scenarios_regression.py
│ ├── frames/ # PNG-uri numite {ts}_{color}.png, izolate de logs/fires și samples
│ └── README.md
├── logs/
│ ├── YYYY-MM-DD.jsonl # audit zilnic, se rotește la miezul nopții local
│ ├── dead_letter.jsonl # alerte care au eșuat după retries
│ ├── fires/ # screenshot-uri adnotate, unul per trigger BUY/SELL (tranzitoriu, se poate goli)
│ └── calibrate_capture_*.png / debug_*.png # artefacte debug (gitignored)
├── samples/ # frame complet salvat automat la fiecare schimbare de culoare (tranzitoriu)
├── src/atm/ # pachetul Python
│ ├── config.py # dataclass + loader TOML
│ ├── vision.py # crop ROI, phash, pixel↔preț, Hough, componente conectate
│ ├── state_machine.py # FSM 5 stări + lockout per direcție
│ ├── detector.py # capture → crop → găsește dot-ul rightmost → clasifică → debounce
│ ├── canary.py # watchdog layout via phash drift + flag de pauză
│ ├── levels.py # extracție SL/TP pe Faza-B
│ ├── notifier/ # FanoutNotifier + webhook Discord + bot Telegram
│ ├── audit.py # JSONL line-buffered, rotație zilnică
│ ├── calibrate.py # wizard Tk (selectează regiune + click pe culori)
│ ├── labeler.py # UI Tk → labels.json
│ ├── dryrun.py # replay pe corpus, gate precision/recall
│ ├── validate.py # gate offline de clasificare a culorilor
│ ├── journal.py # înregistrări trade-uri
│ ├── report.py # raport săptămânal PnL în R
│ └── main.py # CLI unificat
├── tests/ # 192 teste pytest (184 core + 8 scenarii regresie)
└── TODOS.md # backlog P1/P2/P3
Instalare
Python 3.11+.
Windows (producție)
python -m venv .venv
.venv\Scripts\activate
pip install -e ".[windows]"
# → creează .venv\Scripts\atm.exe
atm --help
[windows] aduce mss, pygetwindow, pywin32. Fără venv, pip install -e ".[windows]" direct în Python-ul global funcționează la fel.
Pornire rapidă cu scriptul inclus — instalează automat la primul run:
atm.bat # prima rulare: pip install + atm run
atm.bat run --stop-at 23:00
atm.bat debug
WSL / Linux (dev + teste)
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
[dev] aduce pytest, pytest-cov, pytest-asyncio. Nu include dependențele Windows (mss, pygetwindow, pywin32) — nu rulează capture live.
Secrets
Credențialele Discord/Telegram NU se țin în TOML — trăiesc în .env la rădăcina proiectului:
cp .env.example .env
# apoi editezi .env cu valorile reale
Variabile necesare:
| Variabilă | Ce e |
|---|---|
ATM_DISCORD_URL |
Webhook URL-ul Discord (canalul unde vin alertele) |
ATM_TG_TOKEN |
Token-ul bot-ului Telegram (de la @BotFather) |
ATM_TG_CHAT |
Chat ID (group-ul sau user-ul; prefix - pentru group) |
.env e în .gitignore — secretele nu ajung pe git. configs/*.toml pot fi comise pe git (calibrare pură, safe to version).
La pornire, dacă .env e găsit, loader-ul printează pe stderr:
[atm.config] .env: loaded 3 vars (0 overridden by shell)
⚠️ Shell env wins peste .env. Dacă ai făcut export ATM_TG_TOKEN=... cândva în .bashrc / profil, aceasta override-uiește .env — verifică cu printenv | grep ATM_. Mesajul (N overridden by shell) te avertizează când se întâmplă.
Config-ul se refuză să pornească dacă:
- lipsește oricare din cele 3 variabile (mesaj cu numele variabilei + hint către
.env.example); ATM_DISCORD_URLsauATM_TG_TOKENconțineREPLACE_ME(ai copiat.env.exampledar n-ai editat);ATM_TG_CHATnu-i numeric (opțional cu-la început pentru group).
Dev
pytest -q # toate testele (192+)
pytest tests/test_commands.py # un modul specific
pytest tests/test_scenarios_regression.py -v # scenarii FSM pe imagini reale
pytest -q --cov=atm --cov-report=term-missing # cu coverage
Smoke-test fără Windows (stub de captură din samples/):
atm run --capture-stub --duration 0.05
Structura testelor:
| Fișier | Ce acoperă |
|---|---|
test_commands.py |
parsing comenzi Telegram |
test_config.py |
loader TOML, attach_screenshots |
test_handle_tick.py |
loop principal, snapshot, FSM |
test_main.py |
lifecycle, operating hours, canary, dispatcher |
test_validate.py |
gate offline clasificare culori |
test_canary.py |
drift + callback pauză |
test_scenarios_regression.py |
secvențe FSM pe frame-uri reale (arm→prime→trigger, phase_skip, catchup, post-fire suppression) |
Calibrare
Se face o singură dată per layout de chart. Trebuie să ruleze pe mașina pe care face capture live (Windows, fizic — nu RDP/virtual).
atm calibrate # countdown 3s default; pune --delay 10 dacă vrei mai mult timp
Flow:
- Dialog: substring din titlul ferestrei chart-ului (ex.
TradeStationsauDIA). Se salvează în config pentru auto-focus ulterior. - Mesaj "Ready?" → click OK → countdown 3s în terminal. Alt-tab pe TradeStation, minimizează tot ce-l acoperă.
- Se face screenshot full-desktop, apare o fereastră Tk scalată.
- Trage un dreptunghi peste chart (include și banda M2D MAPS). Enter = confirmă. Esc = anulează.
- Click pas cu pas pe regiunea selectată:
- M2D MAPS strip: colț stânga-sus + colț dreapta-jos
- Un click pe fiecare culoare: turquoise, yellow, dark_green, dark_red, light_green, light_red, gray + background (8 total — "Skip" dacă o culoare nu-i vizibilă acum)
- Chart: colț stânga-sus + colț dreapta-jos (pentru detecția de linii în Faza-B)
- Două prețuri cunoscute pe axa Y (pixel y → introduci prețul)
- Canary: colț stânga-sus + colț dreapta-jos pe un element UI stabil (etichetă axă, bară titlu)
- Save → scrie
configs/YYYY-MM-DD-HHMM.toml+ marcajconfigs/current.txt. TOML-ul conține doar calibrare — secretele Discord/Telegram se țin în.envla rădăcina proiectului (vezi secțiunea Secrets de mai jos).
⚠️ Reguli critice la calibrare (evită incidentul 2026-04-17)
1. Click EXCLUSIV pe dot-ul din DREAPTA al strip-ului. Banda M2D MAPS e istoric: dot-ul din dreapta = activ/curent, restul sunt mai vechi. TradeStation desenează dot-ul activ mai strălucitor decât cele vechi. Detector-ul live citește MEREU dot-ul din dreapta. Dacă dai click pe unul din stânga, culoarea calibrată e mai întunecată decât realitatea → clasificare greșită live (dark_red poate ajunge citit ca light_red, de exemplu).
2. Canary pe un pixel STATIC. NU pune regiunea canary peste: volume bar, preț curent, ceas/timestamp. Orice se schimbă natural în acea zonă declanșează drift-pause silent → bot-ul se oprește din detecție fără alertă vizibilă (asta s-a întâmplat la 22:25 pe 17.04, drift=129). Alege: o etichetă de axă, un titlu de panel, un colț de bordură.
3. Calibrează în mijlocul unei sesiuni active, nu dimineața înainte de deschidere. Dot-urile sunt clar vizibile și reflectă exact aceleași setări de rendering ca la live.
Ce scrie în TOML
chart_window_region = {x, y, w, h}— dreptunghi absolut virtual-desktop. Capture-ul la runtime crop-ează exact aceeași cutie, deci fereastra nu trebuie mutată după calibrare.dot_roi,chart_roi,canary.roi— coordonate relative la regiunea selectată.- RGB per culoare (eșantionat cu saturation-snap într-o rază de 15px de click, media unui box 5x5 în jurul pixelului snapped).
y_axis— pereche de interpolare liniară.canary.baseline_phashal ROI-ului canary.
Tips de sampling:
- Click pe culori chiar vizibile acum în istoricul dot-urilor. Dacă o culoare nu-i vizibilă, skip —
atm dryrunîți zice dacă valoarea ratată nu se potrivește cu dot-uri reale. - Tolerance default: 60 pentru dot-uri, 25 pentru background. Strângi în TOML după dryrun dacă apar misclasificări.
Smoke-test după calibrare
atm debug --delay 5
Ia un frame. Salvează logs/debug_full_<ts>.png, logs/debug_dot_roi_<ts>.png, logs/debug_annotated_<ts>.png. Tipărește:
window_found: True
dot_found: True
rgb: (114, 114, 114)
classified: gray distance=24 confidence=0.79
accepted: True color=gray
Deschizi PNG-ul adnotat: dreptunghi galben = dot_roi, cerc roșu = dot detectat. Cercul trebuie să pice pe dot-ul colorat cel mai din dreapta din banda M2D MAPS. Dacă nu:
- Cerc la mijloc de strip → alt window e sub regiunea de capture (adu TradeStation în față).
- Cerc pe element UI non-dot →
dot_roiprea larg; recalibrează mai îngust. color=None+UNKNOWN→ tolerances prea strânse SAU RGB-urile eșantionate nu se potrivesc cu dot-urile reale; recalibrează cu click pe dot-uri reale.
Validare offline a calibrării
Verifici dacă calibrarea actuală clasifică corect un set de frame-uri etichetate manual, fără să aștepți sesiunea live. Esențial după orice recalibrare.
atm validate-calibration calibration/calibration_labels.json
Format input (calibration/calibration_labels.json):
[
{"path": "calibration/frames/20260420_171501_yellow.png", "expected": "yellow"},
{"path": "calibration/frames/20260420_172104_dark_red.png", "expected": "dark_red"},
{"path": "calibration/frames/20260420_173004_light_red.png", "expected": "light_red"}
]
Frame-urile sunt copiate în calibration/frames/ cu numele {timestamp}_{culoare}.png
— numele reflectă ground truth-ul vizibil pe dot, nu label-ul de eveniment din
logs/fires/. Directorul e auto-suficient: samples/ și logs/fires/ se pot
goli oricând fără să afecteze validarea.
Output: per fiecare frame PASS/FAIL + culoarea detectată + top 3 candidați după distanță RGB + sugestii de pixel pentru misclasificări.
Exit code:
0— 100% PASS (poți porni live în siguranță)1— cel puțin un FAIL2— input invalid/lipsă
Trei surse de frame-uri, roluri distincte
| Sursă | Unde se salvează | Cum se populează | Folosit de |
|---|---|---|---|
calibration/frames/ |
PNG-uri curate {ts}_{color}.png |
manual — copii din logs/fires/ doar cele verificate |
atm validate-calibration + test_scenarios_regression.py |
samples/ |
frame complet la fiecare schimbare de culoare detectată | automat de atm run |
atm label + atm dryrun |
logs/fires/ |
screenshot adnotat la fiecare alertă BUY/SELL, /ss manual, interval automat /3 |
manual sau scheduler | sursă pentru calibration/frames/ |
calibration/ e singurul director persistent. Celelalte două se pot goli
după ce ai extras ce-ți trebuie — tranzitorii prin natură.
Regresie FSM pe frame-uri reale
calibration/scenarios.json definește secvențe ordonate (arm → prime → trigger,
phase_skip, catchup, suprimare dark_* post-fire) care refolosesc aceleași frame-uri.
tests/test_scenarios_regression.py rulează fiecare secvență prin pipeline-ul real
Detector → _handle_tick, asertând per pas: culoarea detectată, tranziția FSM
(prev→next + reason + trigger), alertele emise prin notifier, și starea
scheduler-ului (running/stopped).
Extensii fără cod nou: adaugi un scenariu în JSON și pytest-ul îl consumă automat
(parametrizat pe id). Dacă scenariul cere o combinație de culori noi, copii
frame-ul în calibration/frames/ cu numele {timestamp}_{culoare}.png.
Flow A — calibrare fină cu screenshots automate (/3)
Util când vrei să acumulezi repede frame-uri din culori reale, fără să aștepți schimbări de culoare.
- În sesiunea live, trimite
/3în Telegram → bot-ul face screenshot automat la 3 minute și îl salvează înlogs/fires/*_ss.png. Oprești cu/stop. - După sesiune, adaugi intrări în
calibration/calibration_labels.jsonpentru fiecare screenshot relevant, cu culoarea pe care ai văzut-o TU pe chart:{"path": "logs/fires/20260420_151234_ss.png", "expected": "dark_green", "note": "văzut live, ratat de bot"} - Rulează validarea:
atm validate-calibration calibration/calibration_labels.json - Interpretează rezultatul:
- Toate PASS → calibrarea ține, continui live fără modificări.
- Măcar un FAIL → output-ul îți arată pixelul real (ex.
RGB(128, 0, 0)), centrul curent din TOML (ex.dark_red RGB(83, 0, 0)) și distanța. Două opțiuni:- Fix tactic rapid: editezi TOML-ul direct, muți centrul culorii aproape de pixelul observat. Rulezi iar
validate-calibration. Te oprești când e PASS. - Fix complet: la următoarea sesiune live completă, rulezi
atm calibratede la zero pe Windows, cu disciplina cele 3 reguli critice de mai sus (rightmost dot, pixel static pentru canary, în timpul unei sesiuni active).
- Fix tactic rapid: editezi TOML-ul direct, muți centrul culorii aproape de pixelul observat. Rulezi iar
- Acumulezi mai multe samples în timp. Obiectiv: 2-3 intrări per culoare în
calibration_labels.json. Cu cât fișierul are mai multe etichete, cu atât calibrarea următoare e validată mai solid.
Flow B — gate de precizie pe corpus de schimbări de culoare
atm run salvează automat în samples/ un frame complet la fiecare schimbare de culoare detectată. După sesiune:
atm label samples # UI Tk — etichetezi fiecare frame cu culoarea reală văzută pe chart
atm dryrun samples # replay prin detector + FSM; exit 0 dacă precision=100%, recall≥95%
Dacă gate-ul pică, ajustezi tolerance per culoare în TOML sau corectezi eșantioanele nepotrivite, apoi rulezi iar atm dryrun până trece.
Workflow de corectare iterativă (când apare o alertă greșită live)
Scenariu: ai rulat o sesiune live, ai văzut pe chart o culoare pe care bot-ul n-a detectat-o (sau a detectat greșit).
- În timpul sesiunii — două opțiuni pentru a captura dovezi:
/ssîn Telegram → un screenshot instant înlogs/fires//3în Telegram → screenshots automate la 3 min înlogs/fires/(util dacă nu ești la monitor continuu); oprești cu/stop
- După sesiune, adaugi intrările relevante în
calibration/calibration_labels.jsoncu culoarea corectă și ruleziatm validate-calibration(Flow A de mai sus). - Dacă apar FAIL-uri, aplici fix tactic în TOML sau recalibrezi complet.
Exemplu real — incidentul 2026-04-17
La 20:53 s-a afișat un dark_red pe chart dar bot-ul l-a citit ca light_red (alertă ratată). Root cause: calibrarea anterioară (2026-04-16-0703.toml) a fost făcută dând click pe dot-uri istorice (mai întunecate), nu pe dot-ul activ din dreapta.
Fix aplicat în 2026-04-18-1220.toml, pe bază de evidență live:
| Culoare | Centru vechi | Pixel live observat | Centru nou |
|---|---|---|---|
| dark_red | (83, 0, 0) | (128, 0, 0) | (128, 0, 0) |
| light_red | (153, 0, 0) | (171, 0, 0) | (171, 0, 0) |
| dark_green | (0, 77, 0) | — | (0, 122, 0) (ajustat proporțional: +45 pe G) |
| light_green | (0, 153, 0) | — | (0, 171, 0) (ajustat proporțional: +18 pe G) |
yellow, turquoise, gray, background — lăsate neschimbate (nu am dovezi live care să justifice ajustarea).
După fix: atm validate-calibration → 3/3 PASS, confidence 1.00 pe ambele roșuri.
Exemplu real — incidentul 2026-04-20/21 (culori saturate)
User a observat screenshot-uri poll periodice după ce un trigger BUY/SELL părea deja declanșat. Dovadă: logs/fires/20260420_214908_poll.png avea pixel verde pur (0, 255, 0) (trigger light_green) dar detector-ul îl clasifica UNKNOWN. Investigație: 27/114 PNG-uri din corpus ieșeau UNKNOWN pentru că paleta din 2026-04-18-1220.toml avea centrele celor patru culori luminoase prea întunecate — distanța până la pixelul real depășea toleranța de 60.
Fix aplicat în 2026-04-21-recalib.toml:
| Culoare | Centru vechi | Pixel live observat | Centru nou | d(vechi) |
|---|---|---|---|---|
| turquoise | (0, 153, 153) | (0, 253, 253) | (0, 253, 253) | 141 |
| yellow | (153, 153, 0) | (253, 253, 0) | (253, 253, 0) | 141 |
| light_green | (0, 171, 0) | (0, 255, 0) | (0, 255, 0) | 84 |
| light_red | (171, 0, 0) | (255, 0, 0) | (255, 0, 0) | 84 |
dark_green, dark_red, gray, background — neschimbate (nu ieșeau UNKNOWN).
Consecință invizibilă pentru user: fără trigger acceptat de FSM, starea rămânea blocată în PRIMED_* → ScreenshotScheduler nu primea reason=fire/cooled/phase_skip/opposite_rearm → polling continuu la 3 min ore în șir.
După fix: corpus 27→0 UNKNOWN pe culorile luminoase (restul 9 sunt pixeli off-ROI crem, nu dot-uri). atm validate-calibration calibration/calibration_labels.json → 16/16 PASS.
Lesson learned: la recalibrare cu wizard-ul Tk, dacă folosești o imagine screenshot (nu captură live), pipeline-ul de saturation-snap poate rata pixelul cel mai saturat și să ia un dot ușor desaturat. Regulă: după wizard, verifică imediat cu atm validate-calibration pe un corpus cu toate 7 culorile. Dacă vreo culoare iese UNKNOWN, corectează manual în TOML cu pixelul real observat.
Rollback dacă ceva merge prost:
echo "2026-04-18-1220.toml" > configs/current.txt # sau 2026-04-16-0703.toml
Sesiunea live
# Sesiunea de azi 16:30–23:00 România local
atm run --start-at 16:30 --stop-at 23:00
# Fără limită
atm run
# Durată fixă (ore)
atm run --duration 2
# Linux/WSL smoke (rulează pe fișiere din samples/)
atm run --capture-stub --duration 0.05
Startup:
- Așteptare wall-clock până la
--start-at(dacă e setat). pygetwindow.activate()pe prima fereastră care conținecfg.window_title— aduce TradeStation în față (restaurează dacă-i minimizată).- Countdown 5s (
--startup-delay). - Primul frame + check canary. Status (
drift=X/Ysaucapture_failed) e inclus în ping-ul de start. - Ping "ATM started" pe Discord + Telegram.
- Loop principal: la fiecare
loop_interval_s(default 5s) — capture → canary → detect → FSM → poate notifică → poate Faza-B. - La
--stop-at(sau--duration): ping "ATM stopped", apoi exit.
Comportament per ciclu:
- Drift canary → auto-pause + alertă Telegram single-shot (
⚠️ Canary drift=N — monitorizare pauzată). Anulezi cu/resume forceîn Telegram, sau repornești cu flag-ul de pauză șters. - Detector raportează UNKNOWN → rămâne în starea curentă (loghează
noise). - Schimbare de culoare → frame complet salvat în
samples/YYYYMMDD_HHMMSS_<color>.png(pentru corpus). - FIRE (BUY/SELL, nu locked) → PNG adnotat salvat în
logs/fires/, atașat la alertă,LevelsExtractorarmed. - Phase-skip backstop (
fire_on_phase_skip=truedefault) → ARMED → light_red/light_green direct (dark_* ratat) emite totuși alertă⚠️ PHASE SKIPcu screenshot. Lockout-ul FSM previne spam. - Faza-B completă → push "Levels SL=… TP1=… TP2=…".
- Heartbeat la fiecare
heartbeat_minminute.
Ține PowerShell minimizat în timpul sesiunii ca să nu acopere TradeStation.
Fereastra orelor de trading
Configurezi din TOML (sursă adevăr: NYSE local, timezone-aware — DST-ul e gestionat automat):
[options.operating_hours]
enabled = true
timezone = "America/New_York" # validat fail-fast la load
weekdays = ["MON", "TUE", "WED", "THU", "FRI"]
start_hhmm = "09:30" # deschidere NYSE
stop_hhmm = "16:00" # închidere NYSE
Tick-urile din afara ferestrei sunt skipped (logged doar la tranziție). La traversarea boundary-ului bot-ul emite market_open / market_closed în Telegram — o singură dată per tranziție. Pornirea în-fereastră nu emite alertă spurioasă.
Override din CLI (bat TOML-ul):
atm run --tz America/New_York --weekdays MON,TUE,WED,THU,FRI --oh-start 09:30 --oh-stop 16:00
--oh-start / --oh-stopsunt diferite de--start-at / --stop-at.--start-at / --stop-at= wall-clock session bounds (când pornește procesul și când se oprește).--oh-start / --oh-stop= fereastra NYSE în care detecția rulează efectiv în interiorul sesiunii. Se combină.
Comenzi Telegram
Trimiți în chat-ul bot-ului:
| Comandă | Efect |
|---|---|
/ss sau /screenshot |
Screenshot acum |
/status |
Stare FSM + motiv pauză + fereastră open/closed |
/pause |
Suspendă detecția (heartbeat-urile continuă) |
/resume |
Elimină DOAR pauza user. Dacă Canary e drift-paused, rămâne paused — folosește /resume force |
/resume force |
Elimină și drift-pause-ul canary (după recalibrare) |
/3 sau /interval 3 |
Interval auto-screenshot = 3 min |
/stop |
Oprește scheduler-ul de screenshot |
/h sau /help |
Listă scurtă a tuturor comenzilor disponibile |
Doar allowed_chat_ids sunt acceptate. După 3 401 consecutive, poller-ul intră în mod degradat.
După sesiune
atm label samples # UI Tk — etichetezi fiecare frame salvat cu culoarea reală
atm dryrun samples # replay prin detector + FSM; exit 0 dacă precision=100%, recall≥95%
Dacă gate-ul pică, ajustezi tolerance per culoare în configs/<current>.toml, sau recalibrezi eșantioanele care n-au potrivit. Rulezi iar atm dryrun până trece. Numai atunci ai încredere în semnalele live.
Pentru calibrare fină a clasificării de culori (Flow A cu /3), vezi secțiunea Validare offline a calibrării de mai sus.
Evidență trade-uri:
atm journal # înregistrare interactivă după un trade real
atm report --week 2026-16 # win rate săptămânal + PnL în R + slippage
Note DPI / multi-monitor
- Regiunea din calibrare e absolută virtual-desktop; runtime capture folosește același dreptunghi. Nu muta fereastra TradeStation după calibrare. Canary prinde drift-ul și pauzează automat.
- Schimbi DPI scaling sau muți pe un alt monitor cu DPI diferit → recalibrezi.
- RDP / desktop virtual:
msspoate returna frame-uri negre peste RDP. Rulează local pe aceeași mașină fizică pe care e TradeStation.
Troubleshooting
| Simptom | Cauză probabilă | Fix |
|---|---|---|
capture_failed în ping-ul de start |
chart_window_region referă coords off-screen (alt layout monitor) |
Recalibrează. |
Canary la startup arată drift=X/8 cu X ≫ 8 |
Alt window e în regiunea de capture | TradeStation trebuie să fie ferestra la cfg.chart_window_region. Relansează. |
WARN: no window contains 'xxx' la start |
cfg.window_title nu prinde nimic |
Editează window_title în TOML cu un substring unic pentru TradeStation. |
| Nu vin alerte deși ar trebui | Verifică logs/YYYY-MM-DD.jsonl — event=frame au culoare acceptată? trigger setat? |
Dacă mereu UNKNOWN → tolerances prea strânse SAU RGB-urile calibrate nu se potrivesc. Rulează atm validate-calibration. Dacă trigger dar locked=true → lockout de la fire anterior, normal. |
| Alertă pe culoare greșită (ex. dark_red → light_red) | Calibrarea a luat dot istoric, nu activ | Rulează atm validate-calibration. Corectezi tactic în TOML sau recalibrezi cu regula rightmost dot. |
| Discord OK, Telegram tace (sau invers) | logs/dead_letter.jsonl are alertele eșuate + eroarea |
Fixezi credențiale în TOML, restart. |
Heartbeat arată telegram: failed > 0 |
Telegram a răspuns ok:false |
Check logs/dead_letter.jsonl pentru error_str / description. Comun: bot-ul nu-a fost pornit de user în Telegram, sau chat_id greșit (channel vs group vs DM). |
| Bot-ul "moare" după N ore, heartbeat merge dar comenzile nu răspund | Era bug-ul de hang din 2026-04-17 — drain coadă de comenzi sărit când Canary paused | Fixat în c5024ce. Update git pull. |
| Poll-uri periodice continuă deși un trigger BUY/SELL s-a afișat pe chart | Trigger-ul a ieșit UNKNOWN (pixel saturat, paletă întunecată) → FSM blocat în PRIMED → scheduler nu primește fire/cooled/phase_skip |
Rulează atm validate-calibration calibration/calibration_labels.json. Dacă vreo culoare luminoasă iese UNKNOWN, actualizezi centrul RGB în TOML la pixelul real observat. Vezi incidentul 2026-04-20/21. |
Windows Task Scheduler (producție)
Pentru rulare automată zilnică care supraviețuiește reboot-urilor:
- Task Scheduler → Create Task → nume
ATM M2D Monitor - General: "Run only when user is logged on", "Run with highest privileges"
- Triggers: New → Daily, Start
16:30 - Actions: New → Program
C:\path\to\python.exe, Arguments-m atm run --stop-at 23:00, Start inD:\PROIECTE\atm - Conditions: debifează "Start only if AC power" (dacă e laptop)
- Settings: "If task runs longer than 7 hours → stop"
Click-right → Run, să testezi manual. Check DST schimbare de două ori pe an (prima săptămână din martie / octombrie).
Referință rapidă comenzi
atm calibrate [--screenshot PATH] [--delay SEC] # wizard Tk
atm debug [--delay SEC] # one-shot capture + detect
atm label SAMPLES_DIR # etichetare Tk
atm dryrun SAMPLES_DIR # gate pe corpus
atm validate-calibration LABEL_FILE.json # gate offline clasificare culori
atm run [--duration H] [--start-at HH:MM] [--stop-at HH:MM] [--startup-delay SEC] [--capture-stub]
[--tz TZNAME] [--weekdays MON,TUE,...] [--oh-start HH:MM] [--oh-stop HH:MM]
atm journal [--file PATH] # înregistrare interactivă
atm report [--week YYYY-WW] [--file PATH] # raport săptămânal
Exit codes:
atm dryrun— 0 pass, 1 fail.atm validate-calibration— 0 toate PASS, 1 orice FAIL, 2 input invalid.- Restul: standard.
Evenimente audit
Scrise în logs/YYYY-MM-DD.jsonl. Cele adăugate recent:
| Event | Payload | Când |
|---|---|---|
canary_drift_paused |
distance |
Primul tick cu drift după o stare curată; emite alertă Telegram |
user_paused |
— | /pause primit |
user_resumed |
was_drift, was_user, force |
/resume sau /resume force |
market_open / market_closed |
reason |
Boundary fereastră operating-hours (o dată per tranziție; nu la startup) |
phase_skip_fire |
direction |
Alertă backstop când ARMED→light_* direct |
command_error |
action, error |
Excepție la dispatch (izolată de loop-ul de detecție) |