150 lines
9.3 KiB
Markdown
150 lines
9.3 KiB
Markdown
# 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.
|