Claude Agent 4dac21b7c0 fix(vision): erode mask pre-CC to sever anti-aliasing bridges
With tol=25 all dots in the strip fused into one blob via 1px anti-aliased
bridges between adjacent dots → centroid landed mid-strip instead of on the
rightmost dot. Erosion (3x3 kernel, 2 iters) cleanly separates discrete
dots before connected-components labelling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 07:12:57 +00:00

ATM — Automated Trading Monitor

Personal tool for the M2D strategy on TradeStation DIA/GLD charts with US30/XAUUSD execution on TradeLocker. The bot watches the colored dot strip produced by the M2D MAPS custom indicator and sends a Telegram/Discord notification (with chart screenshot + SL/TP levels) when a BUY or SELL trigger fires — so you execute the trade manually in TradeLocker instead of watching two screens.

Current phase: Faza 1 — notification-only. No auto-execution until prop firm TOS has been audited (see docs/phase2-prop-firm-audit.md).


Project structure

atm/
├── pyproject.toml
├── configs/            # calibration configs (YYYY-MM-DD-HHMM.toml + current.txt)
├── logs/               # audit JSONL + dead-letter queue
├── samples/            # screenshots for dry-run validation
└── src/atm/
    ├── config.py       # Config dataclass + loader
    ├── detector.py     # screenshot → color → state machine
    ├── state_machine.py
    ├── vision.py       # color matching helpers
    ├── levels.py       # SL/TP pixel-to-price
    ├── calibrate.py    # Tkinter calibration wizard
    ├── labeler.py      # Tkinter sample labeler
    ├── journal.py      # trade journal (JSONL)
    ├── report.py       # weekly performance report
    ├── audit.py        # structured audit log
    ├── canary.py       # layout drift detection
    ├── dryrun.py       # replay saved screenshots
    ├── notifier/
    │   ├── discord.py
    │   └── telegram.py
    └── main.py         # unified CLI

Setup

Prerequisites

  • Python 3.11+
  • Windows 10/11 (required for live capture; dry-run works on any OS)
  • TradeStation running with a 3-minute DIA or GLD chart open

Install

# Clone (internal repo)
git clone git@gitea.romfast.ro:romfast/atm.git
cd atm

# Create venv and install
python -m venv .venv
.venv\Scripts\activate        # Windows
pip install -e .

# Windows-only extras (screen capture, window detection)
pip install -e ".[windows]"

Environment variables (notifiers)

Create a .env file or set these in your shell before running:

ATM_DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
ATM_TELEGRAM_TOKEN=123456789:AABBcc...
ATM_TELEGRAM_CHAT_ID=-100123456789

Calibration workflow

Calibration maps the TradeStation window layout to the config that drives detection. Redo calibration whenever you resize the chart window, change DPI, or switch monitors.

Step-by-step

  1. Open TradeStation with the 3-minute DIA chart. Maximise or snap to a fixed position. Do not resize it during the session.

  2. Run the calibration wizard:

    atm calibrate
    
  3. Pick window title — type the exact string that appears in the TradeStation title bar (e.g. DIA - 3 Min). The bot uses this to locate the window via pygetwindow.

  4. Mark the dot ROI — a screenshot of the current window is shown. Click the top-left corner and the bottom-right corner of the M2D MAPS dot strip to define the region of interest.

  5. Sample dot colours — for each of the 7 dot colours (turquoise, yellow, dark green, dark red, light green, light red, gray), click a representative dot in the screenshot. The wizard records the RGB value and sets an initial tolerance of 30.

  6. Set y-axis calibration points — click on two price levels that appear as visible horizontal gridlines on the chart, then type the corresponding price for each. This calibrates the pixel-y → price mapping for SL/TP extraction.

  7. Select canary region — drag a small rectangle over a stable, unchanging part of the chart border (title bar strip works well). This becomes the baseline for canary drift detection.

  8. Save — the wizard writes configs/YYYY-MM-DD-HHMM.toml and updates configs/current.txt. Future runs load this config automatically.

Verify calibration

atm dryrun --dir samples/

Review the dry-run output. Every sample should classify to the expected dot colour. If misclassifications appear, re-run the calibration wizard or adjust tolerances manually in the TOML file.


Per-session operating checklist

Before each trading window (NY open 16:30 RO, NY close 21:00 RO):

  • TradeStation open on 3-minute DIA chart, window not minimised
  • Chart window is in the same position/size as when calibrated
  • TradeLocker open in browser, instrument US30 loaded, position sizing ready
  • Telegram / Discord notification channel visible on mobile or second screen
  • Run atm canary-check — confirm no drift alert before starting the bot
  • Start the monitor: atm run
  • After the session: atm journal add to record trade outcome (or leave outcome=open to fill later)
  • At week end: atm report --week YYYY-WW to review win rate and PnL in R

DPI and multi-monitor notes

  • High-DPI displays: Windows DPI scaling can shift pixel coordinates. Set TradeStation to "System (Enhanced)" DPI compatibility mode (right-click EXE → Properties → Compatibility → Change high DPI settings) OR set Python to DPI-unaware via SetProcessDPIAware() in the manifest. The calibration wizard and capture code both call SetProcessDPIAware() on start.

  • Multiple monitors: mss captures the monitor that contains the target window. The ROI offsets in the config are relative to the window's own top-left, so moving the window between sessions (but not resizing) is usually safe. Moving to a different monitor with a different DPI requires recalibration.

  • Virtual desktops / remote desktop: Screen capture via mss does not work through RDP (the window reports on-screen but the pixel data is black). Run the bot locally on the same physical machine as TradeStation.


Troubleshooting

Window not found

WindowNotFoundError: No window matching 'DIA - 3 Min'

Causes and fixes:

  • TradeStation is minimised — restore it to a visible state.
  • The window title has changed — re-run atm calibrate and provide the exact current title string. Copy-paste from the title bar.
  • DPI scaling changed the reported title encoding — confirm the title in pygetwindow.getWindowsWithTitle("") output.

Canary drift alert

CanaryDriftAlert: phash distance 12 > threshold 8

The chart layout has shifted (e.g., chart scroll, zoom change, indicator redraw). Do not trade until this is resolved.

  1. Check TradeStation — scroll or zoom may have shifted the DOT ROI out of frame.
  2. Reset the chart to the calibrated state (same zoom/scroll as during calibration).
  3. If the layout change was intentional, re-run calibration.
  4. To suppress a single false alarm without recalibrating, run atm canary-reset which re-samples the canary region baseline from the current screenshot.

Low confidence warnings

LowConfidence: cycle 5 — best match 'gray' dist=0.27 (threshold 0.20)

The sampled pixel is near the edge of a colour tolerance zone. Usually caused by:

  • Screenshot timing during a dot colour transition (rare on 3-min chart).
  • Chart re-render artifact (scaling seam at ROI boundary).

If this persists for more than 3 consecutive cycles, an alert is sent automatically. Verify the dot strip is fully visible and not clipped by another window.

Notification not received

  1. Check logs/audit.jsonl for the last cycle — look for "notification_sent": false and the reason field.
  2. Verify webhook/token: atm test-notify.
  3. Check network connectivity from the Windows machine to Discord/Telegram endpoints.
Description
No description provided
Readme 10 MiB
Languages
Python 99.9%