DocumentationReference

Configuration reference

Generated by scripts/docgen/config-ref. Do not edit by hand — run make docs-regen after changing internal/config/config.go, internal/daemon/protection_policy.go, internal/risk/rulebook_policy.go, internal/daemon/opportunity_policy.go or adding/removing a // docgen:env comment.

TOML config

Config file is loaded from $CANARY_CONFIG, else $XDG_CONFIG_HOME/ibkr/config.toml, else $HOME/.config/ibkr/config.toml. Every field is optional; absent fields take their documented default. Unknown keys fail the load with a targeted error. For [flex], use Set up broker reporting rather than placing the token in TOML; the generated reporting Flex reference is the exact field authority.

Section Field Type Description
[auto_trade] fast_path_enabled *bool FastPathEnabled allows manual proposal preview/submit to use the immediate revalidation path; default true so paper protection stops remain usable.
[auto_trade] hot_reload *bool HotReload controls whether policy changes are reloaded while the daemon runs; default true.
[auto_trade] policy_file string PolicyFile points to the local protection-policy TOML; default ~/.config/ibkr/policies/protection-policy.toml.
[auto_trade] proposal_cadence duration ProposalCadence controls how often the daemon refreshes protection proposals; default 30s.
[auto_trade] proposals_enabled *bool ProposalsEnabled controls whether the daemon may produce advisory protection proposals; default true, and proposals are not broker orders unless separately submitted by an explicitly enabled trading path — the [auto_trade] section name is historical: nothing auto-trades, and the policy's auto_submit stays false.
[auto_trade] reload_interval duration ReloadInterval controls how often the daemon checks policy-file changes; default 30s.
[cash_ledger] bearer_token_file string BearerTokenFile optionally names a private file containing a final SSO bearer token for an already authenticated supported session.
[cash_ledger] ca_cert_file string CACertFile optionally trusts the operator's local Gateway certificate; hostname and certificate validation remain enabled.
[cash_ledger] url string URL is the existing authenticated Web API root ending /v1/api.
[daemon] idle_timeout duration IdleTimeout is how long the auto-spawned daemon stays alive between CLI calls (default 15m, accepts any Go duration string like "1h" or "0s"); set "0s" to disable idle-shutdown when running long cold-start jobs such as the first breadth fan-out under canary daemon --foreground.
[daemon] log_after_close_minutes *int LogAfterCloseMinutes includes post-close and extended-hours work after each closing (default 240, range 0..720).
[daemon] log_before_open_minutes *int LogBeforeOpenMinutes includes preparation and extended-hours work before each opening (default 360, range 0..720).
[daemon] log_calendar_mode string LogCalendarMode controls gateway diagnostic quieting: "conservative" (default) retains warnings because cached positions/API orders cannot prove all manual or overnight duties.
[daemon] log_level string LogLevel is the daemon's log verbosity — one of "debug", "info", "warn" (default), or "error".
[daemon] log_markets []string LogMarkets sets the gateway diagnostic operating baseline: us_equity, us_options, de_xetra, uk_lse, jp_tse, hk_hkex.
[flex] enabled bool Enabled turns the daily Flex statement fetch on; default false.
[flex] query_id string QueryID is the IBKR Activity Flex Query id to fetch.
[flex] token_path string TokenPath points to a file holding only the Flex Web Service token; default ~/.config/ibkr/flex-token (mode 0600).
[gateway] account string Account pins the IBKR account ID like "U1234567"; empty (default) defers to the gateway's managedAccounts list — fine for single-account logins, required disambiguator when the login carries multiple accounts.
[gateway] breadth_client_id *int BreadthClientID is the IBKR clientID used by the dedicated historical-bar connector that backs the SPX breadth refresh.
[gateway] client_id *int ClientID pins the IBKR API clientID for the primary connection (default 15); collisions are treated as a stale-client/operator issue and are not auto-walked to neighboring reserved IDs.
[gateway] host string Host pins the IB Gateway / TWS host; empty (the default) defers to auto-discovery on loopback (127.0.0.1), any non-empty value skips probing.
[gateway] maintenance_windows []string MaintenanceWindows lists the broker's scheduled reset windows as "DAY[-DAY] HH:MM-HH:MM TZ" specs, e.g.
[gateway] port *int Port pins the IB Gateway / TWS API port (typically 4001/4002 for IB Gateway live/paper, 7496/7497 for TWS live/paper); absent (nil) defers to port-probing during discovery.
[gateway] restart_grace string RestartGrace bounds the expected local restart observation window, as a Go duration (default 5m, maximum 1h).
[gateway] restart_time string RestartTime declares the owner-configured daily Gateway restart in 24-hour HH:MM.
[gateway] restart_timezone string RestartTimezone is the owner-confirmed Gateway IANA timezone (for example America/New_York).
[gateway] tls *bool TLS pins TLS mode for the API socket: absent (nil) auto-tries plain first then TLS, true forces TLS-only with no plain fallback, false forces plain — setting the field disables fallback in either direction.
[opportunities] enabled *bool Enabled controls whether the daemon may produce advisory opportunities; default true, and opportunities are not broker writes unless separately submitted by an explicitly enabled trading path.
[opportunities] hot_reload *bool HotReload controls whether opportunity policy changes are reloaded while the daemon runs; default true.
[opportunities] policy_file string PolicyFile points to the local opportunity-policy TOML; default ~/.config/ibkr/policies/opportunity-policy.toml.
[opportunities] refresh_cadence duration RefreshCadence controls how often the daemon refreshes opportunities; default 2m.
[opportunities] reload_interval duration ReloadInterval controls how often the daemon checks the opportunity policy file for changes; default 30s.
[rulebook] policy_file string PolicyFile points to the owner's Rulebook policy TOML (thresholds and rule modes); default ~/.config/ibkr/policies/rulebook-policy.toml.
[rulebook] terminal_evidence_file string TerminalEvidenceFile points to an optional JSON document of reviewed, exact-contract terminal/non-reporting issuer evidence for rules 6-8.
[spx] members_auto_refresh *bool MembersAutoRefresh controls whether the daemon refreshes the S&P 500 constituent list from Wikipedia daily at 02:30 ET (default true; set false to pin the embedded baseline) — overridden symmetrically by the CANARY_SPX_MEMBERS_AUTO_REFRESH env var (1 force-on, 0 force-off).
[trading] allow_option_sell_to_open *bool AllowOptionSellToOpen is retired (owner decision 2026-10-05 19:56 CEST): risk-policy.toml [order_limits].allow_option_sell_to_open decides.
[trading] allow_stock_short *bool AllowStockShort is retired (owner decision 2026-10-05 19:56 CEST): risk-policy.toml [order_limits].allow_stock_short decides.
[trading] max_notional *float64 MaxNotional is retired (owner decision 2026-10-05 19:56 CEST): the per-order notional cap lives in risk-policy.toml [order_limits] as max_order_floor_base, max_order_pct_nlv and max_order_ceiling_base.
[trading] max_option_contracts *int MaxOptionContracts is retired (owner decision 2026-10-05 19:56 CEST): risk-policy.toml [order_limits].max_option_contracts decides.
[trading] mode string Mode selects the local order-entry state: "disabled" (default), "paper", or "live".

Protection policy file

Loaded from the path in [auto_trade].policy_file (default ~/.config/ibkr/policies/protection-policy.toml). The installer and each daemon start write it from Canary's defaults when it is missing (canary policy default protection prints the same file), headed Canary defaults, not yet reviewed; automatic submission and the budget governor's caps are commented placeholders for your decision. An existing file gains the keys a release adds at the next daemon start, after an exact backup; canary policy ensure --dry-run previews the change. Material edits require a higher policy_version; cosmetic edits keep operational identity, and unknown keys fail the load. This policy shapes protection proposals. Automatic submission requires an explicit supported pre-authorised bucket and all existing execution gates; the default grants none. Each key is checked against its own range on load; canary policy check reads the values against each other, against the [order_limits] cap in force and against the live book (Check a policy for plausibility).

Section Field Type Description
(top level) kind string Kind checks the file type: canary.protection_policy or the legacy ibkr.protection_policy alias.
(top level) policy_id string PolicyID is the required identity string for this policy (embedded default "protection-mvp").
(top level) policy_version int PolicyVersion is the owner revision.
(top level) profile string Profile is a human-readable label for the parameter set (embedded default "theta-priority-mvp"); falls back to policy_id when empty.
(top level) schema_version int SchemaVersion is the policy schema revision; only 1 is supported.
[authority] auto_submit bool AutoSubmit would let proposals submit themselves; must be false — proposals are advisory and every broker write stays behind the gated order path.
[authority] close_reduce_only bool CloseReduceOnly restricts proposals to reducing or closing existing positions; must be true in the MVP schema.
[authority] pre_authorised []string PreAuthorised lists the protection buckets whose unblocked proposals the daemon places itself after recording an alert and the veto window (owner decision D3, 2026-09-21).
[authority] veto_window string VetoWindow is how long a pre-authorised proposal waits between its notice and its submission; default 30m, minimum 5m.
[buckets.budget_reduction] basis string Basis is declared_risk_capital (default; the two percentages above are needed) or rulebook: the per-line cap becomes the Rulebook's option_line_act_pct of NLV, and once the book's premium at risk reaches rule 3's premium budget act level of the regime set in force the total cut brings it back to that set's watch level, with no drawdown-brake gate; the two percentages must then be absent.
[buckets.budget_reduction] enabled bool Enabled turns the premium budget governor on (default false; the table is only a commented placeholder in the file Canary writes).
[buckets.budget_reduction] max_order_notional float64 MaxOrderNotional caps the notional of one generated reduction order, exactly as risk_reduction.max_order_notional does (the remainder waits for the next cycle); no default, and until it is written the governor reports needs_your_number.
[buckets.budget_reduction] mode string Mode is shadow or active (default shadow): shadow lists and journals rows that preview and submit refuse with shadow_mode; active makes them ordinary proposals.
[buckets.budget_reduction] per_line_pct_of_risk_capital float64 PerLinePctOfRiskCapital caps one long option line's market value as a percent of declared risk capital, in (0, 100] and at most the total cap; no default, and until it is written the governor reports needs_your_number.
[buckets.budget_reduction] premium_at_risk_pct_of_risk_capital float64 PremiumAtRiskPctOfRiskCapital caps the total market value of non-protection long option legs as a percent of the constitution's declared risk capital, in (0, 100]; no default, and until it is written the governor reports needs_your_number.
[buckets.risk_reduction] enabled bool Enabled turns the issuer concentration-reduction bucket on (default true).
[buckets.risk_reduction] max_order_notional float64 MaxOrderNotional caps the notional of a single generated reduction order (default 10000).
[buckets.theta_hygiene] enabled bool Enabled turns the near-dated time-decay hygiene bucket on (default true).
[buckets.theta_hygiene] max_dte int MaxDTE only considers options expiring within this many days (default 21).
[buckets.theta_hygiene] max_spread_pct_of_mid float64 MaxSpreadPctOfMid skips quotes whose bid/ask spread exceeds this percent of mid — too wide to act on (default 25).
[buckets.theta_hygiene] min_abs_theta_per_day float64 MinAbsThetaPerDay is a dust floor that cheaply skips trivially small positions before the extrinsic decomposition (default 5.0 per day).
[buckets.theta_hygiene] min_extrinsic_pct_of_mark float64 MinExtrinsicPctOfMark is the materiality gate: below this percent of mark the option is intrinsic-dominated and a theta-saving close is suppressed (default 40).
[buckets.trailing_stop] enabled bool Enabled turns the trailing-stop bucket on (default true).
[buckets.trailing_stop] tif string TIF applies to every trailing-stop proposal in this bucket: DAY or GTC, empty means DAY.
[buckets.trailing_stop.options] allow_short_profit_trail bool AllowShortProfitTrail is retained for config compatibility but must remain false; V1 option exits are long-only.
[buckets.trailing_stop.options] default_index_puts_protection bool DefaultIndexPutsProtection keeps ungrouped hedge-listed long puts out of directional exits unless an exact declaration or economic conflict needs review.
[buckets.trailing_stop.options] default_long_calls_directional bool DefaultLongCallsDirectional assigns purpose to ungrouped standard long calls and non-hedge-listed long puts without a conflicting holding or exact-contract declaration.
[buckets.trailing_stop.options] default_pct float64 DefaultPct is the native broker percentage-trail distance before spread, minimum-amount, and tick floors (default 30).
[buckets.trailing_stop.options] directional_intents []protectionOptionDirectionalIntent DirectionalIntents are time-bounded exact-contract overrides.
[buckets.trailing_stop.options] enabled bool Enabled turns approved directional-option loss exits, in-the-money expiry closes and profit trails on (default false).
[buckets.trailing_stop.options] limit_offset_abs float64 LimitOffsetAbs is the explicitly configured absolute limit offset for the stop; required positive when order_type is TRAIL LIMIT (default 0.05).
[buckets.trailing_stop.options] locked_gain_pct float64 LockedGainPct is the minimum gain over cost the rounded initial trail stop must retain (default 5).
[buckets.trailing_stop.options] max_pct float64 MaxPct is the upper bound on the trailing distance (default 50).
[buckets.trailing_stop.options] max_spread_pct_of_mid float64 MaxSpreadPctOfMid skips option quotes wider than this percent of mid (default 25).
[buckets.trailing_stop.options] min_dte int MinDTE is the profit trail's minimum calendar days to expiry (default 14); the loss exit and the in-the-money expiry close still apply below it, until expiry.
[buckets.trailing_stop.options] min_pct float64 MinPct is the lower bound on the trailing distance (default 20).
[buckets.trailing_stop.options] min_trail_abs float64 MinTrailAbs is the minimum absolute trailing amount in dollars (default 0.10).
[buckets.trailing_stop.options] order_type string OrderType is TRAIL LIMIT in V1; a plain TRAIL market trigger is not approved (default TRAIL LIMIT).
[buckets.trailing_stop.options] profit_arm_gain_pct float64 ProfitArmGainPct arms a premium trail when the fresh executable bid is this percent above cost (default 50).
[buckets.trailing_stop.options] recover_cost_gain_pct float64 RecoverCostGainPct is the harvest point: once a long option's gain reaches this percent of its cost, enough contracts are sold to recover the cost and the rest runs (default 100; long-option-exits LO-H2, read by the exit replay until the harvest exit is built).
[buckets.trailing_stop.options] spread_multiple float64 SpreadMultiple sizes the trailing amount as a multiple of the observed spread (default 2).
[buckets.trailing_stop.options] stock_trail_range_multiple float64 StockTrailRangeMultiple is the stock trail: a long option exits when its stock closes more than this many 20-day average true ranges below its highest close since entry (default 2.5; long-option-exits LO-H4, read by the exit replay until the stock trail is built).
[buckets.trailing_stop.options] tif string TIF is the option profit-trail lifetime; V1 requires DAY so theta cannot trigger a persistent order (default DAY).
[buckets.trailing_stop.stock_etf] default_pct float64 DefaultPct is the standard trailing distance in percent (default 8).
[buckets.trailing_stop.stock_etf] enabled bool Enabled turns trailing-stop proposals for stock/ETF positions on (default true).
[buckets.trailing_stop.stock_etf] fallback_pct float64 FallbackPct is the trailing distance used when the default cannot be applied; must lie within [min_pct, max_pct] (default 10).
[buckets.trailing_stop.stock_etf] limit_offset_abs float64 LimitOffsetAbs is the absolute limit offset for the stop; required positive when order_type is TRAIL LIMIT.
[buckets.trailing_stop.stock_etf] max_pct float64 MaxPct is the upper bound on the trailing distance (default 15).
[buckets.trailing_stop.stock_etf] max_spread_pct_of_mid float64 MaxSpreadPctOfMid skips stock/ETF quotes wider than this percent of mid (default 2).
[buckets.trailing_stop.stock_etf] min_pct float64 MinPct is the lower bound on the trailing distance (default 2).
[buckets.trailing_stop.stock_etf] order_type string OrderType is TRAIL or TRAIL LIMIT (default TRAIL).
[cash] confirmation_window string ConfirmationWindow is how long, after you confirm a cash settings save from Desk on your passkey or companion, a further save from the same Desk console session may rely on that confirmation instead of asking your device again, as a duration (Canary writes "10m"; "0s" or no value always asks your device); a save that lets more reach the broker always asks your device.
[cash] pre_authorised []string PreAuthorised lists the cash buckets whose unblocked rows the daemon places itself after recording an alert and the full veto window: only cash_sweep, the sweep's bill buys and redemptions, each held to the sweep's order cap in force.
[cash.leveling] cushion_base *float64 CushionBase is the positive balance, in base currency at the ledger rate, a repaid loan lands at most (between zero and this, never above), and the balance a currency that pays keeps.
[cash.leveling] enabled bool Enabled turns currency leveling on (default false; policy ensure writes the table with enabled = false): each currency borrowed beyond trigger_base then gets a proposal you approve, never one sent on its own.
[cash.leveling] max_slippage_bp *float64 MaxSlippageBP bounds the limit price, in basis points from the live IDEALPRO mid, against the conversion: the preview sends a limit at the mid moved by this much, and holds when the quote is not live and two-sided or its touch already lies beyond it.
[cash.leveling] payback_days *int PaybackDays is how many days a conversion has to earn back its worst-case cost (the commission bound plus the slippage bound) in interest saved, at the rates in the broker's statements: a conversion that would not is not proposed, and between ways to repay a loan the one that saves the most within these days wins.
[cash.leveling] trigger_base *float64 TriggerBase is the band, in base currency at the ledger rate: a currency is repaid only when its trade-date cash is below minus this amount; a smaller loan is left alone.
[cash.leveling.currency.<name>] deliberate_carry bool DeliberateCarry leaves this currency negative on purpose: leveling never repays it or spends from it, whatever the debit (default false).
[cash.sweep] bills_exempt_from_trading_max_notional *bool BillsExemptFromTradingMaxNotional lets a same-currency sweep bill order (BILL or BOND buy or redemption, no conversion) pass the order cap in force of the risk constitution's [order_limits], but only up to the sweep's own order cap in force; anything else keeps the order cap.
[cash.sweep] currency_priority string CurrencyPriority orders eligible native-currency proposals only.
[cash.sweep] enabled bool Enabled turns the cash sweep on (default false; the table is only a commented placeholder in the file Canary writes).
[cash.sweep] keep_cash *float64 KeepCash is the settlement float kept in every currency's own unit, unless a currency table writes its own keep_cash; it applies on top of the reserve's own floor.
[cash.sweep] max_order_notional float64 MaxOrderNotional is the fixed part of the largest sweep order, a buy or a redemption, in base currency, compared at the ledger rate (the next cycle sweeps the rest); the cap in force is the larger of it and max_order_pct_nlv of net liquidation value.
[cash.sweep] max_order_pct_nlv *float64 MaxOrderPctNLV is the share of net liquidation value, in percent, that can lift the order cap above max_order_notional (0 leaves the fixed cap alone).
[cash.sweep] min_net_gain float64 MinNetGain is an advisory benchmark for incremental purchase gain in base currency through maturity.
[cash.sweep] min_order_notional *float64 MinOrderNotional is the smallest sweep buy in base currency: below it nothing is bought.
[cash.sweep] mode string Mode is shadow or active (default shadow): shadow lists and journals rows that preview and submit refuse with shadow_mode; active makes them ordinary proposals under every gate.
[cash.sweep] no_buy_while_borrowed *bool NoBuyWhileBorrowed holds every sweep buy, in every currency, while any currency's cash balance is negative (a margin loan) or a currency's cash is unknown; redemptions still sell.
[cash.sweep] order_step_base *float64 OrderStepBase is the money grid, in base currency, every sweep order is sized on: a buy rounds its amount down to a whole step and a redemption rounds its target up, so the quantity changes only when free cash crosses a step, not with every move of net liquidation value that the reserve and the order cap follow (0 means no grid).
[cash.sweep] reserve_cushion_eur *float64 ReserveCushionEUR is one portfolio-wide cushion.
[cash.sweep] reserve_floor_base *float64 ReserveFloorBase is the least cash, in base currency, the sweep keeps uninvested; the reserve is the largest of it, reserve_pct_nlv of net liquidation value and the cash planned exercises or withdrawals need, and is held in the base currency.
[cash.sweep] reserve_pct_nlv *float64 ReservePctNLV is the share of net liquidation value, in percent, kept as cash (see reserve_floor_base).
[cash.sweep] tax_reviewed_at policyDate TaxReviewedAt is the date you reviewed how bill rolls are taxed (a TOML date such as 2026-09-30); until it is written every row carries the advisory line "tax treatment not yet confirmed" and blocks nothing.
[cash.sweep.currency.<name>] cash_interest_rate_upper *float64 CashInterestRateUpper is retired and no longer read (owner decision 2026-10-11 14:07 CEST): the sweep's cash rate is the broker's own, from the Flex statement's Interest Details (Tiers) section.
[cash.sweep.currency.<name>] cash_interest_valid_through policyDate CashInterestValidThrough is retired with cash_interest_rate_upper and no longer read; kept readable so an older file still loads.
[cash.sweep.currency.<name>] etf_exchange string ETFExchange is the declared ETF's listing exchange, required with etf_symbol; the pair is resolved to a contract id and matched by it, never by broker text.
[cash.sweep.currency.<name>] etf_symbol string ETFSymbol is the declared ETF's exchange symbol, required when etf is an instrument or the fallback; no default, and until it is written the status names it under needs_your_number.
[cash.sweep.currency.<name>] fallback string Fallback is etf or none: the instrument used only after a completed contract search finds no bill line (default etf for EUR, none elsewhere).
[cash.sweep.currency.<name>] instruments []string Instruments lists what the sweep may buy in this currency from the closed vocabulary us_tbill (USD only), de_bubill and fr_btf (EUR only), uk_tbill (GBP only), ca_tbill (CAD only), etf, or none on its own (default: the currency's compiled declaration).
[cash.sweep.currency.<name>] isins []string ISINs lists the bills the sweep may buy in EUR, GBP or CAD by ISIN (default empty, which reads universe_unavailable), each of a declared bill instrument: DE de_bubill, FR fr_btf, GB uk_tbill, CA ca_tbill; USD bills come from TreasuryDirect's list instead.
[cash.sweep.currency.<name>] keep_cash *float64 KeepCash is this currency's settlement float in its own unit, overriding the bucket's keep_cash: the sweep invests only above it and redeems below it.
[cash.sweep.currency.<name>] ladder_rungs int LadderRungs is how many target maturities the ladder spreads evenly from min_maturity_days to max_maturity_days (default 4).
[cash.sweep.currency.<name>] max_maturity_days int MaxMaturityDays is the longest maturity a bill may have when bought and the last rung's target (default 91, EUR 182; at most 397).
[cash.sweep.currency.<name>] min_maturity_days int MinMaturityDays is the shortest maturity a bill may have when bought and the first rung's target (default 28, the four-week bill).
[cash.sweep.currency.<name>] min_tranche *float64 MinTranche is retired in favour of min_order_notional and kept readable: when written it still raises this currency's smallest buy, in its own unit; absent, it adds nothing.
[cash.sweep.currency.<name>] settlement_days *int SettlementDays overrides the bill route's settlement lag in payment business days, between 1 and 5 (default: Canary's maintained route, USD bills T+1 and EUR bills T+2, T+1 for trades from 2027-10-11; other currencies have none and hold).
[cash.sweep.currency.<name>] settlement_exchange string SettlementExchange overrides the bill route's broker exchange (default SMART for USD and EUR bills); a bill order on another exchange holds.
[cash.sweep.currency.<name>] settlement_valid_through policyDate SettlementValidThrough optionally ends this currency's settlement route on a date (a TOML date such as 2027-06-30), after which its bill orders hold; omit it, as Canary maintains its default route with its payment calendars.

Rulebook policy file

Loaded from the path in [rulebook].policy_file (default ~/.config/ibkr/policies/rulebook-policy.toml). The installer and each daemon start write it from Canary's defaults when it is missing (canary policy default rulebook prints the same file); until then the compiled defaults run. A key absent from the file follows Canary's default; the next daemon start writes that default into the file, after a backup. canary rules policy set KEY=VALUE edits only the keys you name, in place, and raises policy_version; a material hand edit applies only with a higher policy_version, unknown keys and invalid values fail the load, and the policy in force stays until a valid file replaces it. canary rules policy shows the limits in force; canary policy check reads them against each other and across the regime sets. The Rulebook is advisory; these limits never block or place an order by themselves.

Section Field Type Description
(top level) budget_watch_pct float64 BudgetWatchPct watches at or above this issuer loss as a percent of effective risk capital: the lesser of declared risk capital and equity above the protected floor. Missing capital inputs remain unknown. Rule 18 never acts or trims.
(top level) cluster_drop_pct float64 ClusterDropPct is the downward price scenario, in percent, for every issuer in a declared cluster. Empty clusters leave rule 17 unevaluated.
(top level) cluster_watch_pct float64 ClusterWatchPct watches at or above this cluster scenario loss as a percent of NLV. Rule 17 never acts or trims.
(top level) clusters map[string][]string Clusters names related issuers that rule 17 tests falling together, keyed by a name you choose; members are symbols or issuer group names.
(top level) delta_swing_watch_pct float64 DeltaSwingWatchPct watches at or above this magnitude of issuer dollar delta as a percent of NLV. Protection-classified index short delta is exempt. Rule 16 never acts or trims.
(top level) earnings_freeze_sessions int EarningsFreezeSessions acts on an issuer already at rule 1's watch/act level when earnings are zero through this many US sessions away, inclusive. Missing applicable earnings or size evidence is unknown. Freeze is a finding, not an order prohibition.
(top level) earnings_stale_days int EarningsStaleDays is retired compatibility metadata; no rule reads it. Earnings provider evidence older than 24 hours is stale; this key cannot change that.
(top level) exit_act_loss_pct float64 ExitActLossPct acts at or above this percentage of premium paid lost on a non-protection long option. The loss-exit bucket may propose a sale; a separate permission check governs submission.
(top level) exit_participation_pct float64 ExitParticipationPct is the percentage of 20-day average daily share volume available per exit day. Missing volume leaves the normal concentration bands in use, with liquidity unmeasured.
(top level) exit_watch_loss_pct float64 ExitWatchLossPct watches at or above this percentage of premium paid lost on a long option. Protection-classified hedges are exempt.
(top level) fx_exposure_watch_pct float64 FXExposureWatchPct watches at or above this magnitude of combined non-base-currency exposure as a percent of NLV. No act tier; missing account or currency evidence remains unknown.
(top level) greeks_gap_floor_pct_nlv float64 GreeksGapFloorPctNLV is the materiality floor: a name whose legs missing delta exceed this share of NLV makes exposure rules unknown rather than understated.
(top level) hedge_line_act_pct float64 HedgeLineActPct acts at or above this protection option's premium at risk as a percent of NLV.
(top level) hedge_line_watch_pct float64 HedgeLineWatchPct watches at or above this protection option's premium at risk as a percent of NLV. Rule 12 separately measures total hedge size.
(top level) hedge_min_days int HedgeMinDays is the minimum calendar days to expiry for same-issuer option hedge credit; expiry must also follow known earnings. Unknown earnings falls back to this minimum alone. Cross-issuer index hedges give no issuer credit.
(top level) hedge_symbols []string HedgeSymbols lists the index underlyings whose long puts can classify as protection (rules 1, 2, 5, 12, 13).
(top level) illiquid_act_pct float64 IlliquidActPct acts at or above this illiquid issuer loss as a percent of NLV.
(top level) illiquid_days_to_exit float64 IlliquidDaysToExit switches to the illiquid bands only when estimated exit days strictly exceed this value.
(top level) illiquid_watch_pct float64 IlliquidWatchPct watches at or above this illiquid issuer loss as a percent of NLV.
(top level) issuer_groups map[string][]string IssuerGroups joins share classes and ADR/ordinary lines into one issuer, keyed by a name you choose. Canary has no issuer data: an ungrouped symbol is its own issuer.
(top level) kind string Kind identifies the file type (canary.rulebook_policy); ibkr.rulebook_policy remains a supported alias. It grants no authority.
(top level) margin_headroom_act_pct float64 MarginHeadroomActPct acts strictly below this excess liquidity as a percent of NLV; it may not exceed the watch level. Rule 19 never trims and drives no proposal.
(top level) margin_headroom_watch_pct float64 MarginHeadroomWatchPct watches strictly below this broker excess liquidity as a percent of NLV (rule 19), the worse of the current and the look-ahead figure when the broker reports both; a reading exactly at the level passes. Missing excess liquidity or NLV is unknown, never a pass.
(top level) modes map[string]string Modes controls presentation and alerts: off hides the row, track shows it without alerts, alert enables alert production. Shared measurements still run; independent proposal buckets retain their own enablement.
(top level) option_line_act_pct float64 OptionLineActPct acts at or above this long-option premium at risk as a percent of NLV. It also supplies the budget governor's per-line limit under basis = rulebook.
(top level) option_line_watch_pct float64 OptionLineWatchPct watches at or above this long-option premium at risk (the higher of cost and current value) as a percent of NLV. Missing cost falls back to current value; protection uses the separate hedge bands.
(top level) option_name_act_pct float64 OptionNameActPct caps the premium at risk on one underlying, every long option outside protection on it summed (the higher of price paid and current value, as rule 2 measures a line), as a percent of NLV. An option buy that would take the name past it is refused at every order gate; the premium budget's act level caps the book the same way. Owner decision 2026-10-23 18:22 CEST: options add risk within premium limits, not within the mandate's volatility budget.
(top level) overhedge_multiple float64 OverhedgeMultiple is the over-hedge boundary as a multiple of rule 12's band top: rule 12 acts above this multiple of the current regime's top, and index puts above this multiple of the widest regime's top count as directional exposure rather than protection.
(top level) policy_id string ID names the policy (baseline rulebook-v5; canary rules policy set writes rulebook-owner).
(top level) policy_version int Version records the owner revision; raise it for material edits. Cosmetic edits do not change operational identity. The first valid file is adopted at any positive revision.
(top level) red_on_green_name_drop_pct float64 RedOnGreenNameDropPct watches a stock-leg day change at or below this negative percent when SPY meets red_on_green_spy_up_pct. Missing stock-leg tape is not screened; absent SPY makes the row unknown. US session only.
(top level) red_on_green_spy_up_pct float64 RedOnGreenSPYUpPct activates rule 9 when SPY's day gain is at or above this percent; the holding must also meet its drop threshold.
(top level) regime_stage_max_age_minutes int RegimeStageMaxAgeMinutes bounds trust in the latched regime stage, in minutes. Carried or missing stages evaluate both the carried set and calm set, keeping the worse verdict; stale evidence cannot relax a band.
(top level) runway_act_dte int RunwayActDTE acts on the same long-option scope at this many calendar days to expiry or fewer.
(top level) runway_itm_delta_floor float64 RunwayITMDeltaFloor exempts a long option when absolute delta is at least this fraction (0.70 means 70 delta). Missing delta gives no ITM exemption.
(top level) runway_watch_dte int RunwayWatchDTE watches long options at this many calendar days to expiry or fewer. ITM and eligible hedge legs are exempt; excessive hedging removes the hedge exemption.
(top level) schema_version int SchemaVersion selects the file format (1), independently of the owner revision.
(top level) short_put_act_line_pct_nlv float64 ShortPutActLinePctNLV acts when one short put spanning earnings has assignment notional at or above this percent of NLV. Short calls spanning earnings always act.
(top level) short_put_act_name_pct_nlv float64 ShortPutActNamePctNLV acts when a name's short puts spanning earnings together reach this assignment notional as a percent of NLV.
(top level) single_name_act_pct float64 SingleNameActPct acts at or above this issuer loss as a percent of NLV. This can generate a trim proposal; it never authorises an order.
(top level) single_name_watch_pct float64 SingleNameWatchPct watches at or above this modelled worst-case issuer loss as a percent of NLV (account equity). All issuer legs are netted from current marks; an authorised risk-reduction proposal trims toward this level.
(top level) takeover_gap_pct float64 TakeoverGapPct is the upward price scenario, in percent, for short stock and uncovered short calls. It is a finite scenario for an unbounded loss, not a maximum possible loss.
(top level) winner_trim_day_up_pct float64 WinnerTrimDayUpPct watches a holding whose stock-leg day gain is at or above this percent and whose absolute stock-equivalent exposure meets winner_trim_min_exposure_pct. Missing tape is not screened. US session only; no automatic trim is authorised here.
(top level) winner_trim_min_exposure_pct float64 WinnerTrimMinExpoPct is rule 10's inclusive minimum absolute stock-equivalent exposure as a percent of NLV. A qualifying gain with unmeasured size remains unknown.
[regime_calm] extrinsic_act_pct float64 ExtrinsicActPct is rule 4's act level: option time value outside protection as a percent of NLV.
[regime_calm] extrinsic_watch_pct float64 ExtrinsicWatchPct is rule 4's watch level: option time value outside protection as a percent of NLV.
[regime_calm] hedge_band_max_pct float64 HedgeBandMaxPct is rule 12's upper bound: index protection as a percent of gross long exposure.
[regime_calm] hedge_band_min_pct float64 HedgeBandMinPct is rule 12's lower bound: index protection as a percent of gross long exposure.
[regime_calm] net_exposure_act_pct float64 NetExposureActPct is rule 15's act level for the same measure; the stress read calls it urgent while the regime set is confirmed.
[regime_calm] net_exposure_watch_pct float64 NetExposureWatchPct is rule 15's watch level: the magnitude of the whole book's signed stock-equivalent exposure, hedges included, as a percent of NLV. Material missing delta may prove a breach by a lower bound but cannot prove a pass. At watch or act the Rulebook reads sell-only.
[regime_calm] premium_budget_act_pct float64 PremiumBudgetActPct is rule 3's act level, the cap on the same measure. Canary's default is the same in every regime set, so a rise in volatility alone never forces a sale; tighten it per set if you want. Under basis = rulebook the budget governor sells back to the set's watch level once the total reaches it.
[regime_calm] premium_budget_watch_pct float64 PremiumBudgetWatchPct is rule 3's watch level, the budget for new buying: premium at risk in long options outside protection (the higher of price paid and current value, summed) as a percent of NLV. It tightens with the regime; at watch or act the Rulebook reads sell-only.
[regime_confirmed] extrinsic_act_pct float64 ExtrinsicActPct is rule 4's act level: option time value outside protection as a percent of NLV.
[regime_confirmed] extrinsic_watch_pct float64 ExtrinsicWatchPct is rule 4's watch level: option time value outside protection as a percent of NLV.
[regime_confirmed] hedge_band_max_pct float64 HedgeBandMaxPct is rule 12's upper bound: index protection as a percent of gross long exposure.
[regime_confirmed] hedge_band_min_pct float64 HedgeBandMinPct is rule 12's lower bound: index protection as a percent of gross long exposure.
[regime_confirmed] net_exposure_act_pct float64 NetExposureActPct is rule 15's act level for the same measure; the stress read calls it urgent while the regime set is confirmed.
[regime_confirmed] net_exposure_watch_pct float64 NetExposureWatchPct is rule 15's watch level: the magnitude of the whole book's signed stock-equivalent exposure, hedges included, as a percent of NLV. Material missing delta may prove a breach by a lower bound but cannot prove a pass. At watch or act the Rulebook reads sell-only.
[regime_confirmed] premium_budget_act_pct float64 PremiumBudgetActPct is rule 3's act level, the cap on the same measure. Canary's default is the same in every regime set, so a rise in volatility alone never forces a sale; tighten it per set if you want. Under basis = rulebook the budget governor sells back to the set's watch level once the total reaches it.
[regime_confirmed] premium_budget_watch_pct float64 PremiumBudgetWatchPct is rule 3's watch level, the budget for new buying: premium at risk in long options outside protection (the higher of price paid and current value, summed) as a percent of NLV. It tightens with the regime; at watch or act the Rulebook reads sell-only.
[regime_early_warning] extrinsic_act_pct float64 ExtrinsicActPct is rule 4's act level: option time value outside protection as a percent of NLV.
[regime_early_warning] extrinsic_watch_pct float64 ExtrinsicWatchPct is rule 4's watch level: option time value outside protection as a percent of NLV.
[regime_early_warning] hedge_band_max_pct float64 HedgeBandMaxPct is rule 12's upper bound: index protection as a percent of gross long exposure.
[regime_early_warning] hedge_band_min_pct float64 HedgeBandMinPct is rule 12's lower bound: index protection as a percent of gross long exposure.
[regime_early_warning] net_exposure_act_pct float64 NetExposureActPct is rule 15's act level for the same measure; the stress read calls it urgent while the regime set is confirmed.
[regime_early_warning] net_exposure_watch_pct float64 NetExposureWatchPct is rule 15's watch level: the magnitude of the whole book's signed stock-equivalent exposure, hedges included, as a percent of NLV. Material missing delta may prove a breach by a lower bound but cannot prove a pass. At watch or act the Rulebook reads sell-only.
[regime_early_warning] premium_budget_act_pct float64 PremiumBudgetActPct is rule 3's act level, the cap on the same measure. Canary's default is the same in every regime set, so a rise in volatility alone never forces a sale; tighten it per set if you want. Under basis = rulebook the budget governor sells back to the set's watch level once the total reaches it.
[regime_early_warning] premium_budget_watch_pct float64 PremiumBudgetWatchPct is rule 3's watch level, the budget for new buying: premium at risk in long options outside protection (the higher of price paid and current value, summed) as a percent of NLV. It tightens with the regime; at watch or act the Rulebook reads sell-only.

Opportunity policy file

Loaded from the path in [opportunities].policy_file (default ~/.config/ibkr/policies/opportunity-policy.toml). Same envelope, reload discipline and materialization as the protection policy; canary policy default opportunity prints Canary's defaults. Controls option-exercise detection and eligibility; no automatic exercise is supported. Schema 2 requires all effective fields of an enabled detector. Schema 1 preserves historical zero/false omissions with diagnostics. Legacy profile and retired authority switches select no preset and grant no permission.

Section Field Type Description
(top level) kind string Kind checks the file type: canary.opportunity_policy or the legacy ibkr.opportunity_policy alias. It grants no trading permission.
(top level) policy_id string PolicyID is the required identity string for this policy (embedded default "opportunity-option-exercise-mvp").
(top level) policy_version int PolicyVersion records the owner revision; raise it for material edits. Names, comments and revision-only bumps do not change live action identity.
(top level) profile string Profile is a legacy display label only; it selects no preset and has no operational effect. New files omit it.
(top level) schema_version int SchemaVersion selects the file format. Schema 1 preserves historical omission defaults; schema 2 requires every real setting of an enabled detector.
[authority] auto_submit bool AutoSubmit is unsupported and must be false. Every exercise requires explicit confirmation through the existing gated order path. New files omit this key.
[authority] exercise_reduce_only bool ExerciseReduceOnly is retired and ignored. Code always requires exercise to close or reduce the underlying position; this field cannot widen that scope.
[buckets.option_exercise] allow_no_option_bid bool AllowNoOptionBid is retired and ignored. An absent or negative option bid prevents a candidate; a zero bid is accepted. New files omit this key.
[buckets.option_exercise] enabled bool Enabled runs the option-exercise detector (Canary default true). Detection produces candidates, never automatic submission. Set false to disable this detector.
[buckets.option_exercise] max_quote_age string MaxQuoteAge is the maximum age of option quote evidence and a dated underlying quote, written as a positive duration (Canary default 30s). Missing or stale option evidence blocks eligibility; an undated underlying quote has no age check. This key does not prove executable liquidity.
[buckets.option_exercise] min_gain_pct_intrinsic float64 MinGainPctIntrinsic is the minimum gross gain as a percentage of intrinsic value (Canary default 0.5). It must be met together with min_total_gain.
[buckets.option_exercise] min_total_gain float64 MinTotalGain is the minimum gross gain for the full candidate quantity in the contract currency (Canary default 25). Gain is intrinsic value minus option bid value, before fees, slippage and funding. Both gain thresholds must be met, including equality.
[buckets.option_exercise] require_american_style bool RequireAmericanStyle requires the current USD stock/ETF heuristic when true (Canary default true). This is not verified contract-style evidence; failing the heuristic blocks eligibility.
[buckets.option_exercise] require_rth bool RequireRTH blocks exercise eligibility outside the US regular trading session when true (Canary default true). A blocked candidate may remain visible.

Runtime platform settings

Daemon-owned preferences persisted in $XDG_STATE_HOME/ibkr/daemon.db and changed at runtime without a restart. Feature preferences may be changed via canary settings set <key>=<value>, the SPA Settings tab, or PATCH /api/settings. Setting a key to null clears the runtime override, and every response field carries access/source/reason metadata. trading.freeze requires canary settings set from an interactive human terminal; missing, agent, and paired-device origins are rejected in disabled, paper, and live modes. The runtime trading-limit keys (trading.limits.*) are retired: the order limits are read from risk-policy.toml [order_limits] only, and a time-bounded larger cap is a one-shot canary policy override --control order_limits.max_order_floor_base (Policy). Ownership and semantics: internal-docs/design/platform-settings.md.

Key Value Class Description
cash_sweep.currency_priority usd_first/balanced/eur_first/null owner Cash-sweep ordering only: usd_first, balanced, eur_first, or null for policy/default; never activates reserve policy or changes funding, caps, floors, freeze, or execution authority.
display.date_format us/eu/us_weekday/eu_weekday/null owner Calendar-date presentation in the SPA: us, eu, us_weekday, or eu_weekday; it never changes typed timestamps or market-session authority (default us).
features.stock_protection.enabled true/false/null owner Allows stock/ETF protection proposal actions; false blocks them with a stock_protection_disabled blocker while proposal snapshots stay readable (default true).
features.rulebook.enabled true/false/null owner Turns the advisory daily trading-rulebook checklist on; false hides the SPA card, empties rules.snapshot, and stops advisory rule_* preview warnings — it can never affect broker-write gating (default true).
features.rulebook.earnings_overrides.<SYMBOL> YYYY-MM-DD[Tamc/Tbmo]/null owner Manual SYMBOL → YYYY-MM-DD (optional Tamc/Tbmo suffix) earnings pins, authoritative over fetched dates for rules 6-8; patches merge per symbol.
trading.freeze true/false/null safety Runtime trading brake: true blocks every new broker write while cancels stay allowed; human-only by policy, and the write origin is audited (default false).
trading.tws_order_control.enabled true/false/null safety Lets an owner-confirmed cancel or change reach an order placed by hand in TWS through a separate client-0 connection; paper works once enabled, live also needs the daemon-recorded paper proof (trading.tws_order_control.paper_proven_at); human-only by policy (default false).
regime.journal.enabled true/false/null owner Turns forward regime decision-event collection in daemon.db on (default true).
stress.journal.enabled true/false/null owner Turns forward portfolio-stress decision-event collection in daemon.db on, mirroring regime.journal.enabled (default true).
chains.recorder.enabled true/false/null owner The owner's off switch for the daily option-chain snapshot (quotes, sizes, IV, greeks, open interest) 30 minutes before the US close into option-chains.db beside daemon.db: unset, it records what holdings and registered strategies declare; false stops it. Market-data reads only, within a line reserve for the live display (default unset: on).
chains.recorder.symbols SYM,SYM,.../[]/null collection Research names the option-chain recorder covers after held option underlyings and registered strategies' declared chains, at most 12 in all; a collection setting any origin may change; null restores none.

Environment variables

Read at process startup. Override TOML config where applicable; see the per-var description for precedence rules.

Variable Description
CANARY_AGENT_CONTEXT When set (any value), broker writes from this process are classified as agent-origin for audit and origin-specific policy. The variable can only restrict: no environment variable can claim a human origin.
CANARY_APP_ADDR HTTP listen address for canary app. Defaults to 0.0.0.0:8765 so a paired phone on the LAN can reach the app.
CANARY_APP_LOG_LEVEL Log verbosity for canary app — one of debug, info, warn (default), or error. Mirrors the daemon's [daemon] log_level config key.
CANARY_APP_PUBLIC_URL Public trusted HTTPS base URL for the canary app PWA/relay origin. Defaults to a LAN URL for wildcard listen addresses, falling back to loopback when no LAN address is available.
CANARY_APP_REMOTE Enable the outbound Cloudflare Worker relay for canary app, making pairing URLs reachable through the public relay origin.
CANARY_APP_REMOTE_URL Cloudflare Worker relay base URL for canary app --remote. Defaults to https://remote.osauer.dev.
CANARY_APP_STATE_DIR Directory for canary app paired devices, alert settings, VAPID keys, and private alert-delivery evidence. Defaults to $XDG_STATE_HOME/ibkr/app or $HOME/.local/state/ibkr/app.
CANARY_COLOR Force terminal colour on (always), off (never); any other value defers to NO_COLOR + TTY detection.
CANARY_CONFIG Override the config.toml path. Defaults to $XDG_CONFIG_HOME/ibkr/config.toml or $HOME/.config/ibkr/config.toml.
CANARY_INSTALL_DIR Override the install directory for canary update. Defaults to $HOME/.local/bin only when the running binary is installed there; custom installations require an explicit override. The release pipeline uses this to sandbox dog-food installs to a temporary directory.
CANARY_LOG Override the daemon log file path. Defaults to $XDG_STATE_HOME/ibkr/ibkr-daemon.log or $HOME/.local/state/ibkr/ibkr-daemon.log.
CANARY_SOCKET Override the daemon IPC socket path. Defaults to $XDG_RUNTIME_DIR/ibkr/ibkr.sock or $HOME/.cache/ibkr/ibkr.sock.
CANARY_SPX_MEMBERS_AUTO_REFRESH Symmetric override of [spx] members_auto_refresh. 1 force-enables, 0 force-disables, unset / other defers to TOML.
IBKR_PACKET_LOG_TEMPLATE Template path for raw IBKR wire-packet logs. Trailing / treats as directory; %d placeholder gets the gateway client ID. Unset disables wire logging.
IBKR_WIRE_INTERCEPTOR Enable the account-sensitive decoded wire-frame recorder. Unset or false disables it.
IBKR_WIRE_LOG_PATH Append decoded account-sensitive wire frames as JSONL at this path. Unset keeps frames in memory only.
IBKR_WIRE_RING_SIZE Maximum decoded wire frames retained in memory when the interceptor is enabled; default 256.
NO_COLOR Standard https://no-color.org/ override. Any non-empty value disables colour regardless of CANARY_COLOR (unless CANARY_COLOR=always).