docs: reflect Telegram /pause/resume, operating hours, phase-skip backstop, validate-calibration
README gets: operating-hours config + CLI override flags, Telegram command table with /pause /resume [force] semantics, validate-calibration usage + exit codes, new audit event reference, phase-skip backstop note, and test count bump. CLAUDE.md quick reference now lists the new subcommand, CLI flags, and Telegram commands so future sessions pick them up without re-reading main.py. TODOS.md marks the 2026-04-17 hang fix, canary drift notification, phase-skip backstop, operating-hours window, and validate-calibration as done with commit pointers; adds exchange-calendar holidays as known gap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
23
CLAUDE.md
23
CLAUDE.md
@@ -6,14 +6,31 @@ Personal Faza-1 tool for the M2D strategy. Python 3.11+.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install -e ".[windows]" # Windows: live capture
|
pip install -e ".[windows]" # Windows: live capture
|
||||||
pip install -e . # Linux/macOS: dev/dryrun only
|
pip install -e ".[dev]" # Linux/macOS: dev + tests (WSL: create venv first)
|
||||||
atm calibrate # Tk wizard
|
atm calibrate # Tk wizard
|
||||||
atm debug --delay 5 # one-shot capture + detect
|
atm debug --delay 5 # one-shot capture + detect
|
||||||
atm run --start-at 16:30 --stop-at 23:00 # live session
|
atm validate-calibration samples/calibration_labels.json # offline color gate
|
||||||
|
atm run --start-at 16:30 --stop-at 23:00 # live session
|
||||||
|
atm run --tz America/New_York --oh-start 09:30 --oh-stop 16:00 # NYSE window override
|
||||||
atm dryrun samples # corpus gate
|
atm dryrun samples # corpus gate
|
||||||
pytest # run tests
|
pytest -q # 184 tests
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Telegram commands (live)
|
||||||
|
|
||||||
|
`/ss` `/status` `/pause` `/resume` `/resume force` `/3` (interval min) `/stop`
|
||||||
|
|
||||||
|
- `/resume` clears only user pause; Canary drift requires `/resume force`.
|
||||||
|
- Drift-pause now emits a single Telegram alert (was silent pre-refactor — root cause of the 2026-04-17 hang).
|
||||||
|
|
||||||
|
## Operating-hours config
|
||||||
|
|
||||||
|
`[options.operating_hours]` in TOML: `enabled`, `timezone` (NYSE local, e.g. `America/New_York`), `weekdays`, `start_hhmm`, `stop_hhmm`. Timezone validated at load; `_tz_cache` reused per tick. Boundary crossings log `market_open` / `market_closed` and notify once. Startup in-window is silent.
|
||||||
|
|
||||||
|
## Phase-skip backstop
|
||||||
|
|
||||||
|
`[options.alerts] fire_on_phase_skip = true` (default) — ARMED→light_* direct (dark_* missed) still emits a `⚠️ PHASE SKIP` alert using FSM lockout to suppress spam.
|
||||||
|
|
||||||
## Skill routing
|
## Skill routing
|
||||||
|
|
||||||
When the user's request matches an available skill, ALWAYS invoke it using the Skill
|
When the user's request matches an available skill, ALWAYS invoke it using the Skill
|
||||||
|
|||||||
85
README.md
85
README.md
@@ -32,7 +32,7 @@ atm/
|
|||||||
│ ├── journal.py # trade entries
|
│ ├── journal.py # trade entries
|
||||||
│ ├── report.py # weekly R-multiple PnL
|
│ ├── report.py # weekly R-multiple PnL
|
||||||
│ └── main.py # unified CLI
|
│ └── main.py # unified CLI
|
||||||
├── tests/ # 105 pytest cases
|
├── tests/ # 184 pytest cases
|
||||||
└── TODOS.md # P1/P2/P3 backlog, Faza 2 items
|
└── TODOS.md # P1/P2/P3 backlog, Faza 2 items
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -135,13 +135,74 @@ Startup sequence:
|
|||||||
7. At `--stop-at` (or `--duration`): **"ATM stopped" ping**, then exit.
|
7. At `--stop-at` (or `--duration`): **"ATM stopped" ping**, then exit.
|
||||||
|
|
||||||
Per-cycle behaviour:
|
Per-cycle behaviour:
|
||||||
- Canary drift → auto-pause (logs `paused`, skips detection). Clear by running `atm run` again with the pause-file removed.
|
- Canary drift → auto-pause + **single-shot Telegram alert** (`⚠️ Canary drift=N — monitorizare pauzată`). Clear via `/resume force` in Telegram, or restart with pause-file removed.
|
||||||
- Detector reports UNKNOWN → stays in current state (logged as `noise`).
|
- Detector reports UNKNOWN → stays in current state (logged as `noise`).
|
||||||
- Colour change → full frame saved to `samples/YYYYMMDD_HHMMSS_<color>.png` (for corpus).
|
- Colour change → full frame saved to `samples/YYYYMMDD_HHMMSS_<color>.png` (for corpus).
|
||||||
- FIRE (BUY/SELL, not locked) → annotated PNG saved to `logs/fires/`, attached to the alert, `LevelsExtractor` armed.
|
- FIRE (BUY/SELL, not locked) → annotated PNG saved to `logs/fires/`, attached to the alert, `LevelsExtractor` armed.
|
||||||
|
- **Phase skip backstop** (`fire_on_phase_skip=true` default) → ARMED → light_red/light_green direct (dark_red/dark_green missed) still emits `⚠️ PHASE SKIP` alert with screenshot. FSM lockout suppresses spam.
|
||||||
- Phase-B complete → "Levels SL=… TP1=… TP2=…" push.
|
- Phase-B complete → "Levels SL=… TP1=… TP2=…" push.
|
||||||
- Heartbeat every `heartbeat_min` minutes.
|
- Heartbeat every `heartbeat_min` minutes.
|
||||||
|
|
||||||
|
### Operating hours window
|
||||||
|
|
||||||
|
Configure via `[options.operating_hours]` in TOML (source of truth: NYSE local time, timezone-aware so DST is handled automatically):
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[options.operating_hours]
|
||||||
|
enabled = true
|
||||||
|
timezone = "America/New_York" # fail-fast validated at config load
|
||||||
|
weekdays = ["MON", "TUE", "WED", "THU", "FRI"]
|
||||||
|
start_hhmm = "09:30" # NYSE open
|
||||||
|
stop_hhmm = "16:00" # NYSE close
|
||||||
|
```
|
||||||
|
|
||||||
|
Out-of-window ticks are skipped (logged only on transition). On boundary crossings the bot emits `market_open` / `market_closed` Telegram status messages exactly once per transition. **Startup in-window does not emit a spurious `market_open` alert.**
|
||||||
|
|
||||||
|
CLI overrides (beat TOML):
|
||||||
|
|
||||||
|
```
|
||||||
|
atm run --tz America/New_York --weekdays MON,TUE,WED,THU,FRI --oh-start 09:30 --oh-stop 16:00
|
||||||
|
```
|
||||||
|
|
||||||
|
> `--oh-start / --oh-stop` are **different** from `--start-at / --stop-at`. The `--start-at / --stop-at` pair controls wall-clock session bounds (when the process starts and quits); `--oh-*` controls the NYSE trading window inside the session (what hours detection actually runs). They compose.
|
||||||
|
|
||||||
|
### Telegram commands
|
||||||
|
|
||||||
|
Send to the bot chat:
|
||||||
|
|
||||||
|
| Command | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `/ss` or `/screenshot` | Take and send a screenshot now |
|
||||||
|
| `/status` | State + pause reason + window open/closed |
|
||||||
|
| `/pause` | Suspend detection (heartbeats continue) |
|
||||||
|
| `/resume` | Clear user pause only. If Canary is drift-paused it **stays paused** — use `/resume force` |
|
||||||
|
| `/resume force` | Also clear Canary drift-pause (use after recalibration) |
|
||||||
|
| `/3` or `/interval 3` | Set auto-screenshot interval to 3 min |
|
||||||
|
| `/stop` | Stop the scheduler |
|
||||||
|
|
||||||
|
Only `allowed_chat_ids` are accepted. After 3 consecutive `401`s the poller enters degraded mode.
|
||||||
|
|
||||||
|
### Calibration validation (offline gate)
|
||||||
|
|
||||||
|
Validate that the current calibration classifies known-labeled frames correctly **without waiting for a live session**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
atm validate-calibration samples/calibration_labels.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Input JSON:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"path": "logs/fires/20260417_201500_arm_sell.png", "expected": "yellow", "note": "first arm"},
|
||||||
|
{"path": "logs/fires/20260417_205302_ss.png", "expected": "dark_red"},
|
||||||
|
{"path": "logs/fires/20260417_210441_ss.png", "expected": "light_red"}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Output: per-sample PASS/FAIL with detected color + top-3 candidates by RGB distance + suggestion pixels for misclassifications.
|
||||||
|
|
||||||
|
Exit code: `0` if 100% PASS, `1` on any FAIL, `2` on malformed/missing input. Suitable for CI or a pre-`atm run` sanity check.
|
||||||
|
|
||||||
Keep PowerShell minimized during the session so it doesn't cover TradeStation.
|
Keep PowerShell minimized during the session so it doesn't cover TradeStation.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -209,9 +270,27 @@ atm calibrate [--screenshot PATH] [--delay SEC] # Tk wizard
|
|||||||
atm debug [--delay SEC] # one-shot capture + detect
|
atm debug [--delay SEC] # one-shot capture + detect
|
||||||
atm label SAMPLES_DIR # Tk labeling
|
atm label SAMPLES_DIR # Tk labeling
|
||||||
atm dryrun SAMPLES_DIR # corpus gate
|
atm dryrun SAMPLES_DIR # corpus gate
|
||||||
|
atm validate-calibration LABEL_FILE.json # offline color-classification gate
|
||||||
atm run [--duration H] [--start-at HH:MM] [--stop-at HH:MM] [--startup-delay SEC] [--capture-stub]
|
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] # interactive trade entry
|
atm journal [--file PATH] # interactive trade entry
|
||||||
atm report [--week YYYY-WW] [--file PATH] # weekly summary
|
atm report [--week YYYY-WW] [--file PATH] # weekly summary
|
||||||
```
|
```
|
||||||
|
|
||||||
Exit code: `atm dryrun` exits 0 if gate passes, 1 otherwise. Other commands follow standard convention.
|
Exit codes:
|
||||||
|
- `atm dryrun` — 0 pass, 1 fail.
|
||||||
|
- `atm validate-calibration` — 0 all PASS, 1 any FAIL, 2 bad input.
|
||||||
|
- Others: standard convention.
|
||||||
|
|
||||||
|
## Audit log events
|
||||||
|
|
||||||
|
Events written to `logs/YYYY-MM-DD.jsonl`. Added by the lifecycle+canary work:
|
||||||
|
|
||||||
|
| Event | Payload | When |
|
||||||
|
|---|---|---|
|
||||||
|
| `canary_drift_paused` | `distance` | First drift tick after clean; emits Telegram alert |
|
||||||
|
| `user_paused` | — | `/pause` received |
|
||||||
|
| `user_resumed` | `was_drift`, `was_user`, `force` | `/resume` or `/resume force` |
|
||||||
|
| `market_open` / `market_closed` | `reason` | Operating-hours window boundary (once per transition; **not** at startup) |
|
||||||
|
| `phase_skip_fire` | `direction` | Backstop alert when ARMED→light_* direct |
|
||||||
|
| `command_error` | `action`, `error` | Dispatch exception (isolated from detection loop) |
|
||||||
|
|||||||
6
TODOS.md
6
TODOS.md
@@ -60,6 +60,12 @@ Price overlay (from Telegram commands feature) uses `y_axis` linear interpolatio
|
|||||||
## Quality debt
|
## Quality debt
|
||||||
|
|
||||||
- [x] **Integration test for run_live loop**: lifecycle async test added in `tests/test_main.py` (IDLE→ARMED→PRIMED auto-poll→FIRE auto-stop).
|
- [x] **Integration test for run_live loop**: lifecycle async test added in `tests/test_main.py` (IDLE→ARMED→PRIMED auto-poll→FIRE auto-stop).
|
||||||
|
- [x] **Detection-loop hang on canary pause** (2026-04-17 incident): `_drain_cmd_queue` now runs unconditionally; helpers extracted to module scope for testability (commit `c5024ce`).
|
||||||
|
- [x] **Silent canary drift-pause**: single-shot Telegram alert on `not_paused → paused` (commit `9cf49ca`).
|
||||||
|
- [x] **Phase-skip backstop**: `fire_on_phase_skip` (default on) emits alert when ARMED→light_* direct (commit `8b53b8d`).
|
||||||
|
- [x] **Operating hours window**: NYSE-timezone-aware gate with `/pause` `/resume` `/resume force` control (commits `54f5575`, `2386577`).
|
||||||
|
- [x] **Offline calibration gate**: `atm validate-calibration` replays labeled frames through detector (commit `8bae507`).
|
||||||
- [ ] **Coverage report**: run `pytest --cov=atm --cov-report=term-missing`, aim for ≥ 85% per module.
|
- [ ] **Coverage report**: run `pytest --cov=atm --cov-report=term-missing`, aim for ≥ 85% per module.
|
||||||
- [ ] **Typing strictness**: run `pyright src/` with strict mode, fix reported issues.
|
- [ ] **Typing strictness**: run `pyright src/` with strict mode, fix reported issues.
|
||||||
- [ ] **Perf baseline**: profile one detection cycle on a representative frame; ensure < 100ms so 5s loop has ample headroom.
|
- [ ] **Perf baseline**: profile one detection cycle on a representative frame; ensure < 100ms so 5s loop has ample headroom.
|
||||||
|
- [ ] **Exchange calendar holidays**: operating_hours doesn't know about NYSE closures (MLK, Thanksgiving, Good Friday). User `/pause`s manually for now.
|
||||||
|
|||||||
Reference in New Issue
Block a user