StopWarden

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

KeyDefaultMeaning
exeC:\Program Files\NinjaTrader 8\bin\NinjaTrader.exePath to NinjaTrader 8.
user_dir"" = autoYour 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": "" } ]
KeyMeaning
strategyThe strategy name as shown in the Control Center → Strategies tab (the part before any /).
accountThe account column value on that row, exactly (e.g. Sim101, or your prop account id).
instrumentOptional. 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

KeyDefaultMeaning
daysMon–FriTrading days (Mon Tue Wed Thu Fri Sat Sun).
launch_at08:30Start NinjaTrader, sign in, connect.
enable_at08:45Enable the strategy (only if flat).
disable_at16:05Disable the strategy, then end-of-day cleanup. Must be after enable_at, same day.
flatten_on_disabletrueAt 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

KeyDefaultMeaning
enabledtrueRun the watchdog.
naked_secondsthe fixed waitHow 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_seconds1How 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.
flattentruefalse = 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

KeyDefaultMeaning
enabledtrueRelaunch / reconnect / re-enable when things break during the trading window.
max_attempts_per_day6Hard cap per day. When it's hit: alert, stop trying, leave the strategy off.
max_consecutive3Consecutive failures before switching to slow retry.
backoff_minutes30Slow-retry interval.
heartbeat_stale_minutes8Only used if your strategy writes the optional heartbeat file (see FAQ): no heartbeat for this long in the trading window → reconnect.
ui_timeout_seconds240Longest any single NinjaTrader UI action may run before it's killed.

alerts

KeyDefaultMeaning
telegramfalseSend alerts to Telegram (store the secret first).
discordfalseSend alerts to a Discord webhook.
heartbeat_hours0Send an "I'm alive" message every N hours (0 = off).

balance_floor: optional account guard

KeyDefaultMeaning
enabledfalseRead the account balance from NinjaTrader's Accounts grid every 5 minutes.
floor0If 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

KeyDefaultMeaning
state_dir"" = C:\ProgramData\StopWarden\stateLogs, state, and the kill switch file STOP.

mode, telegram, license (schema 2)

KeyDefaultMeaning
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_days7Days 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

KeyDefaultMeaning
transition_max_sbuilt-inA 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_sbuilt-inA 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_sbuilt-inA 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_s0Uncovered 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_factor3.0A 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.minutes20 / 5A 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_sessions20 / 5When the Learn report counts as complete (round trips / trading sessions seen in NinjaTrader's log).
learn.acceptednullWritten 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:

  1. Run in Watch (the default) while your strategy trades, until autopilot learn says the report is complete (20 round trips over 5 sessions by default). It reads NinjaTrader's log and changes nothing.
  2. 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.
  3. 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.
  4. Activate a paid licence, then set mode to protect (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.