DocumentationOperate

Protection and risk reduction

Updated: 2026-10-12 22:05 CEST

Proposals are advisory by default. The standard binary cannot place an order. In a trading build, manual submission requires the exact proposal and its fresh preview; optional pre-authorised buckets let the daemon schedule close/reduce actions under an owner-edited policy. Installing Canary does not enable that automation. The cash sweep and currency leveling are cash management, not protection: they have their own section of the policy and their own authority (Cash management).

A blocked proposal row is normally the system refusing to act on evidence it cannot trust, not a fault to work around. Canary exposes only constrained close/reduce actions here; use TWS for an unmodeled emergency exit.

What each command does

Command Reaches the broker Use it for
canary proposals list no the current proposal set, blockers included
canary proposals refresh no rebuild the set against fresh positions and quotes
canary proposals preview KEY REVISION no mint a preview token and read the broker WhatIf verdict
canary proposals submit KEY REVISION yes place that one protective order
canary proposals reduce SYMBOL --percent N only with --submit a discretionary partial close; the preview returns a token with the exact terms, --submit --preview-token places them
canary proposals veto KEY no hold the current automatic proposal revision before submission
canary proposals request-stop SYMBOL no stage a trailing-stop proposal for one uncovered stock/ETF holding now

canary proposals with no subcommand runs list. In a standard build the submit path fails closed anyway: the daemon's write handler is compiled out behind the trading build tag and returns ErrTradingDisabled. See Constrained orders and the trading build.

Proposals close or reduce only

The daemon owns generation. It rebuilds the set from current positions, the protection policy, and market-event context, and every protection row it emits closes or reduces, without exception. The cash sweep's bill buys and currency leveling's conversions are not protection rows: the [cash] section admits them by their own typed bounds (Cash management). The submit path checks a protection row twice, once against the proposal's own position effect and once against the preview's, and blocks on either. A protection proposal cannot open, increase, or flip exposure. authority.auto_submit must be false; the policy file fails validation otherwise.

Six buckets generate protection rows, enabled through the protection policy:

The option-exit policy uses the explicitly approved absolute 0.05 quote-currency TRAIL LIMIT offset. An inherited or omitted offset still fails activation. Standing defaults apply only to standard ungrouped long contracts. default_long_calls_directional classifies long calls and non-hedge-listed long puts as directional unless they cover a holding: a call over a short stock of its own underlying, a put over a long stock of its own underlying, or an index option over such a stock anywhere in the book, which makes the option protection. default_index_puts_protection excludes hedge-listed puts from directional exits. Exact declarations, including expired declarations, take precedence. A contract no standing default covers, such as a short option, a non-standard multiplier or a strategy leg, stays an owner review; Canary requests no quote for it and reports no quote blocker. Without a qualifying standing default or exact intent, an exit stays blocked.

Budget reduction

The bucket measures the market value of every long option leg Canary does not hold as protection — a hedge-listed index put (SPY, SPX, SPXW, QQQ, IWM), a put over a long stock of its own underlying, or a call over a short one is never counted and never selected — against two caps you write as a percent of capital.declared_risk_capital from risk-policy.toml:

[buckets.budget_reduction]
enabled = true
mode = "shadow"                            # shadow (default) or active
premium_at_risk_pct_of_risk_capital = 40   # total, (0, 100]
per_line_pct_of_risk_capital = 15          # one line, at most the total
max_order_notional = 10000                 # one order, as risk_reduction

Bump policy_version when you add it. Neither cap has a default in code: a value you did not write is a value the bucket does not have. An enabled table missing a cap or max_order_notional stays valid, and the governor switches itself off with the state needs_your_number, naming the keys it waits for; every other bucket keeps working. The numbers above are the 2026-09-21 mandate the product manager set for the desk owner to confirm by writing them; they are not a recommendation from the software.

It generates rows only when all of the following hold, and the snapshot's budget_reduction status names the first one that does not:

State Meaning
needs_your_number the table is enabled but a cap or max_order_notional is not written; the reason names the keys
constitution_unapproved no risk constitution is active, or a material key is unapproved
enforcement_shadow drawdown.block_enforcement is shadow; the bucket acts only under advisory or stronger
not_latched the drawdown block tier is neither latched nor breached
currency_mismatch the constitution's base currency is not the account's
unmeasurable no long option leg has a base market value
within_budget / over_budget measured; the status carries the total, the share of risk capital, and the leg counts

Selection runs per line first: a line above the per-line cap is cut to the cap in whole contracts (keep = floor(cap ÷ value per contract)), and a cap that leaves no whole contract is a full close. Then the total: while the projected sum still exceeds the total cap, lines are cut in whole contracts, ranked by what the sale fixes, until the sum is within the cap:

  1. the number of open Rulebook rules the line relieves: rows at watch or act among rules 1, 2, 4, 5, 13, 16 and 18 on which the line, or its issuer, is an offender, read from the Rulebook result Canary already holds;
  2. the share of the line's value that is time value, highest first (unknown last);
  3. the unrealised loss, largest first; then the line's value; then the contract id.

Without a current Rulebook result no line relieves anything, the ranking starts at time value, and the status says ranking_without_rulebook. Every row names the cap that selected it, the measured line and total, the excess, its place in the order and the order used, under budget in JSON and on a Budget: line in canary proposals list --details. max_order_notional bounds one order exactly as risk_reduction.max_order_notional does; the next cycle measures what is left. A stale mark blocks the row with fresh_option_quote_required; a leg of a multi-leg unit is measured but routes to the strategy workflow. Rows are close or reduce only, like every proposal.

The whole fix in one place. The budget_reduction status lists up to three candidates, the ranked lines with their contract, contracts held, unit value, the rules they relieve (relief), time_value_pct, unrealised P&L and a one-line why ("offends 2 open rules; 50% time value; unrealised −500"), and the plan: every order the measurement needs, each with its rank, contract, contracts, raises_base and cycle (1 for this refresh, 2 and later for what max_order_notional holds back). canary proposals list --details prints both under the Budget header, and every governor row there adds three detail lines: its place in the plan, the other open rules the sale relieves, and the next two candidates with their why. Ignoring a row takes its line out of the plan: the next refresh moves to the next candidate.

Index-put classification is shared with the Rulebook for both budget and mandate reduction plans. A measured directional put can enter the plan even when its symbol is on the hedge list; measured protection stays excluded. Missing classification holds the line and is reported separately from protection. Planning may use the same closed-session observations as the warning. Before preview or prepared submission admits a reduction, a fresh, complete broker measurement must still confirm that the put is directional; the existing scope-bound evidence expires with the order token. The policy limits, order caps, veto window and approval requirements are unchanged.

Measured against the Rulebook instead. basis = "rulebook" replaces the two caps with limits you already keep in the Rulebook policy, as shares of NLV: a line is cut to option_line_act_pct (its premium at risk being the higher of price paid and value), and when the book's premium at risk reaches the premium budget's act level of the regime set in force (Rulebook rule 3, premium_budget_act_pct), lines are sold in the same ranked order, each contract counted at its premium at risk, until the total is back at the budget's watch level (premium_budget_watch_pct). This basis needs the account's NLV, not a risk constitution or available funds, and it waits for no drawdown brake: the rows appear whenever those limits are breached. Leave out the two percentages; the file fails validation with both a basis of rulebook and declared-capital caps.

[buckets.budget_reduction]
enabled = true
mode = "shadow"
basis = "rulebook"
max_order_notional = 10000

The state is account_unavailable when NLV is missing; the status then carries per_line_pct_of_nlv, premium_budget_watch_pct, premium_budget_act_pct and premium_budget_set, the account values, premium_pct_of_nlv and, once the act level is reached, premium_excess_base (the premium at risk above the watch level), and each row names the limit that selected it.

This basis sells against the Rulebook's numbers, which may still be Canary's defaults. Your mode applies whatever state the Rulebook policy file is in: you approve every order, and that approval is the gate. The status names the state in rulebook_review, and while it is anything but reviewed every row carries one detail line saying so:

rulebook_review Detail line on every row
reviewed none: the file in force is yours, read cleanly
unreviewed "Rulebook limits: Canary's defaults, not yet reviewed" (the file still opens with # Canary defaults, not yet reviewed.)
no_file "Rulebook limits: no Rulebook policy file; compiled defaults" (canary policy ensure writes one)
drift "Rulebook limits: the file on disk is not the one in force" (edited without a higher policy_version, or removed)
error "Rulebook limits: the file could not be read; the last good file applies" (before any good file, Canary's compiled defaults apply)

canary proposals list names the state on the Budget header. The declared-risk-capital basis measures your own caps and reads no review state.

Shadow first. In mode = "shadow" the rows are generated, journaled in the snapshot with shadow: true, marked shadow in canary proposals list and listed by --details under a Shadow (budget reduction) heading of their own, so you can read what the rule would have done beside what you did. preview and submit refuse them with shadow_mode, and the pre-authorisation scheduler skips them: a row is eligible for automatic placement only when AutomaticEligible() holds, which a shadow row never does. counts.budget_reduction and counts.budget_reduction_shadow report the rows; shadow rows are never actionable.

Activating. Set mode = "active" and bump policy_version. The rows become ordinary proposals under every existing gate (preview, WhatIf, the double check of position effect, duplicate orders, account, mode, freeze, origin and the explicit submit). One thing does not change with the mode: every row carries never_skip_veto, so a scheduler that shortens or skips the veto window under a latched brake must still wait the full window for these. A reduction to budget is a discretionary-scale action, not a stop.

canary proposals reduce is separate: a discretionary partial close you size yourself. It previews unless you pass --submit. Under --portfolio the mode says what is cut. --mode net, the default, removes that share of the book's net delta-adjusted risk, only on lines in the net direction. --mode longs sells the same share of every long-delta line and keeps every short and long put. --mode all cuts that share of every line, buying back shorts. --sector (repeatable, GICS names) and --min-beta narrow a longs or all sweep. --plan sizes the legs without broker previews and reports what the book would lose if the index fell 10% now and after, from the mandate's index stress; a plan cannot be submitted.

A reduction reserves the quantities already committed by Canary's working orders, including individual legs of combo orders. A known fill does not make those units available for another sale while positions are catching up: Canary checks a completed broker position snapshot against the position used for the reduction and refuses while they disagree or cannot be confirmed. An order-state change before transmission also requires another review. These checks, and the reviewed worst price, apply when a reduction token is submitted through order place as well as through proposals reduce.

No portfolio sweep, in any mode, selects a locked holding. canary locks lock SYMBOL --con-id ID --role hedge|core puts a line on the keep list: a hedge is a hedge because you say so, not because of its delta sign that day. Net mode reads the direction of the unlocked book. The mandate's automatic reduction leaves locked lines out too. If the keep list cannot be read, automatic reductions wait; an unreadable list never means no locks. A lock save waits for any in-flight broker transaction before acknowledging the new list. It does not cancel orders already sent. A reviewed basket refuses, and sends nothing for, a leg locked after the review. A single-holding proposals reduce SYMBOL still works on a locked line. --include-hedges is a hard error under --portfolio instead of a silent no-op.

A net portfolio preview also discloses signed net dollar delta before and the estimated delta after eligible orders fill, using current prices and Greeks; blocked orders do not count toward that estimate. Its untouched_positions list names every nonzero holding left unchanged, with exact contract identity, held quantity and the reason: locked by you, opposite-direction delta, unsupported position, whole-unit rounding, or a blocked preview. An empty list means no untouched holdings; null means the review is unavailable, as for a scoped sweep, which lists what it keeps under kept. These fields only explain the existing sizing and never change which orders are selected.

A reduce preview returns, for each order it would place, a signed preview token and the exact terms that token binds (terms): the contract, side, quantity, order type, limit, time in force and algorithm the broker will receive, the token's expiry, and the worst price the submit will hold the market to. canary proposals reduce --submit --preview-token TOKEN places exactly those terms, nothing re-sized and nothing re-priced; under --portfolio pass one --preview-token per leg, and each leg is placed on its own, so a refused leg never holds another. The daemon refuses, and sends nothing, when the token is stale or expired, when the position no longer holds the reviewed quantity on the reviewed side (a sale of at most the confirmed long is admitted; a smaller position refuses as position_changed rather than shrinking the order), when the market is already beyond the reviewed worst price (beyond_worst_price: the bid below a sale's limit, or the ask above a purchase's; a market that moved the other way is no reason to refuse; stated in every preview as price_bound), when the token was already submitted (token_consumed), or when any order gate refuses, Canary's own stop on the line included (a reduce sale joins the stop's one-cancels-all group or waits for the stop to shrink, like any other sale). --request-ref REF names a submission: a retry with the same reference replays the recorded result and never sends twice.

Two reductions of one line never together sell more than is held (owner instruction 2026-10-22 17:45 CEST): a reduction sizes its percentage from what Canary's own working orders on the line leave unsold (stops aside, which their one-cancels-all group and the stop guard keep within the line) and states that quantity as committed_quantity; the send refuses (reduce_already_working) when another of Canary's sales went out in between. Hand orders in TWS do not count. A send that may have reached the broker is submit_unclear, never submit_failed. Under --portfolio, a stock the broker reports as having no market and values at zero counts as no exposure and is listed as left out (defunct_holding) instead of blocking the book.

A reduction is a limit priced as a worst price, DAY (owner decision 2026-10-22 15:26 CEST, which replaced the limit at the mid and its ±0.5%/2% band): a sale's limit sits [order_limits].reduce_allowance_pct below the bid (reduce_option_allowance_pct, and at least one tick, for an option), a purchase's that far above the ask, rounded toward the touch. The order can fill at once in a fast market, and the broker fills a marketable limit at the best price available. On a US stock or ETF routed SMART it carries IBKR's Adaptive algorithm at Normal priority unless --adaptive-priority asks for Patient, Urgent or none (a plain limit). On an option, a non-USD line or a directed route the order is a plain limit and the terms say "Adaptive not supported for this contract"; the broker layer sends Adaptive only for that one stock shape.

--submit without a token is the hand path: it previews the holding at the live book and places that in one call, with the terms it sent in the result. Anything that reviews terms with a person first, Desk and the paired app included, submits the token.

canary proposals request-stop answers the coverage ledger directly: name an uncovered stock/ETF holding (symbol, or --con-id when ambiguous) and the daemon rebuilds the proposal set and returns that position's trailing-stop proposal with the key and revision to preview. It generates only — placing the stop still goes through preview and submit with every gate intact. An earlier ignore for that stop is cleared by the explicit request, and the result says so. The paired app offers the same action from the Protection panel's uncovered-positions list.

Option exits do not enter the protection coverage ledger. That ledger remains stock/ETF stop coverage; calling a directional option exit portfolio protection would overstate what the broker is actually covering. Option proposals still use the same preview, WhatIf, full position-effect, duplicate-order, account, mode, freeze, origin and explicit submit gates as every other broker-adjacent proposal.

Option hedges are listed, not proposed

A held long option the engine holds as protection produces no exit row, but it is not silent either. The snapshot lists it under option_hedges with what it covers (book for a hedge-listed index option, otherwise the underlying whose stock it covers), the Rulebook's role for a hedge-listed put (protection or unclassified) and how that role was established: measured by Canary's check of the whole book, structural because it covers a holding of its own underlying, unmeasured when that check has not completed (the detail says why), or closed_market when it waits for the options session. The check is Canary's own work and asks nothing of the owner; the standing rule applies until it completes, and the detail sentence says so in plain words. A hedge record carries its days to expiry, cost basis per contract unit, mark and market value, and no threshold, premium return or order terms. A hedge the classifier measures as directional leaves the list and appears as an exit review among the proposals. counts.option_hedges reports the list size separately from the proposal counts.

One row per contract

Two buckets can ask to sell the same contract. A loss exit and theta hygiene both close a near-expiry call deep in loss, and the budget governor and the issuer trim can both cut one line. Canary shows one row for each exact contract and side, and that row carries every reason under covers. Its size is the largest single requirement, never the sum: each sale asks to sell at least its own quantity now, so the largest meets them all. When sizes tie, the Rulebook's exits come first (loss exit, expiry close, profit take), then the issuer trim, the budget governor and theta hygiene; the orders are then identical. The other rows stay listed, blocked with covered_by_proposal, and name the covering row in covered_by.

Two rules settle the cases where the largest would be wrong (owner decisions, 2026-09-28):

Once an order works at the broker for the contract and side, the exits, trims, budget and theta rows for it block until that order fills or is cancelled, and they then recompute from the new position:

Preview and submit repeat the check against a fresh broker read. The brief counts covered rows apart from blocked ones.

A blocked row is the system working

Every blocker carries a code, a message, and an action line. Under stress the action is the part to read, because it names the next command.

An active regulatory or news halt blocks the row. So does an active LULD pause. That is deliberate: a protective order priced against a symbol that is not trading is a guess about the reopening print. Recent flags that are no longer active stay visible as context and do not block.

Other rows block because the evidence is not good enough. A stale option-exit quote raises fresh_option_quote_required. A revision older than that row's current one raises stale_revision; each row carries its own revision, so a neighbour that moved (a cash sweep re-sized on net liquidation value, say) leaves a reviewed stop current. A time-in-force that drifted between the proposal and its preview raises tif_drift, and a quantity beyond the position raises quantity_outside_position. The row stays visible with its reason attached rather than quietly disappearing.

A directional option whose exact quote, cost, role, or session evidence is unavailable appears as a blocked Option exit review row. It is not silently dropped and it cannot be previewed as an order.

When a stop no longer matches its position

If a position shrinks or goes flat while a close-only protective order is still working, the daemon marks that order position_mismatch and grades it critical. Triggering it would open an opposite-direction position rather than close anything.

Kind What it means Fix
short_entry_full no coverage left cancel the order
short_entry_excess partial coverage reduce to reduce_to_quantity

reduce_to_quantity is the position magnitude available in the order's closing direction: the long share count for a SELL, the short magnitude for a BUY. It is the exact quantity a reduce-modify has to target, and it appears with short_risk_quantity in canary orders open --json. The same holdings show up in canary positions as reconcile_required under protection coverage, where a stale protective order is deliberately not counted as protection.

For a sell stop or trail Canary placed on a stock, ETF or option, the protective stop guard makes that fix itself (next section). An order placed by hand in TWS is yours: Canary reports it and leaves it alone.

Protective stop exemption and guard

A broker-side stop that protects a whole long stock position is usually larger than the order cap in force (the risk constitution's [order_limits], scaled with the book; Order limits), and every apparent stock sell exit is otherwise read as opening a short, which needs [order_limits].allow_stock_short. A protective stock exit is exempt from both:

If the open-order list cannot be read, the exemption does not apply and today's refusal stands. A modify that only lowers the quantity of a working stop is exempt on the same terms without the third condition, because it can only shrink what is already working. Every other order keeps the short re-read. The notional cap and [order_limits].max_option_contracts also pass any close or reduction that lowers its underlying's absolute delta, a stock sale, an option close or a strategy close alike (owner decision 2026-10-07 08:13 CEST; Order limits); an order whose delta cannot be measured keeps both caps.

A trailing-stop row that the gates would refuse no longer reads ready. It carries protective_exit_competing_sell when another working sell already covers the shares, protective_exit_inventory_unavailable (waiting for the broker) when the open orders cannot be read, or protective_exit_exceeds_position when the stop is larger than the position.

A resting GTC stop outlives a later hand sale, so the exemption comes with a guard. On the proposal cadence (30 seconds by default) the daemon compares each working sell stop or trail it placed on a stock, ETF or option with the current position, less any sale of Canary's own that is working beside it without being linked to it (next paragraph): at zero or short it cancels the stop; below the stop's remaining quantity it shrinks the stop to the whole-unit position, keeping the trail amount or percent, the current stop price, the limit offset, trigger method, time in force and outside-hours flag. It acts only on a current, complete portfolio download for the connected account and a complete open-order list, and only when the same correction is planned on two passes at least 20 seconds apart, so a partial download or an out-of-order fill never moves an order. Each change goes through the ordinary modify or cancel path with the origin daemon-protective-guard, is journaled on the order, and is written to the decision log (protective_stop_guard.shrink or .cancel). The order's position_mismatch notice stays open until the change lands.

Two orders Canary placed never sell the same shares twice. Every stop or trail Canary places is born in its own broker one-cancels-all group, named after its order reference (oca_group in canary orders open --json). When you sell the line through Canary while that stop works and the two together would sell more than you hold, the sale joins the stop's group: the broker reduces the other order by whatever fills first, a partial fill included, and routes one of them at a time, so the stop cannot sell what the sale already sold, nor the other way round, without waiting for the guard (decision log protective_oca.link). A stop from before this release has no group, and a working order cannot be moved into one, so Canary first shrinks that stop to what the sale leaves, or cancels it when nothing is left, waits for the broker's answer, and only then sends the sale (protective_oca.shrink, .cancel). If that change is refused, unconfirmed within a few seconds, or its send is uncertain, the sale is refused with the reason and the stop stays as it is (protective_oca.refuse); a sale is never sent unlinked beside Canary's own stop. A stop you placed by hand in TWS is never linked or changed: the sale goes out as it is, and the guard reports the hand stop.

Every write gate still decides. With trading disabled, the broker link down or daemon storage unhealthy the guard does nothing and logs the blocker once. trading.freeze blocks every modify, so a shrink waits while frozen; a cancel still goes through, because a freeze never strands an order that needs cancelling.

The residual gap: while the daemon is down, a hand sale is not followed, so a stop can stay larger than the position until Canary is back and the guard has run; and a hand sale beside Canary's stop, or beside a Canary sale, can still sell the line twice until the guard's next passes.

Pre-authorised buckets

The protection policy's [authority].pre_authorised list is empty by default. Only an explicit owner policy edit and version bump enable the named buckets: trailing_stop, option_loss_exit, option_profit_trail, budget_reduction or mandate_reduction (the reduction back to the risk policy's [mandate] budget: a reduce-only batch, largest risk contributor first, each row held to the order caps; see canary mandate). Budget and mandate reductions always wait the full window, even with the drawdown brake latched. The cash sweep is pre-authorised in its own section, [cash] pre_authorised, under the same veto window (Cash management); currency leveling never is. auto_submit remains false; it is not the switch for this scoped scheduler. Build capability, account/mode pins, freeze, fresh evidence, preview, journal, and broker eligibility gates still apply to every submission.

veto_window defaults to "30m" and cannot be less than five minutes. The window starts after the daemon records the Protection alert in its registry. The paired app or another consuming application owns notification delivery; registry acceptance does not prove that a phone received or displayed it, and neither does push-service acceptance. A push is witnessed only when a paired device reports it back: the app's service worker sends a displayed receipt when it shows the notification and an opened receipt when you tap it, and the app host relays the latest receipts to the daemon. canary status shows the last push sent, the last receipt with its device, and how long alert pushes have been silent; canary app push-test proves the channel with a diagnostic push that never counts as an alert (the paired app). Do not treat the window as a guaranteed opportunity to receive a push, and do not list a bucket until canary status shows a push witnessed on the phone.

After the open. An order that prices off the regular session (a patient limit, or a trail without an initial stop) does not go out in the session's first minutes: the pre-authorisation scheduler and a queued authorisation send no earlier than the open plus 5 minutes for stocks and 15 for options. At a stress open, while the latched regime stage reads confirmed stress (a stale confirmed stage still counts; a stage never observed reads calm), options rows that scale the book at your discretion (budget, theta and issuer-trim reductions) wait 30 minutes; loss exits, expiry closes and trailing stops keep 15, because a stop is a stop. The cash sweep's bills are not options: they keep the 5-minute offset after their own session opens (see Cash sweep). A row's readiness dates that time in default_send_at; at a stress open it adds stress_open: true to a row that waits 30 minutes and stress_open_exempt: true to one that keeps 15, and its message says which applies, with the time.

A latched drawdown brake lets eligible non-budget protection records bypass both the notice prerequisite and the waiting window. Budget reductions and cash sweep rows always retain the notice prerequisite and full veto window; shadow rows never schedule. A sweep row also waits for its bill's session: a record created outside it is due at the session's open plus five minutes. canary proposals status reports authorised buckets and pending counts. A human can veto from canary proposals veto KEY or the app before submission. Agent origins cannot veto. A veto applies to that proposal revision; changed evidence can create a new revision and window.

A submission that trading.freeze refuses is deferred, not failed. The record reads deferred with a resubmit time and is not tried again while the freeze stays set. Once you lift the freeze, the daemon resubmits it once, provided the proposal revision is still current; a changed revision supersedes it like a pending record, and a veto still applies while it waits. Any other refusal fails the record for that revision, as before.

A due submission also does not fire while a hand order that is new to its proposal revision is still working at the broker. A hand order is one entered by hand in TWS or by another API client, or placed from a terminal or the paired app; orders the daemon placed itself and agent-origin gated orders never count. It is new when it was placed, or last modified, after the automatic record for the revision was created. When the record is created, the daemon notes the hand orders already working, so a standing order that stays unmodified, such as a stop you placed last week, never holds it, even while its trailing trigger moves. A new order holds it, and so does a standing order you modify, in TWS or through Canary. Any instrument counts, not only the proposal's. The record stays pending, says why it is held, and fires as soon as that order is filled or cancelled, on its original window: waiting never restarts the veto window. The hold applies under a latched brake as well. If the broker's open-order list cannot be read when the record is created, every working hand order counts as new for that record; if it cannot be read when the submission is due, the submission waits. With no bucket pre-authorised, nothing is ever held.

While a record waits, deferred or held, its Protection notice stays open and says what it waits for: deferred because trading is frozen, held behind a hand order, or held because the broker's open orders cannot be read. It never reads as recovered while it waits; it recovers only when the record is submitted, vetoed, or superseded.

The daemon persists submission intent before the broker call and reconciles it against its journal after restart. Installing or updating the binary enables no bucket and clears no freeze; the daemon's next start migrates the policy file after a backup.

Cash management

The cash sweep and currency leveling buy bills and convert currencies. They are not protection, so they live in their own [cash] section of the protection policy file with their own authority; see Cash management.