Skip to content

DSL reference

The qkt strategy language, explained one construct at a time. Each page covers a single concept — what it does, every variant the parser accepts, examples for each, and what it pairs with.

If you want the one-page cheat sheet, see DSL grammar (one-pager). If you want to learn it properly, start at the top of this page and work down.

Structure of a strategy file

  • The STRATEGY block


    The outer envelope: STRATEGY name VERSION n, the SYMBOLS / RULES sections, what's required and what's optional.

    STRATEGY block

  • Streams: SYMBOLS


    Declaring which markets your strategy listens to. Broker prefixes, symbols, timeframes, multiple streams.

    Streams

  • Synthetic series


    Read-only engine state as candle streams, starting with account equity for indicator-based meta-risk filters.

    Synthetic series

  • Option chain analytics


    Implied volatility and 25-delta skew of a stored option chain, at any tenor, as read-only streams.

    Chain analytics

  • Option structures


    Multi-leg option positions chosen from the chain by delta and days to expiry, margined and unwound as one.

    Option structures

  • LET and DEFAULTS


    Naming values so you can reuse them. The two ways: LET (per-strategy aliases) and DEFAULTS (action defaults).

    LET / DEFAULTS

Conditions — when to act

  • The WHEN clause


    The "if" half of every rule. Edge-triggered vs level-triggered, combining conditions with AND/OR/NOT.

    WHEN

  • Indicators


    Every indicator the parser knows — ema, sma, rsi, atr, vwap, macd, bollinger, donchian (highest/lowest), and the math helpers.

    Indicators

  • Expressions


    Arithmetic, comparisons, account references (account.equity), position references (POSITION.stream).

    Expressions

  • SEQUENCE


    Ordered multi-stage setups with per-stage timeouts, snapshots, and a one-pass completion edge.

    SEQUENCE

Actions — what to do

  • BUY / SELL / CLOSE / CANCEL / LOG


    The action verbs. What each does, what they accept, how to combine them.

    Actions

  • SIZING


    Every way to size a position: fixed lots, percent of equity, fixed USD, risk-based, full-position close.

    SIZING

  • :material-bracket-arrow-down:{ .lg .middle } BRACKET


    Atomic stop-loss + take-profit groups. Fixed prices, percent offsets, ATR-based, scale-out targets.

    BRACKET

  • STACK pyramiding


    Layered entries — one signal becomes N price-triggered orders. Time fences, custom per-layer sizing.

    STACK

  • STACK_AT conditional stacks


    Fire independent micro-trades when the primary leg's MFE crosses thresholds within time windows. Each stack tracks as its own leg with its own bracket.

    STACK_AT

  • TIMES repeated entries


    Emit one entry N times in a single evaluation, each its own ticket and bracket. The count is an expression, so it can follow conviction, volatility, or the account balance.

    TIMES

  • EXIT AFTER timed exits


    Close an entry a fixed time after it fills, checked on every tick rather than at bar close. Applies to its STACK_AT legs too.

    EXIT AFTER

  • OTO one-triggers-other


    Place child orders only when a parent fills (ON_FILL). Children can be a different symbol, the opposite side, and priced relative to the parent fill via entry — legged hedges, scale-ins, reversals.

    OTO

Looping and composition

  • FOR EACH


    Apply the same rule body to multiple streams. AST-level expansion at compile time.

    FOR EACH

  • PORTFOLIO files


    Composing N strategies into a portfolio with regime-gated activation. IMPORT, RUN, HOLD.

    PORTFOLIO

  • BASKET synthetic instruments


    Bind several streams into one tradeable pseudo-stream. An equal-weight log-return index you can read, and BUY/SELL/CLOSE that fan out to one equal-notional order per constituent.

    BASKET

How qkt parses your strategy

When you run qkt parse strategy.qkt, the compiler walks the file in this order:

  1. Header — STRATEGY name VERSION n or PORTFOLIO ...
  2. DEFAULTS (optional) — captures default values for all later actions
  3. SYMBOLS — declares every stream the strategy listens to
  4. PARAM (optional) — number, boolean or string strategy inputs and their portfolio overrides
  5. LET (optional) — name-bound expressions for reuse
  6. SCHEDULE (optional) — clock-driven actions
  7. SEQUENCE (optional) — ordered setup state machines
  8. RULES — pairs of WHEN <condition> THEN <action>
  9. FOR EACH (optional, inside RULES, interleaved with WHEN rules) — macro expansion that emits one rule per listed stream

qkt parse then compiles the file, so an unknown indicator, function, stream alias or reference is reported too — the same diagnostics the language server shows in an editor. Errors are line/column tagged. A typo in WHEN or a missing THEN produces a clear error pointing to the line, not a cryptic stack trace.

STRATEGY typed_params VERSION 1
SYMBOLS
    btc = BACKTEST:BTCUSDT EVERY 1m
PARAM threshold = -0.5          -- number; a leading minus is part of the literal
PARAM armed = TRUE              -- boolean
PARAM label = "breakout"        -- string
RULES
    WHEN armed AND btc.close - btc.open > threshold
    THEN LOG "signal" kind=label

Quick legal/illegal

-- legal: minimum valid strategy
STRATEGY hello VERSION 1
SYMBOLS
    btc = BACKTEST:BTCUSDT EVERY 1m
RULES
    WHEN btc.close > 0
    THEN LOG "tick received"
-- illegal: SYMBOLS must come before RULES
STRATEGY hello VERSION 1
RULES
    WHEN btc.close > 0 THEN BUY btc
SYMBOLS
    btc = BACKTEST:BTCUSDT EVERY 1m
-- parse error: SYMBOLS must come before RULES (line 5)
-- illegal: missing VERSION
STRATEGY hello
SYMBOLS ...
-- parse error: expected VERSION, got 'SYMBOLS' (line 2)

The parser is strict by design. A strategy file that compiles is one where the engine knows exactly what to do — there's no "interpret loosely and hope" mode.

See also

  • Examples — every DSL feature used in a real strategy
  • Recipes — task-oriented walkthroughs
  • CLI commands — qkt parse, qkt backtest, etc.