The rulebook
canary rules evaluates nineteen discipline checks against the book you are
holding, using limits you can set, and reports which are breached. Nothing it produces reaches the
broker.
The Trading Rulebook design document is the semantic authority for every threshold and edge case, and stays in the repository. Sensors covers the same component as a measurement: authority, freshness, and evidence reuse.
The nineteen rules
| # | Rule | What it measures | Default mode |
|---|---|---|---|
| 1 | Worst-case loss on one issuer | The most one issuer can lose at any price, every leg on it netted from current marks, as a share of NLV. Watch at 30%, act (the cap) at 40%; an issuer that takes more than three days to exit at 20% of its 20-day volume uses 20/30. A long option counts as protection only if it expires after the issuer's next earnings and at least 14 days out; short stock and uncovered short calls are sized at a 100% rise and flagged unbounded. | Alert |
| 2 | Premium at risk in one option position | Each long option position at the higher of the price paid and its value, as a share of NLV. A losing position keeps counting at what you paid, so its fall frees no room to buy more. | Track |
| 3 | Premium budget | Premium at risk in every long option position outside portfolio protection (the higher of the price paid and its value, as in rule 2), summed, as a share of NLV. The watch level is the budget for new buying and tightens with the regime: calm 25%, early warning 20%, confirmed stress 15%. The act level is the cap, 35% in every regime by default, so a rise in volatility alone never forces a sale. At watch or act the Rulebook reads sell-only. Available funds are shown as context. Not evaluated without a long option. | Alert |
| 4 | Option time value at risk | Paid option time value as a share of NLV. Positions classified as portfolio protection use rules 2 and 12 instead. | Alert |
| 5 | Options nearing expiry | Long options with 14 days or fewer remaining (act at 7 or fewer). Deep in-the-money positions and portfolio protection are listed separately. | Alert |
| 6 | Earnings timing | Whether an out-of-the-money long option expires before the next earnings announcement. This is a timing fact; it does not assume the position should span earnings. | Track |
| 7 | Short options held through earnings | Short options that remain open through the next earnings announcement, including assignment exposure for short puts. | Alert |
| 8 | Position size near earnings | Positions on an issuer at or above rule 1's watch level within three trading sessions of earnings. | Track |
| 9 | Holding falls while the market rises | A held stock falling while SPY rises during the regular session. | Off |
| 10 | Large winner today | A large holding above its daily gain level. | Off |
| 11 | Positive day with urgent risks open | A positive account day while an act-level Rulebook item remains open. | Off |
| 12 | Index protection size | Short delta assigned to portfolio protection as a share of gross long exposure, against a band that depends on the regime. A long book with no protection reads 0% and watches as unhedged; below the band's bottom is a watch too. It acts above twice the band's top (overhedge_multiple), and index puts above that multiple of the widest band count as directional shorts, not protection. Not evaluated without a long book. |
Alert |
| 13 | Long option loss limit | Loss on premium paid for each long option position. | Alert |
| 14 | Foreign-currency exposure | Non-base-currency exposure as a share of NLV. | Track |
| 15 | Net market exposure | The whole book's signed stock-equivalent exposure, index protection included, as a share of NLV: how far the book moves with the market. Watch and act by regime: calm 100% (fully invested, unlevered) and 150%, early warning 100% and 130%, confirmed stress 75% and 100%. At watch or act the Rulebook reads sell-only. | Track |
| 16 | Delta swing on one issuer | One issuer's dollar delta as a share of NLV: what a 10% move costs, with gamma named when it bends that materially. Watch at 30%; it never acts. | Track |
| 17 | Cluster falling together | Every issuer in a cluster you declare falls 30% together, each netted like rule 1. Watch when the cluster loses 15% of NLV; it never acts. Not evaluated until you declare a cluster. | Track |
| 18 | Issuer loss against risk capital | One issuer's worst-case loss against the constitution's effective risk capital. Watch at 100% of it; it never acts. Unknown, never a pass, until the constitution carries the numbers. | Alert |
| 19 | Margin headroom | The broker's excess liquidity as a share of NLV: the room left before a margin call. When the broker also reports its look-ahead excess liquidity (after the next margin cycle), the lower of the two counts, and the evidence says which governed. It reads downward: watch below 30%, act below 15%, and a reading exactly at a level passes it. The evidence adds the maintenance and initial margin when the broker reports them. Unknown, never a pass, without the excess liquidity or NLV. It never trims and drives no proposal; at watch or act an order preview warns every buy and every sale that opens or adds to a short position. | Alert |
alert rules can create alert episodes, track rules remain visible without
creating alerts, and off rules are not evaluated. Rules 16 to 18 only watch:
they never act, never count toward act totals, and never drive a trim.
Sell-only
While rule 3 or rule 15 is at watch or act, whatever its mode, the result
carries sell_only: {active: true, rules: [...]} naming them, the two rows
carry sell_only: true, and canary rules prints a sell-only line under its
header. An order preview then warns every buy with rule_cash_sell_only, and a
buy that adds to the side rule 15 flags with rule_net_exposure (a put bought
against a net-long book does not). Like every Rulebook verdict it is advisory:
nothing about submit eligibility changes. Rule 15 tracks by default; to have
it raise alerts as well, run canary rules policy set modes.net_exposure=alert.
Rule 19 does not put the Rulebook in sell-only, but while margin headroom is
at watch or act an order preview warns every buy with rule_margin_headroom,
because a buy consumes margin, and every sale that opens or adds to a short
stock or option position, for the same reason. A close or reduce never warns,
and the warning is advisory like the others.
One issuer, one measure
Rule 1 is Canary's single definition of concentration. An issuer is an
underlying joined with the share classes and ADR or ordinary lines you list
under issuer_groups (Canary has no issuer data, so an unlisted symbol is its
own issuer). Its worst-case loss comes from valuing every leg on intrinsic
payoffs at zero, every strike, today's price and a 100% rise
(takeover_gap_pct), from current marks: long stock can lose its value, a long
option its premium, a short put its strike notional less what it is worth
now, and a covered call credits only its premium. An early assignment realizes
exactly a short leg's intrinsic value, so the netting holds if any short leg is
assigned. Index options and options on other underlyings give an issuer no
credit. The risk-reduction trim starts at the act level and goes back to the
watch level on this same measure, and the stress read uses rule 1 and rule 16
for its concentration row rather than measuring concentration itself.
Rule 15 is likewise the only definition of net exposure. The stress read's
exposure row, its net_delta_high driver and its net figure are rule 15's
reading, bands and verdict under the regime set in force: rule 15 at watch is
a stress watch, at act a stress act, and at act under the confirmed-stress set
urgent. Without a rule 15 measurement the exposure row says so and never reads
as a pass.
Rule 19 is the only definition of margin headroom. The stress read's margin
row, its margin_cushion_low driver and its cushion figure are rule 19's
reading, bands and verdict: rule 19 at watch is a stress watch, at act a
stress act that cuts back to the watch level. Rule 19 already judges the
broker's look-ahead figure, so there is no separate look-ahead warning.
Without a rule 19 measurement, including rule 19 turned off, the margin row
says so, quotes the look-ahead figure as context, and never reads as a pass.
Set your own limits
Every threshold and mode in the table is yours to change. They live in
~/.config/ibkr/policies/rulebook-policy.toml (or [rulebook].policy_file),
which the installer and each daemon start write from Canary's defaults, policy
rulebook-v5, when it is missing. Until you delete its
# Canary defaults, not yet reviewed. line it reads default, unreviewed.
See the limits in force:
canary rules policy
Change one, turn a rule off or up, or return to Canary's defaults:
canary rules policy set regime_confirmed.premium_budget_watch_pct=12
canary rules policy set modes.net_exposure=alert
canary rules policy reset regime_confirmed.premium_budget_watch_pct
canary rules policy reset --all
set edits the file in place: it changes only the lines of the keys you
name, keeps every other value and comment, raises policy_version, and refuses
an unknown key or an invalid value before writing anything. reset KEY writes
Canary's current default for that key, and reset --all rewrites the file
from Canary's template after keeping the old one as a backup. Declare an
issuer group or a cluster with set issuer_groups.NAME=AAA,AAB and remove it
with reset issuer_groups.NAME. set refuses the retired keys no rule reads
— cash_sell_only_pct, cash_reserve_min_pct (rule 3 is now the premium
budget) and the top-level net_exposure_watch_pct and net_exposure_act_pct
(rule 15's bands now live in the [regime_*] tables); a file that still
carries one loads with the key ignored, a note in policy_status names it,
any set or reset removes it, and the next upgrade turns it into a comment
and adds the new keys at their defaults. The daemon
applies the file within 30 seconds. Hand edits work as well and apply only
with a higher policy_version. A key missing from the file follows Canary's
default, canary rules policy lists it under not in file, and the next
daemon start adds it at that default. A file the daemon cannot read or validate
never replaces the limits in force, and canary rules names the problem. A
deleted file comes back as Canary's template at the next daemon start. Every result says where its limits came from:
policy_status names the baseline or your file, and policy carries every
threshold. Agent sessions can read the limits; only you can change them.
Rules 3, 4, 12 and 15 take their thresholds from the classified regime stage,
so the same book can pass in a calm regime and breach in a confirmed one; each
of their rows names the set it used in regime_set. A never-observed stage
uses the calm set, and a stale one is evaluated against both its own threshold
set and the calm set, keeping the worse verdict: old market state may tighten
a rule, never relax it.
The baseline ships as policy rulebook-v5, and every row carries its
observed value, threshold, and an evidence string, so you can check the
arithmetic instead of trusting the verdict. threshold is the limit for the
row's status: the act level on an act row, the watch level otherwise, and the
evidence quotes that same number. Rules with a watch and an act level also
carry both as watch_threshold and act_threshold, and each of their
offenders carries its own status, act or watch, measured against that
offender's own limits (an illiquid issuer's bands, a protection line's tier):
a second issuer between the levels reads watch while the row reads act.
Offenders of the watch-only rules 16 to 18 read watch, and an offender that
could not be measured reads unknown. A rule 1 offender also carries
issuer: the lines it joins, every leg with its loss at the worst price, the
hedges credited or not, and the legs sized at the takeover gap. A reading
exactly at a level is in that level. Three rules read differently: expiry runway counts
down and triggers at its limits (watch at 14 days or fewer, act at 7 or
fewer), index protection is a range whose edges are inside it, and margin
headroom counts down and triggers only strictly below its levels
(margin_headroom_watch_pct, margin_headroom_act_pct). A baseline value is not itself proof that the
threshold has your approval; set the ones you have decided.
Advisory by construction
The rulebook has no path to the broker. Its verdicts never touch submit
eligibility or broker-write authorization, and turning it off with
features.rulebook.enabled=false cannot affect broker-write gating either. An
order preview may carry matching advisory rule_* warnings, but they are
annotations and change nothing about whether it is submittable.
That is deliberate. A hard block on a discipline heuristic fails in the direction nobody wants: it stops a correct trade at the worst moment, and it teaches you to route around it. The rules are stated so you can disagree with one in a specific case and still see the flag.
A rule that cannot see does not pass
A rule that cannot get clean data reports that it could not evaluate. It never passes.
When a required input is missing, the affected row reports unknown and names
the missing input rather than quietly returning a clean result. Partial data
may identify a breach but never clear one: where a
provable minimum alone breaches a cap, the breach is reported as a disclosed
lower bound; where it does not, the row degrades to unknown instead of
passing on incomplete arithmetic.
Row outcomes are pass, info, watch, act, unknown, and
not_evaluated. The last two differ. unknown means the rule applies but its
inputs are not trustworthy: an unresolved earnings date, a missing delta, an
absent currency report. not_evaluated means the rule does not apply right
now, as with the tape rules outside the US regular session, the hedge rule
with no long book, the premium budget with no long option, or the earnings
rules when every held name is a security
that has no issuer earnings by nature — an index, future, fund, bond, bill,
cash, or commodity position is disclosed as exempt rather than left unknown.
Neither is a pass, and the summary line counts them
separately from passes for that reason.
Read input_health before you count passes. It is the result-level gate, with
one row each for account, positions, earnings, regime stage, and tape.
Alerts first
Rows in alert mode come first, followed by track, then off. Within each
mode they are ranked act, watch, unknown, info, not_evaluated,
pass. Ties break on base-currency impact, then rule number.
Plain canary rules shows breaches and hides passes. --all prints the full
checklist, --symbol narrows offender lists to one underlying, and --json
returns the ranking and input health alongside the rows.
What a clean run means
It means nineteen specific checks did not fire on the book as the daemon last saw it. That is all.
A clean rulebook run is not permission to trade and carries no submit authority. It says nothing about whether the thesis holds, or whether these are the right rules for your account. Every submission stays a transaction-specific human decision behind the separate controls described in Trading policy.
What history is kept
A transition is recorded when a row's status changes, not on every evaluation, so the timeline reads as a sequence of events rather than a log of minutes.
canary rules history
canary rules history --rule single_name_exposure --since 2026-01-01 --json
The window defaults to the last 7 days and returns 50 rows newest first, up to
500 with --limit; --until closes it. Each row carries the transition, the
evidence string at the time, and the policy identity behind it, so a verdict
from an older policy version is not read as a current one. Evidence strings
are free text for display and are never parsed back into authority.