Gated Child
Wraps a portfolio child strategy in backtest so its behaviour matches a live com.qkt.cli.daemon.portfolio.PortfolioSupervisor:
When the portfolio gate is active the inner strategy sees ticks and candles normally.
When the gate transitions from active to inactive and hold is false, the wrapper emits market orders that flatten every traded symbol, and ends its option structures, before the strategy is paused.
When hold is true the strategy keeps running (so it can manage existing positions with exits) but the pipeline's gateFor still suppresses new risk-increasing entries.
Implements DslCompiledStrategy by delegation so every runtime facility that detects the DSL interface (CandleHub binding, warmup seeding, order-lifecycle callbacks, schedules) sees through the wrapper to the child. Without this the engine treats a wrapped child as a hand-written strategy and drives it via the legacy no-hub onCandle path, where cross-stream reads evaluate Undefined — a child whose WHEN references two streams then silently never trades. Signal gating for the hub-bound path is enforced by the pipeline's gateFor (see TradingPipeline), so the overrides below only add the flatten-on-deactivate transition and the legacy-path gating.
Properties
Stream alias → underlying (broker, symbol, timeframe) declared in the strategy file.
Symbols whose mark or index (<alias>.mark, .index) the strategy reads. The runtime verifies its data source serves their marks (com.qkt.marketdata.source.MarketSource.marksFor) before it goes live.
Symbols on which this strategy will create more than one concurrent leg via STACK_AT. The runtime verifies that the routing broker for each such symbol declares com.qkt.broker.OrderTypeCapability.MULTI_POSITION_PER_SYMBOL before the strategy goes live. Empty for strategies with no STACK_AT clauses.
Symbols whose option mark IV or Greeks (<alias>.iv, .delta, ...) the strategy reads. The runtime verifies each is a catalogued option its data source serves marks of (com.qkt.marketdata.source.MarketSource.optionMarksFor).
The generator of the strategy's own order ids, or null when it mints none; a restart resumes it.
Per-strategy stack registry. The action compiler populates this when a STACK_AT-bearing BUY/SELL emits its primary submit; the runtime consumes it on the matching com.qkt.events.BrokerEvent.OrderFilled. Strategies with no STACK_AT clauses have an empty registry that's never written to.
Warmup seeding keys off com.qkt.strategy.PerStreamWarmable, which the compiled child implements but the DslCompiledStrategy interface does not — so class delegation alone left every portfolio child unseeded in backtests while the daemon seeds each one. Pass the child's own requirements through so a PORTFOLIO backtest warms exactly like a live deploy.
Stream aliases whose conditions read quote fields (bid/ask/spread). These evaluate Undefined unless the data source carries real quotes — bar-synthesized backtest feeds do not, so spread-aware rules silently never fire there. The backtest engine warns loudly when this is non-empty.
Per-key history retention required by the strategy's indicators.
True when any action sizes with RISK … OF BOOK. The runtime verifies a portfolio book is bound before the strategy goes live — a standalone deploy has no book, and failing at deploy beats erroring on the first signal. False for every other sizing.
Symbols bound to a volume-weighted indicator (VWAP/OBV). The runtime verifies the data source for each declares com.qkt.marketdata.source.MarketSourceCapability.VOLUME before the strategy goes live — a volume indicator on a quote-only feed (MT5 FX/metals) otherwise never becomes ready and the strategy silently never fires. Empty when no such indicator is used.
Functions
Register every SCHEDULE clause this strategy declared with runner. Called after bindToHub. Strategies with no SCHEDULE block have nothing to register and the default implementation is a no-op (#77).
Bind optional durable state for DSL runtime features that need restart recovery.
Clear every rule edge so the next start evaluates entries like a fresh deployment. Called when an operator stop flattened this strategy's positions: a persisted edge would otherwise still say "already fired", and a rule gated on being flat (for example POSITION.x = 0) never sees another false-to-true transition, so the restarted strategy never enters again.
Execute one validated exit hook against the strategy's latest evaluation state.
Compiled exit-hook identities available for durable binding validation.
Observe rule edges before their produced signals enter the trading pipeline.
A market exit this strategy's rule sent ended at the venue cancelled or rejected without filling in full: re-arm that rule so it sends what is still held again on its next bar (#1359). Null when clientOrderId was no rule's exit, or nothing is held any more.
Order clientOrderId filled in full.
Re-arm the rule edge that produced a rejected order, if this strategy owns it.
Associate an emitted signal with the client order id assigned by the pipeline.
Forget rule ownership after an order reaches a non-rejected terminal state.
The strategy's position on symbol flipped between flat and held (nowHeld) at venue time atMs.
Continue the strategy's order-id sequence past usedIds, the ids of orders and legs a restarted session restored. Without this a restart mints dsl-<name>--0 again, which a restored non-terminal order of the same id swallows as a duplicate submit.