StopWarden is not open yet. Nothing here can be downloaded or bought today; these pages describe how StopWarden is planned to work when it opens. Get one email when it opens.
Configuration reference
StopWarden reads one file: C:\ProgramData\StopWarden\autopilot.json (to use another path, set the environment variable AUTOPILOT_CONFIG). The installer copies config\autopilot.example.json there the first time and never overwrites it afterwards. After every edit, run autopilot doctor. It explains every mistake at once, in plain English.
Secrets are never in this file. Store them with:
autopilot store-secret nt8 # your NinjaTrader username + password
autopilot store-secret telegram # chat id + bot token
autopilot store-secret discord # webhook URL
They go into Windows Credential Manager (targets StopWarden/NinjaTrader, /Telegram, /Discord) and never leave your PC.
Times are HH:MM, 24-hour, on this PC's clock. Set Windows to your exchange's timezone (Settings → Time & language), or convert the times yourself.
nt8: how to reach NinjaTrader
| Key | Default | Meaning |
|---|---|---|
exe | C:\Program Files\NinjaTrader 8\bin\NinjaTrader.exe | Path to NinjaTrader 8. |
user_dir | "" = auto | Your NinjaTrader 8 data folder. Blank means <your Documents folder>\NinjaTrader 8, found through Windows so a Documents folder redirected to cloud storage still works. Set it only if doctor says it can't find it. |
login.method | "credential" | credential: types your stored NinjaTrader username/password into the login window. google: clicks your saved Google account (home PCs only; Google often blocks sign-ins from data-center/VPS IPs). none: you sign in yourself. |
login.google_account | "" | Required for google: text shown on the Google account tile, e.g. your email. |
connections | (required) | Connection names exactly as in NinjaTrader's Connections menu, e.g. ["My NinjaTrader"]. Tradovate-based prop accounts usually appear under My NinjaTrader. |
reject_feed_types | ["Simulated","Playback"] | Connections of these types are refused (so a replay or sim feed never drives a live account). |
targets: what to run (v1: exactly one)
"targets": [ { "strategy": "MyStrategy", "account": "Sim101", "instrument": "" } ]
| Key | Meaning |
|---|---|
strategy | The strategy name as shown in the Control Center → Strategies tab (the part before any /). |
account | The account column value on that row, exactly (e.g. Sim101, or your prop account id). |
instrument | Optional. The contract used for an emergency flatten if NT8 hasn't logged a position line yet, e.g. "NQ DEC26". Blank = take it from NinjaTrader's own position line (recommended). |
Before first use: add the strategy to the Strategies tab yourself, on the right account and instrument, with the parameters you want, then save your workspace. StopWarden enables and disables that row; it never creates or edits strategies.
schedule: when
| Key | Default | Meaning |
|---|---|---|
days | Mon–Fri | Trading days (Mon Tue Wed Thu Fri Sat Sun). |
launch_at | 08:30 | Start NinjaTrader, sign in, connect. |
enable_at | 08:45 | Enable the strategy (only if flat). |
disable_at | 16:05 | Disable the strategy, then end-of-day cleanup. Must be after enable_at, same day. |
flatten_on_disable | true | At disable_at: cancel working orders and flatten, then confirm flat from NT8's log. |
holidays | [] | Dates to skip entirely, "YYYY-MM-DD". |
Overnight/24h schedules aren't supported in v1. StopWarden enables within one day window.
watchdog: naked-position backstop
| Key | Default | Meaning |
|---|---|---|
enabled | true | Run the watchdog. |
naked_seconds | the fixed wait | How long a position may exceed its stop coverage before the watchdog acts. The wait is fixed: a higher value in an older file is read as the fixed wait, with one warning in the log, and StopWarden still starts. A lower value, or one that is not a number, is refused. In Watch, and in Protect until a Learn report is accepted, it only alerts. Protect turns on only for a strategy whose stop is normally working well inside the wait (the Learn report checks this), so your strategy gets the first chance to replace a stop. The Learn report also adds up, for each minute, how long the position had no working stop, and refuses a strategy whose total is too long in any one minute. |
poll_seconds | 1 | How often the NT8 log is checked, from 0.5 to 1 second. Any other value is refused: StopWarden must check at least once a second to act close to the end of the wait. |
flatten | true | false = alert only, never flatten, even in Protect. |
extra_stop_name_prefixes | [] | Only if your strategy protects positions with orders that are not Stop Market/Stop Limit (for example a protective order your strategy logs under another order type): list their name prefixes (a list of text values, each at least 2 characters, for example ["SL_"]) and they'll count as protection. A Limit or Market-if-touched order is judged against your average entry price, not the market: on the profit side of it, or when the entry price is not known, it is a target and never counts, whatever its name; on the loss side of it, it counts. A Market order never counts through a name. |
How coverage is judged: per instrument, a position is covered when stop orders on the closing side (Sell for a long, Buy/Buy-to-cover for a short), on the same contract, add up to at least the position size. Profit targets never count, and neither does a stop that has partially filled (it has already gone to market). Which order states count is set by the protection section below.
The watchdog acts only with a running supervisor. It closes a position only when the supervisor has written a fresh Protect permission (state\tier.json, rewritten every ~15 s and trusted for at most 15 minutes), the supervisor is still running, and no kill switch (STOP) is set. A watchdog started on its own (autopilot watchdog, without the supervisor) is alert-only by design.
recovery: self-healing
| Key | Default | Meaning |
|---|---|---|
enabled | true | Relaunch / reconnect / re-enable when things break during the trading window. |
max_attempts_per_day | 6 | Hard cap per day. When it's hit: alert, stop trying, leave the strategy off. |
max_consecutive | 3 | Consecutive failures before switching to slow retry. |
backoff_minutes | 30 | Slow-retry interval. |
heartbeat_stale_minutes | 8 | Only used if your strategy writes the optional heartbeat file (see FAQ): no heartbeat for this long in the trading window → reconnect. |
ui_timeout_seconds | 240 | Longest any single NinjaTrader UI action may run before it's killed. |
alerts
| Key | Default | Meaning |
|---|---|---|
telegram | false | Send alerts to Telegram (store the secret first). |
discord | false | Send alerts to a Discord webhook. |
heartbeat_hours | 0 | Send an "I'm alive" message every N hours (0 = off). |
balance_floor: optional account guard
| Key | Default | Meaning |
|---|---|---|
enabled | false | Read the account balance from NinjaTrader's Accounts grid every 5 minutes. |
floor | 0 | If the balance is below this: alert, disable, flatten, and set the kill switch. For prop accounts, set it a little above your firm's liquidation level. |
accounts_tab | "Accounts" | Name of the Control Center tab that shows your accounts grid (if you renamed it). |
paths
| Key | Default | Meaning |
|---|---|---|
state_dir | "" = C:\ProgramData\StopWarden\state | Logs, state, and the kill switch file STOP. |
mode, telegram, license (schema 2)
| Key | Default | Meaning |
|---|---|---|
mode | "watch" | watch (the default for every install): detect and alert only, never act on the account. protect (opt-in): also launch, enable, re-enable, flatten and cancel as described in Safety. Protect needs all of: a paid licence, an accepted Learn report for the configured strategy and account (see protection below), and an algo account. The engine refuses to save mode: "protect" without an accepted report. A file edited by hand to protect without one stays alert-only: the supervisor and the watchdog both check the same gate. |
cancel_scope | "account" | How end of day, the kill switch, the balance floor and the enable-undo cancel orders. account: CLOSEPOSITION for the configured account's position (NinjaTrader cancels that instrument's working orders on that account with it) plus one ATI CANCEL per remaining working order on the configured account -- other accounts in the same NinjaTrader are never touched. global: additionally NinjaTrader's CANCELALLORDERS, which cancels working orders on every account; it is refused (with a WARN, falling back to account) whenever working orders have been seen on a non-configured account this session, and never sent in Watch mode. |
telegram.bot_username | "" | Your own bot's username, filled in by autopilot link-telegram. The bot token itself stays in Credential Manager. |
license.grace_days | 7 | Days a last-known-valid licence keeps working when the licence server can't be reached (0–30). |
A schema_version: 1 file is upgraded in memory on load (the three keys above get their defaults); nothing is lost.
protection: how cover is judged, and the Learn gate
| Key | Default | Meaning |
|---|---|---|
transition_max_s | built-in | A stop being moved (ChangePending / ChangeSubmitted) still counts as cover for this long, counted from the first change since the stop was last Working. |
arriving_max_s | built-in | A stop just sent (Submitted / Initialized) counts as cover for this long, counted from when it was sent, however many states it passes through. If it is then rejected, the credit is taken back: the naked time counts as if that stop had never been there. |
exit_settle_s | built-in | A closing Market order for the whole position counts as cover for this long from when it was sent: your strategy is exiting. A closing limit order is a resting target and never counts. |
naked_budget_s | 0 | Uncovered seconds within any rolling 60 s that also count as "too long", for a stop that keeps disappearing and coming back: 0 = the same as watchdog.naked_seconds. A value lower than the wait is refused, because StopWarden could then close trades your strategy was about to protect. |
far_factor | 3.0 | A stop farther than far_factor × the max loss from your average entry still counts as cover, but you get a warning with the dollars at risk (1–20). |
max_loss_usd_per_contract | {} | Per instrument root, in dollars per contract, e.g. {"NQ": 800}. Built-in, in points: NQ 40, MNQ 40, ES 10, MES 10, YM 100, MYM 100, CL 0.50, GC 5. An instrument with neither gets no far-stop warning. |
reject_storm.count / reject_storm.minutes | 20 / 5 | A CRITICAL alert when this many orders are rejected on the account within this many minutes. |
account_mode | "algo" | "manual-allowed": you also trade this account by hand, so StopWarden never flattens or cancels on it by itself and the order guard stays off; alerts only. |
learn.min_trades / learn.min_sessions | 20 / 5 | When the Learn report counts as complete (round trips / trading sessions seen in NinjaTrader's log). |
learn.accepted | null | Written by autopilot learn --accept. Protect cannot act until it exists for the configured strategy and account. |
Other states count as follows: a stop that NinjaTrader simulates on your PC (TriggerPending) counts only while the configured connection is up, and you are warned about it; a stop being cancelled counts only while an exit for the whole position is working.
Watch to Protect, step by step:
- Run in Watch (the default) while your strategy trades, until
autopilot learnsays the report is complete (20 round trips over 5 sessions by default). It reads NinjaTrader's log and changes nothing. - Read the report: how long your strategy's stop normally takes to be in place, how it moves it, and how many times Protect would have acted with its wait.
autopilot learn --accept. It refuses an incomplete report, and a strategy the report classifies as STOPLESS (exits without a resting stop), UNSTABLE (its slowest 1% of stop placements take longer than the wait), ATM, SLOW (strategies whose own stop is not reliably working well inside the wait, or is missing for too long in total within a minute) or two instruments held at once on one account: those stay Watch-only in this version.- Activate a paid licence, then set
modetoprotect(the StopWarden window's Use Protect, or this file). Until all of this is in place, Protect alerts after the wait with no working stop and never flattens.