Documentation
¶
Overview ¶
Package config loads and validates operator-owned TOML configuration for gateway identity, daemon behavior, and capability enablement.
A missing file or absent gateway field leaves that dimension discoverable; an explicitly configured value is binding. Runtime platform preferences are separate daemon.db state and are not read or written by this package.
Index ¶
- Constants
- func DefaultPath() string
- func SPXMembersAutoRefreshFromEnv() (enabled bool, forced bool)
- type AutoTrade
- func (a AutoTrade) FastPathEnabledResolved() bool
- func (a AutoTrade) HotReloadEnabled() bool
- func (a AutoTrade) ProposalCadenceDuration() time.Duration
- func (a AutoTrade) ProposalsEnabledResolved() bool
- func (a AutoTrade) ReloadIntervalDuration() time.Duration
- func (a AutoTrade) WithDefaults() AutoTrade
- type Config
- type Daemon
- type Flex
- type Gateway
- type Opportunities
- type Resolved
- type Rulebook
- type SPX
- type Scan
- type Trading
Constants ¶
const ( TradingModeDisabled = "disabled" TradingModePaper = "paper" TradingModeLive = "live" )
Supported local trading modes.
Variables ¶
This section is empty.
Functions ¶
func DefaultPath ¶
func DefaultPath() string
DefaultPath returns the canonical config path for the current user.
func SPXMembersAutoRefreshFromEnv ¶
SPXMembersAutoRefreshFromEnv resolves CANARY_SPX_MEMBERS_AUTO_REFRESH as a bidirectional override of the [spx] members_auto_refresh TOML field:
- "1" → returns (true, true): explicit force-on.
- "0" → returns (false, true): explicit force-off.
- unset / other → returns (false, false): defer to TOML. Garbage values are silently ignored rather than rejected; env-var typos are a CI friction we'd rather not fail-loud on, and there's no realistic compliance posture that wants "fail when the env is present but malformed."
The second return ("forced") distinguishes "env actively overrode the TOML" from "env unset, TOML governs." The status renderer uses this to pick the "disabled (env)" vs "disabled (config)" suffix.
Lives next to the SPX type so the precedence rules don't have to be re-derived at every call site.
Types ¶
type AutoTrade ¶
type AutoTrade struct {
// 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.
ProposalsEnabled *bool `toml:"proposals_enabled"`
// PolicyFile points to the local protection-policy TOML; default ~/.config/ibkr/policies/protection-policy.toml.
PolicyFile string `toml:"policy_file"`
// HotReload controls whether policy changes are reloaded while the daemon runs; default true.
HotReload *bool `toml:"hot_reload"`
// ReloadInterval controls how often the daemon checks policy-file changes; default 30s.
ReloadInterval duration `toml:"reload_interval"`
// ProposalCadence controls how often the daemon refreshes protection proposals; default 30s.
ProposalCadence duration `toml:"proposal_cadence"`
// FastPathEnabled allows manual proposal preview/submit to use the immediate
// revalidation path; default true so paper protection stops remain usable.
// Trading write gates still own broker-submit authority.
FastPathEnabled *bool `toml:"fast_path_enabled"`
}
AutoTrade configures advisory protection-proposal production and policy reloads. Despite the historical section name, these fields do not authorize automatic broker submission.
func (AutoTrade) FastPathEnabledResolved ¶
FastPathEnabledResolved reports whether manual proposal actions may use the immediate revalidation path; absence defaults to enabled.
func (AutoTrade) HotReloadEnabled ¶
HotReloadEnabled reports the effective protection-policy reload toggle; absence defaults to enabled.
func (AutoTrade) ProposalCadenceDuration ¶
ProposalCadenceDuration returns the effective advisory-proposal refresh cadence.
func (AutoTrade) ProposalsEnabledResolved ¶
ProposalsEnabledResolved reports the effective advisory-proposal toggle; absence defaults to enabled.
func (AutoTrade) ReloadIntervalDuration ¶
ReloadIntervalDuration returns the effective protection-policy reload interval.
func (AutoTrade) WithDefaults ¶
WithDefaults returns the protection-proposal configuration with missing operational values resolved. It does not enable broker submission.
type Config ¶
type Config struct {
Gateway Gateway `toml:"gateway"`
Daemon Daemon `toml:"daemon"`
Trading Trading `toml:"trading"`
Rulebook Rulebook `toml:"rulebook"`
AutoTrade AutoTrade `toml:"auto_trade"`
Opportunities Opportunities `toml:"opportunities"`
Flex Flex `toml:"flex"`
SPX SPX `toml:"spx"`
Scans map[string]Scan `toml:"scans"`
}
Config is the on-disk shape of ~/.config/ibkr/config.toml.
type Daemon ¶
type Daemon struct {
// 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`.
IdleTimeout duration `toml:"idle_timeout"`
// LogLevel is the daemon's log verbosity — one of "debug", "info" (default), "warn", or "error".
LogLevel string `toml:"log_level"`
}
Daemon holds runtime knobs for the daemon process.
func (*Daemon) SetIdleTimeout ¶
SetIdleTimeout overrides the daemon's idle timeout. Used by --foreground (set 0 to disable idle-shutdown) and by tests that want a fast-firing idle watcher; the underlying field type is unexported so callers outside this package cannot construct it directly.
type Flex ¶
type Flex struct {
// Enabled turns the daily Flex statement fetch on; default false.
Enabled bool `toml:"enabled"`
// QueryID is the IBKR Flex query id to fetch (create the query in
// Account Management with cash transactions, transfers, and equity
// summary sections); required when enabled.
QueryID string `toml:"query_id"`
// TokenPath points to a file holding only the Flex Web Service token;
// default ~/.config/ibkr/flex-token (mode 0600). The token itself never
// belongs in config.toml, and no surface ever echoes it.
TokenPath string `toml:"token_path"`
}
Flex configures daily IBKR Flex statement ingestion for post-trade reconciliation (internal-docs/design/post-trade-truth.md). Read-only toward the broker: statements feed the recon report; nothing here can touch order entry.
func (Flex) WithDefaults ¶
WithDefaults returns the Flex configuration with its default token path.
type Gateway ¶
type Gateway struct {
// 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.
Host string `toml:"host"`
// 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.
Port *int `toml:"port"`
// 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.
ClientID *int `toml:"client_id"`
// BreadthClientID is the IBKR clientID used by the dedicated
// historical-bar connector that backs the SPX breadth refresh.
// Default 16 (one above the primary's default 15). Pinned to its
// own connection so breadth's 503-name fan-out runs against a
// separate 40-msg/sec and 60-historical/10-min rate-limit budget
// rather than competing with interactive RPCs and the gamma
// option-leg fan-out on the primary client. Collisions are treated
// as stale-client/operator issues, not silently shifted to another
// role's reserved ID.
BreadthClientID *int `toml:"breadth_client_id"`
// 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.
Account string `toml:"account"`
// 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.
TLS *bool `toml:"tls"`
}
Gateway holds the four pinnable connection knobs. Pointer fields distinguish "user wrote this value" (binding) from "field absent" (auto).
Host is plain string because "" and "127.0.0.1" carry the same meaning: auto-discovery only probes loopback. A non-loopback host implies "I know where my gateway is" and is treated as pinned.
Account is plain string because empty already means "auto-detect via managedAccounts" in the SDK.
func (Gateway) BreadthClientIDOrDefault ¶
BreadthClientIDOrDefault returns the clientID for the bulk-historical breadth connector. Default 16 — one above the primary default — so a fresh install gets two non-colliding role-owned IDs without any config tweak.
func (Gateway) ClientIDOrDefault ¶
ClientIDOrDefault returns ClientID if pinned, else 15.
func (Gateway) HostOrDefault ¶
HostOrDefault returns Host if set, else 127.0.0.1.
func (Gateway) PortOrZero ¶
PortOrZero returns Port (dereferenced) or 0 if unset. Callers should check PortPinned first; the zero is a sentinel for "discover."
func (Gateway) PortPinned ¶
PortPinned reports whether the user pinned a port. Discovery skips the port-probe step when true and uses Port directly.
func (Gateway) TLSOrFalse ¶
TLSOrFalse returns TLS (dereferenced) or false if unset. Callers should check TLSPinned first; the false is a sentinel meaning "auto, try plain first" — distinct from a binding tls=false.
type Opportunities ¶
type Opportunities struct {
// 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.
Enabled *bool `toml:"enabled"`
// PolicyFile points to the local opportunity-policy TOML; default ~/.config/ibkr/policies/opportunity-policy.toml.
PolicyFile string `toml:"policy_file"`
// RefreshCadence controls how often the daemon refreshes opportunities; default 2m.
RefreshCadence duration `toml:"refresh_cadence"`
// HotReload controls whether opportunity policy changes are reloaded while the daemon runs; default true.
HotReload *bool `toml:"hot_reload"`
// ReloadInterval controls how often the daemon checks the opportunity policy file for changes; default 30s.
ReloadInterval duration `toml:"reload_interval"`
}
Opportunities configures advisory opportunity production and policy reloads. Broker submission remains subject to the independent trading path.
func (Opportunities) EnabledResolved ¶
func (o Opportunities) EnabledResolved() bool
EnabledResolved reports the effective advisory-opportunity toggle; absence defaults to enabled.
func (Opportunities) HotReloadEnabled ¶
func (o Opportunities) HotReloadEnabled() bool
HotReloadEnabled reports the effective opportunity-policy reload toggle; absence defaults to enabled.
func (Opportunities) RefreshCadenceDuration ¶
func (o Opportunities) RefreshCadenceDuration() time.Duration
RefreshCadenceDuration returns the effective advisory-opportunity refresh cadence.
func (Opportunities) ReloadIntervalDuration ¶
func (o Opportunities) ReloadIntervalDuration() time.Duration
ReloadIntervalDuration returns the effective opportunity-policy reload interval.
func (Opportunities) WithDefaults ¶
func (o Opportunities) WithDefaults() Opportunities
WithDefaults returns the opportunity configuration with missing operational values resolved. It does not enable broker submission.
type Resolved ¶
type Resolved struct {
Gateway Gateway
Daemon Daemon
Trading Trading
Rulebook Rulebook
AutoTrade AutoTrade
Opportunities Opportunities
Flex Flex
SPX SPX
Scans map[string]Scan
}
Resolved is the validated, defaults-applied view a daemon actually uses. Gateway carries the raw (pointer-fielded) user input; discovery happens later in internal/discover and produces concrete values.
type Rulebook ¶
type Rulebook struct {
// TerminalEvidenceFile points to an optional JSON document of reviewed,
// exact-contract terminal/non-reporting issuer evidence for rules 6-8. An
// empty path leaves the retained daemon.db authority unchanged.
TerminalEvidenceFile string `toml:"terminal_evidence_file"`
}
Rulebook configures operator-owned evidence inputs for the advisory trading rulebook. The import file is not read on snapshot paths: daemon startup validates and transactionally publishes it into daemon.db, which remains the live authority.
type SPX ¶
type SPX struct {
// 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).
//
// Pointer type lets the daemon distinguish an explicit `members_auto_refresh = true` from "field absent" — both enable the refresher today, but a future "user opted in" vs "default behaviour" distinction stays additive.
MembersAutoRefresh *bool `toml:"members_auto_refresh"`
}
SPX holds the SPX-related daemon knobs. Currently just the members auto-refresh toggle; grouping under [spx] gives future SPX-scoped configs (e.g. fetcher concurrency, sweep tunables) a natural home without proliferating top-level TOML sections.
When MembersAutoRefresh is true (default) the daemon fetches Wikipedia's constituent list daily at 02:30 ET plus on startup if the cached file is stale; when false it loads whatever is on disk (or the binary's embedded fallback) and never reaches out.
Use case for pinning off: regulated traders running reproducibility audits, air-gapped boxes, anyone debugging breadth drift. The CANARY_SPX_MEMBERS_AUTO_REFRESH env var overrides this field at runtime: "1" force-enables, "0" force-disables, anything else (including unset) defers to the TOML value. Symmetric semantics — the env is a bidirectional override, not a one-way kill switch.
func (SPX) MembersAutoRefreshEnabled ¶
MembersAutoRefreshEnabled returns the resolved value of [spx] members_auto_refresh. Defaults to true when the field is absent — the refresher is opt-out, not opt-in.
type Scan ¶
type Scan struct {
// Type is the IBKR scanner code, such as TOP_PERC_GAIN; dump your gateway's catalog with `canary scan params`.
Type string `toml:"type"`
// Exchange is the IBKR scanner locationCode, such as STK.US.MAJOR or STK.NASDAQ.
Exchange string `toml:"exchange"`
// Instrument is the IBKR scanner instrument token, such as STK for US stocks or STOCK.EU for European stocks; empty defaults to STK.
Instrument string `toml:"instrument"`
// Limit caps returned rows for this preset.
Limit int `toml:"limit"`
// Timeout is the per-preset scan timeout; <=0 falls back to the daemon default (20s).
Timeout duration `toml:"timeout"`
}
Scan holds a single scanner preset. Timeout is per-preset and optional; <=0 falls back to the daemon's default (20s).
type Trading ¶
type Trading struct {
// Mode selects the local order-entry state: "disabled" (default), "paper", or "live".
Mode string `toml:"mode"`
// MaxNotional caps every equity/ETF order before broker WhatIf; apparent close/reduce orders are not exempt because this client cannot prove that a manual TWS order has not already consumed the exit capacity. Default 10000 in account currency.
MaxNotional float64 `toml:"max_notional"`
// MaxOptionContracts caps every single-leg option order; apparent close/reduce orders are not exempt because account-global working-order authority is incomplete. Default 5.
MaxOptionContracts int `toml:"max_option_contracts"`
// AllowStockShort permits stock short/opening flip previews when true. Default false.
AllowStockShort bool `toml:"allow_stock_short"`
// AllowOptionSellToOpen permits option sell-to-open previews when true. Default false.
AllowOptionSellToOpen bool `toml:"allow_option_sell_to_open"`
// PaperSmokeMaxAge is the freshness window for the paper-smoke evidence reported in trading status. The smoke is informational at runtime and enforced by the release pipeline; it does not gate live enablement. Defaults to 168h.
PaperSmokeMaxAge duration `toml:"paper_smoke_max_age"`
}
Trading holds local order-entry gates for experimental trading builds. Stable ibkr releases are read-only; a missing [trading] section resolves to mode="disabled". Treat active trading config as an explicit, as-is operator override. TWS / Gateway broker permissions remain the final authority even after these local gates pass.
func (Trading) OrderEntryEnabled ¶
OrderEntryEnabled reports whether the configured trading mode can progress beyond read-only status/preview diagnostics.
func (Trading) PaperSmokeMaxAgeDuration ¶
PaperSmokeMaxAgeDuration returns the resolved paper-smoke freshness window.
func (Trading) WithDefaults ¶
WithDefaults returns t with default values applied without granting trading.