# Design: ATM — Automated Trading Monitor (M2D Strategy) Generated by /office-hours on 2026-04-15 Branch: master Repo: /workspace/atm (greenfield) Status: APPROVED Mode: Builder (personal live-trading tool, high-stakes) ## Problem Statement User trades the M2D strategy on DIA (TradeStation chart with custom indicator) with execution on TradeLocker US30 CFD (prop firm account). Same strategy also applies to GLD → XAUUSD. Bridging signal source (TradeStation Windows app) with execution (TradeLocker web) currently requires user to watch both screens for 4 hours per evening. Goal: bot detects the trigger signal automatically and notifies user via Telegram/Discord with chart screenshot + SL/TP levels so user can execute the trade in TradeLocker. ## Strategy M2D — Full Spec **Setup:** TradeStation, 3-minute chart, DIA (or GLD) symbol, custom indicator "M2D MAPS" that renders a horizontal strip of colored dots below the price panel. Dots are indexed by time, y-position is fixed. ### BUY sequence (sequential in time, rightmost N dots): 1. **Turquoise dot** — 15-minute buy trigger 2. **Dark green dot** — 3-minute sell 3. **Light green dot** — 3-minute buy → **TRIGGER** At trigger: - Execute BUY on TradeLocker, instrument US30 CFD - Stop Loss 0.6% - Volume 0.1 lots maximum - TP1, TP2, SL are drawn automatically as horizontal lines on the TradeStation chart after entry - User manual lifecycle: at TP1 close half, move SL to ~breakeven; at TP2 close remaining half ### SELL sequence (mirror): 1. **Yellow dot** — 15-minute sell (red 15min candle) 2. **Dark red dot** — 3-minute buy 3. **Light red dot** — 3-minute sell → **TRIGGER** Same size (0.1 lots), same SL %, same TP management. ### Instrument mapping (intentional asymmetry): - DIA chart (TradeStation) ↔ US30 CFD (TradeLocker) - GLD chart (TradeStation) ↔ XAUUSD CFD (TradeLocker) ### Trading window: - NY open first 2 hours + NY close last 2 hours - RO summer time: 16:30-18:30 and 21:00-23:00 - Typical frequency: 1 trade per evening ## Constraints - **Prop firm account on TradeLocker.** Faza 2 (auto-execution) requires reading prop TOS first — many prop firms prohibit automation or detect robotic timing patterns. - No API on TradeLocker. No signal export on TradeStation for compiled custom indicator. - Bot runs on the same Windows machine as TradeStation. Cross-machine (RDP/VNC) screenshot adds latency and fragility. ## Premises (agreed) 1. Screenshot + visual detection is the only viable bridge. 2. Notification-first (Faza 1) is the right sequencing. Zero-click MVP removes all financial bug risk. 3. M2D MAPS dot strip has stable y-position on fixed TradeStation layout → ROI color sampling is the right detection method. 4. DIA→US30 price divergence is acceptable risk (user's judgment, has been trading this pairing live). 5. Bot runs on the same Windows machine as TradeStation. ## Recommended Approach — B: Structured Service with Dry-Run and Audit Log Python package on Windows, structured for clean extension to Faza 2. ### Components: - **Detector core:** `mss` screenshot of TradeStation window (located by title via `pygetwindow`) → crop M2D MAPS ROI → scan rightmost N dot positions → classify each by closest-color match with tolerance → feed into state machine that tracks 3-dot sequences (turquoise→dark-green→light-green = BUY trigger; yellow→dark-red→light-red = SELL trigger). - **Level extractor:** after trigger, scan chart region for horizontal colored lines (SL/TP1/TP2). Convert pixel y to price via calibration of y-axis scale. - **Calibration tool (Tkinter):** interactive — user clicks on each dot color sample, captures RGB + tolerance, clicks on ROI corners, captures y-axis price references. Writes to `config.toml`. - **Dry-run mode:** runs detector against a folder of saved screenshots (recorded during normal operation). Shows what notification WOULD have been sent for each. Used to validate new color thresholds or strategy tweaks without live risk. - **Notifier abstraction:** interface with Discord webhook and Telegram bot implementations. Sends: annotated screenshot + decoded SL/TP1/TP2 prices + signal type (BUY/SELL) + timestamp. - **Audit log (JSONL):** every detection cycle — timestamp, detected dots, classification, decision, notification sent y/n. Replayable, debuggable. - **Scheduler:** Windows Task Scheduler entry, auto-start/stop at 16:30 / 18:30 / 21:00 / 23:00 local time (summer/winter offset aware). ### Structure: ``` atm/ ├── pyproject.toml ├── config.toml # populated by calibration tool ├── src/atm/ │ ├── detector.py # screenshot + color classification + state machine │ ├── levels.py # SL/TP1/TP2 pixel-to-price extraction │ ├── notifier/ │ │ ├── __init__.py # abstract Notifier │ │ ├── discord.py │ │ └── telegram.py │ ├── audit.py # JSONL logger │ ├── calibrate.py # Tkinter UI │ ├── dryrun.py # replay on saved screenshots │ └── main.py # orchestration + scheduler hooks ├── samples/ # saved screenshots for dry-run corpus └── logs/ # JSONL audit ``` ### Detection algorithm (core loop): 1. Every 1 second during trading window: - Locate TradeStation window - If not foreground or minimized, log + skip - Screenshot M2D MAPS ROI (fixed offsets from window bounds) - For rightmost N=5 dot positions, sample center pixel, classify to nearest labeled color within tolerance - Update rolling window of last 10 dots with their timestamps - Evaluate state machine: did the last 3 classified dots (within a bounded time window) complete a BUY or SELL sequence? - If trigger fired AND not already fired for this bar: extract SL/TP1/TP2 levels, send notification, log, mark fired. ### Anti-duplicate logic: - Each trigger dot is keyed by (x-pixel position at capture, color). Once fired, stored in "recently fired" set with 10-minute TTL. Prevents re-fire if same dot persists across cycles. ### Sanity guards: - If classification confidence (color distance) low for 3+ cycles in a row → push "bot lost sight" alert to user. Layout may have changed. - If TradeStation window not found for 60 seconds → push "bot cannot find chart" alert. ## Open Questions (non-blocking) - Exact color tolerance values — determined during calibration session, not a design question. - GLD/XAUUSD: same M2D indicator on GLD chart? Assume yes, confirm during calibration. - Multi-symbol monitoring — single window switched manually, or two TradeStation windows side by side? Defer; v1 = single chart at a time, user switches manually. ## Success Criteria (Faza 1) - Over 20 live trading sessions, bot detects ≥95% of signals user also spotted manually. - Zero false-positive notifications during the bot's first 5 sessions (tune tolerances aggressively). - Notification delivered within 3 seconds of trigger dot appearing. - Audit log lets user reproduce "why was no notification sent" for any missed signal. ## Distribution Plan Personal tool, single user. No distribution channel needed — runs locally on user's Windows box. Git repo at `/workspace/atm`. `pyproject.toml` + `pip install -e .` for local dev. No CI/CD; user's own `scheduled task` starts/stops it. ## Risk Flag — Faza 2 (deferred) Before extending to auto-execution in TradeLocker: 1. Read prop firm TOS (search for "EA", "automation", "bot", "copy trading", "external signal"). If prohibited, **Faza 2 is off the table** — tool stays notification-only. 2. If permitted, implement via Playwright browser automation against TradeLocker web UI. 3. Add human-like click timing randomization (100-400ms jitter) to avoid robotic detection. 4. Dry-run mode then becomes: "click coordinates resolved, action NOT sent" — user reviews the intended click before enabling live. ## Next Steps (concrete) 1. Init `/workspace/atm` as Python project. `pyproject.toml`, basic structure. 2. Build calibration tool first. Without calibrated config, nothing works. 3. Record 20-30 sample screenshots across several trading sessions (can start this today — doesn't need any code yet; just `mss` screenshot on a 5-second timer dumping to disk). 4. Build detector + state machine. Validate against recorded screenshots in dry-run mode. 5. Wire Discord webhook first (simpler than Telegram bot). Test end-to-end on live session. 6. Add audit log. 7. Schedule Windows task for trading hours. ## What I noticed about how you think - You explicitly asked for dry-run before writing a line of code. "Să verific dacă vrea să apese corect, fără să apese efectiv." That's not a common instinct for someone building their own tool; it's the instinct of someone who has already had something break expensively. - You phased the project yourself — "faza 2 după ce mă conving că merge." That's the right ordering and you arrived at it unprompted. - When I challenged the API premise, you answered with specifics: the indicator is custom, the account doesn't support API. You knew the constraint, not guessed it. - You flagged the prop account almost casually at the end. A lot of builders would have skipped that detail. It turned out to be the most important constraint in the entire design.