GatedChild

class GatedChild(strategyId: String, inner: DslCompiledStrategy, hold: Boolean, gateFor: (String) -> Boolean, flattenSymbols: List<String>) : DslCompiledStrategy, PerStreamWarmable

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.

Constructors

Link copied to clipboard
constructor(strategyId: String, inner: DslCompiledStrategy, hold: Boolean, gateFor: (String) -> Boolean, flattenSymbols: List<String>)

Properties

Link copied to clipboard
open override val declaredStreams: Map<String, HubKey>

Stream alias → underlying (broker, symbol, timeframe) declared in the strategy file.

Link copied to clipboard
open override val markSymbols: Set<String>

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.

Link copied to clipboard

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.

Link copied to clipboard
open override val optionMarkSymbols: Set<String>

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).

Link copied to clipboard
open override val orderIds: SequentialIdGenerator?

The generator of the strategy's own order ids, or null when it mints none; a restart resumes it.

Link copied to clipboard
open override val pendingStacks: PendingStacks

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.

Link copied to clipboard

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.

Link copied to clipboard
open override val quoteFieldStreams: Set<String>

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.

Link copied to clipboard
open override val retentionByKey: Map<HubKey, Int>

Per-key history retention required by the strategy's indicators.

Link copied to clipboard
open override val usesBookSizing: Boolean

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.

Link copied to clipboard
open override val volumeRequiringSymbols: Set<String>

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

Link copied to clipboard
open override fun bindSchedules(runner: ScheduleRunner, ctx: StrategyContext, nowMs: Long, emit: (Signal) -> Unit)

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).

Link copied to clipboard
open override fun bindStatePersistor(strategyId: String, persistor: StatePersistor)

Bind optional durable state for DSL runtime features that need restart recovery.

Link copied to clipboard
open override fun bindToHub(hub: CandleHub, ctx: StrategyContext, emit: (Signal) -> Unit)

Subscribes this strategy to the shared CandleHub for hub-driven dispatch.

Link copied to clipboard
open override fun clearRuleEdges()

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.

Link copied to clipboard
open override fun executeExitHook(ref: ExitHookRef, exit: ExitContext, timestampMs: Long): List<Signal>

Execute one validated exit hook against the strategy's latest evaluation state.

Link copied to clipboard
open override fun exitHookReferences(): Map<String, ExitHookRef>

Compiled exit-hook identities available for durable binding validation.

Link copied to clipboard
open override fun observeCandleEvaluations(observer: (alias: String, key: HubKey, candle: Candle, rulesEvaluated: Int) -> Unit)

Observe each live closed candle after its alias has completed rule evaluation.

Link copied to clipboard
open override fun observeRuleDecisions(observer: (RuleDecisionAudit) -> Unit)

Observe rule edges before their produced signals enter the trading pipeline.

Link copied to clipboard
open override fun onCandle(candle: Candle, ctx: StrategyContext, emit: (Signal) -> Unit)

Called when a closed candle is published. Default no-op.

Link copied to clipboard
open override fun onExitOrderUnfilled(clientOrderId: String): ExitRetry?

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.

Link copied to clipboard
open override fun onOrderFilled(clientOrderId: String)

Order clientOrderId filled in full.

Link copied to clipboard
open override fun onOrderRejected(clientOrderId: String)

Re-arm the rule edge that produced a rejected order, if this strategy owns it.

Link copied to clipboard
open override fun onOrderSubmitted(signal: Signal, clientOrderId: String): DecisionOrderLink?

Associate an emitted signal with the client order id assigned by the pipeline.

Link copied to clipboard
open override fun onOrderTerminal(clientOrderId: String)

Forget rule ownership after an order reaches a non-rejected terminal state.

Link copied to clipboard
open override fun onPositionStateChanged(symbol: String, nowHeld: Boolean, atMs: Long)

The strategy's position on symbol flipped between flat and held (nowHeld) at venue time atMs.

Link copied to clipboard
open override fun onTick(tick: Tick, ctx: StrategyContext, emit: (Signal) -> Unit)

Called for every published tick. Emit signals via emit — never block.

Link copied to clipboard
open override fun resumeOrderIds(usedIds: Collection<String>)

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.