Equities and reconciliation
The backtest corporate-action stack is implemented: splits/reverse splits, cash and total-return dividends, renames, cash/stock/mixed mergers and delisting. Since GLE-328 (GLE-228 Decision 5a) the engine is a consumer of the price view: marketfeed serves an eq:V:T:adj=split or adj=splitdiv symbol adjusted, anchored at the run end, with the raw prices and the cumulative_price_ratio on every bar, and the engine builds no price schedule for a backtest. The bar loop keeps two frames of each served bar. The strategy receives the bar as served, so its indicators run in the adjusted view. The fill simulator, the corporate-action firing passes and the report recorder receive its raw projection: the raw prices promoted to OHLC, a settle divided by the ratio, the path constituents projected the same way and the adjustment fields cleared. Fills are therefore at historical prices. An order placed in the adjusted view has its limit, stop and trailing levels divided by the symbol’s latest served ratio (attached orders by their own symbol’s); a fill is multiplied back by the ratio of the bar it filled in, where the instant belongs to the bar that closes at it, which covers a next-open fill, a path fill and a market-on-close fill delivered with the next bar’s events. A bar without the raw view passes through both frames unchanged, so a raw equity or futures run is byte-identical to before.
Corporate-action accounting runs for every eq symbol, raw or adjusted. The records are fetched on the run symbol as given (marketfeed serves the same ledger for every price view, stamped with the base symbol) and re-keyed with the run symbol’s qualifier suffix, so a rename or merger relocates a position onto eq:V:NEW:adj=split when the run named eq:V:OLD:adj=split; one event builder, equity.RawEventManifest, folds them into the manifest the firing passes read, and the run security master is built over the pooled records. A split rewrites the held quantity and a dividend is credited whatever the view; under adj=splitdiv the feed has already folded the dividend into the prices, and the CORPORATE_ACTIONS stream is accounting only. The manifest’s source checksum is over the re-keyed records, so a qualified run (adj=raw, adj=split) carries its own per-view checksum. --auto-lineage follows each equity series’ forward rename chain, and a discovered successor inherits the head’s qualifier suffix, interval and session. Stable identity anchors preserve position accounting across ticker changes and reuse; whole-unit changes require an integral result or cash-in-lieu treatment. A declared eq: reference series is served as is and takes no accounting.
The gates are keyed on the symbol’s class, not on a configured registry: an adjusted equity reads its bars and its corporate actions on the protobuf wire only, so it forces pb in auto negotiation (and the DBN demotion has an adjusted-equity clause for a benchmark sleeve), while a raw equity prefers pb with a fallback to a best-effort run without its records. The bars a feed serves must agree with the class: an adjusted symbol whose bars lack is_adjusted, or a raw symbol whose bars carry it, is refused before the first bar, naming the offending close; so the file-csv adapter, which serves raw bars only (its optional ledger answers a qualified request with the base symbol’s rows), cannot run an adj=split symbol. Every BARS request of an adjusted symbol carries adjust_anchor = the run end, and the series cache keys on it. The config keys adjustment-mode and dividend-treatment are refused for one release with a message naming eq:<VENUE>:<TICKER>:adj=split or adj=splitdiv; there is no reinvested treatment left to configure.
Strategies can opt into raw/adjusted prices and CorporateActionObserver notices. The AdjustmentFactorSource adapter contract exists, but the engine consumes no factor feed (GLE-228 Decision 8): the view is the feed’s and the accounting is event-driven.
The IBKR venue is exercised through the deterministic emulator in cmd/tools/ibkr-emulator. Its HTTP endpoints implement account selection, positions, account state, order submission/cancellation, open orders and fills, plus admin clock/fixture control. Its cancel endpoint answers IBKR’s documented bodies, on IBKR’s singular path and on the plural one it served before (Tickets and cancels at the IBKR venue), and its replyWarnings fixture raises IBKR’s order reply messages for tickets at or above a quantity or value threshold, one reply or a chain, so the adapter’s reply policy runs against it (Order reply messages). internal/ibkrclient and emulator handler tests are the maintained endpoint contract.
The ledger persists canonical order identity before submission, under a persisted deployment namespace since GLE-373: every reference is <label>-<nonce>-<n>, the order line carries the complete frame, every execution report is validated against the order it names and quarantined when it fails, and adopted state carries the owner (The order ledger). Startup matches the ledger to venue orders and positions, refuses unexplained orders under the supported exit orphan policy, and sends adopted state before warmup. Continuous reconciliation polls in-flight and open orders and records their fills through the same execution gate, keyed on the venue’s execution id. Each GTC order’s line also records its venue deadline, gtc_deadline, from which the loop reports the venue’s quarter-end cancellation as GTC_EXPIRED (see The venue seam and the current live path); AdoptedOrder carries no deadline.
Live mode currently requires the emulator, one series and bar resolution. Splits/reverse splits are supported; other corporate-action types, multiple actions sharing a symbol/ex-date, and run-start-boundary actions are refused. Live mode is the one place the engine still adjusts prices (GLE-228 Decision 7, kept by GLE-328): the feed’s served view re-anchors as its ledger grows, so a live run on an adjusted symbol builds its own forward-adjust schedule (equity.Build, anchored at the run start, mode split_adjusted for adj=split and split_dividend_adjusted for adj=splitdiv) and applies it to the raw projection of each served bar, warm-up included; an adj=splitdiv live run is refused by liveCASupported whenever a dividend falls in the window. The live and backtest paths agree bar for bar on a split: the feed’s end-anchored view and the engine’s most-recent-segment schedule both put every bar in the post-split basis. Real-time non-emulated feeds, tick/path fills, bracket children, IOC/FOK, unspecified TIF and --limit-fill through are outside the admitted live surface. Synthetic reconciliation fills, orphan claim/ignore, average-price/P&L tolerance policies and automatic alignment remain unfinished. See liveRunSupported, liveCASupported, runStartCADeferred, engine/recon, and engine/liverun_*_test.go.