Appearance

Personalize your experience

Mode
Accent Color
Direction
Strategy DSL — Language Reference

Strategy DSL — Language Reference

Reference

The strategy JSON the C++ engine executes: every top-level block, signals and flow, operands and the 94-indicator catalog, the eleven operators, and the errors and limits the parser enforces.

What the DSL is

A is one JSON document describing when to open positions, how they are, and how they close. It is declarative — no loops, or user functions. The engine parses it once, computes every series it references, and steps through the bars.

The form, node and JSON editors in the all produce exactly this document, and the same document runs in backtests, on the engine and in the API. The parser is strict: an unknown indicator, parameter, output, operator or timeframe is an error with the JSON of the mistake and a “did you mean” hint. Unknown fields are warnings. Nothing falls back silently.

A complete document

rsi-bounce.strategy.json
{
  "version": 2,
  "name": "RSI bounce with trend filter",
  "symbol": {
    "exchange": "zerodha", "symbol": "RELIANCE", "segment": "equity", "timeframe": "5m",
    "sessionMode": "intraday", "sessionStart": "09:15", "sessionEnd": "15:15",
    "utcOffsetMinutes": 330
  },
  "quantity": { "mode": "riskBased", "quantity": 1, "capital": 250000, "maxPositions": 1 },
  "costs": { "commissionPerOrder": 20, "slippagePercent": 0.02 },
  "entry": {
    "side": "long",
    "signals": [{
      "id": "bounce",
      "name": "RSI back above 30 above the 1h EMA 50",
      "repetitive": false,
      "cooldownBars": 3,
      "conditions": { "and": [
        { "indicator": "RSI", "params": { "period": 14 }, "operator": "crossesAbove", "value": 30 },
        { "indicator": "Close", "operator": ">", "value": { "indicator": "EMA", "params": { "period": 50 }, "interval": "1h" } },
        { "or": [
          { "indicator": "RelativeVolume", "operator": ">", "value": 1.5 },
          { "not": { "indicator": "ATR", "params": { "period": 14 }, "operator": ">", "value": 25 } }
        ] }
      ] },
      "flow": [
        { "type": "if", "action": "none", "condition": { "indicator": "TimeOfDay", "operator": ">", "value": 1430 } },
        { "type": "else", "action": "entry" }
      ]
    }]
  },
  "exit": {
    "signals": [{ "id": "done", "conditions": { "indicator": "RSI", "operator": ">=", "value": 70 } }],
    "stopLoss":   { "enabled": true, "type": "atr", "value": 1.5, "atrPeriod": 14 },
    "takeProfit": { "enabled": true, "targets": [
      { "type": "riskReward", "value": 1.5, "exitPercent": 50 },
      { "type": "riskReward", "value": 3,   "exitPercent": 50 } ] },
    "maxDailyLossPercent": 2
  }
}

Top-level blocks

FieldTypeDefaultDescription
versionnumber2Document version written by the builder.
name / descriptionstring—Display only.
symbolobject—exchange, symbol, segment, timeframe (1m…1W), sessionMode (continuous | intraday | positional), sessionStart / sessionEnd (HH:MM, intraday square-off), utcOffsetMinutes (330 for NSE, 0 for crypto — clock values and daily levels use it).
quantityobject— ( | percentOfCapital | riskBased | capitalPerPosition), quantity (units, % of equity, or % risked), capital, maxPositions, leverage.
costsobjectnonecommissionPercent (per side, of ), commissionPerOrder (flat per fill), slippagePercent (against you on every fill).
entry*object—side (long | short), instant (open on the first bar), signals, reEntry, + entries (layered entry sets), exitOverride.
exitobject—signals (any closes every position), , takeProfit (one target or several with exitPercent), maxDailyLossPercent.

Signals and flow

FieldTypeDefaultDescription
id*string—Unique within the ; and signal refer to it.
conditions*logic—A condition, or an and / or / not tree.
repetitivebooleantruetrue: acts on every bar the conditions hold. false: only on the first bar of each run of true bars.
cooldownBarsinteger0Bars the signal waits after it acted.
intervaltimeframestrategy timeframeEvaluate the signal on a higher timeframe.
candleType"candles" | "heikinashi"candlesEvaluate on candles ( always use real bars).
flowblock[]noneif / elif / else blocks with condition and action, and switch blocks on an operand with numeric cases and defaultAction. Decides the action once the conditions hold; an may only use entry or none, an exit or none.
enabledbooleantrueDisabled signals are ignored.

Conditions and logic trees

A condition is a left operand, an operator and a - side. Conditions combine with and, or and not; a node has exactly one of them and children may be further nodes. An empty AND is false.

and: [ leaf, { or: [...] }, { not: ... } ]andLogicNodeconditionRSI(14) < 45ConditionNode — a leaforconditionVolume > 1e5conditionATR(14) < 25either satisfies the groupnotconditionClose < EMAexactly one childOne key per nodeexactly one of and / or / not · an empty and is FALSE · an empty or is FALSEa node carrying both and and or is a parse error, with the path of the node
Leaves, groups and negation
OperatorEditor labelRight-hand side
>is abovenumber, bar field or indicator
<is belownumber, bar field or indicator
>=is at or abovenumber, bar field or indicator
<=is at or belownumber, bar field or indicator
==equalsnumber, bar field or indicator
!=does not equalnumber, bar field or indicator
crossesAbovecrosses abovenumber, bar field or indicator
crossesBelowcrosses belownumber, bar field or indicator
crossescrosses (either way)number, bar field or indicator
risingrising for N barsa whole number of bars, 1…100
fallingfalling for N barsa whole number of bars, 1…100
  • crossesAbove is true when the previous bar had left ≤ and this bar has left > right — both are read on both bars, so crossing a moving indicator works. crossesBelow mirrors it; crosses is either.
  • == and != within a relative tolerance of 1e-9 — use them on events, directions and clock values, not on continuous indicators.
  • rising N: the left side increased on each of the last N bars.
  • Any side with no yet (warm-up, offset before the ) makes the condition false.

Operands

FieldTypeDefaultDescription
indicator*string—One of the 94 names (Close, , , BollingerBands, , TimeOfDay, CustomFormula, QuaScript, …). Case must match.
paramsobjectcatalog defaultsChecked against the : type, whole numbers, ranges, enum , and rules across parameters (MACD fast < slow).
outputstringfirst outputWhich series of a multi-output indicator to read.
offsetinteger0Bars ago in the signal’s timeframe.
intervaltimeframesignal timeframeRead the operand on a higher timeframe; only closed bars of that timeframe are used.
right-hand sides
// 1. a number
{ "indicator": "RSI", "operator": "<", "value": 30 }

// 2. a bar field of the signal's own bars: close open high low hl2 hlc3 ohlc4 volume
{ "indicator": "EMA", "params": { "period": 20 }, "operator": "<", "value": "close" }

// 3. another operand — any indicator, output, offset and interval
{ "indicator": "Close", "operator": ">",
  "value": { "indicator": "DonchianChannel", "params": { "period": 20 }, "output": "upper", "offset": 1 } }

// rising / falling take a bar count
{ "indicator": "OBV", "operator": "rising", "value": 3 }

Bar fields as a string are close, open, high, low, hl2, hlc3, ohlc4, volume. The full list of indicators, parameters and output ranges is the ; it is generated from the engine (dslx_cli --catalog).

Errors, warnings and limits

ProblemResult
Unknown indicator, parameter, output, operator, timeframe or bar fieldError at its , with a suggestion
Parameter of the wrong type or out of range; MACD fast ≥ slowError at the parameter (or params)
A condition, AND group or switch case that can never be trueError at the condition or group — see “Conditions That Can Never Be True”
A logic node with both and and or, a signal without conditions, elif without ifError
Duplicate signal idError
Unknown field anywhere; the field is ignored
Comparing unrelated units ( vs a price)
A signal with no conditions, a stop or target with 0, an intraday without sessionEnd
or a riskReward target without a stopRun-time in the result (sized as / target skipped)
LimitValue
depth32
Condition nodes per 2000
Signals per 128
Layered entry sets32
Bars-ago offset0…500
rising / falling bars1…100
Timeframes (signal / operand interval)1m, 3m, 5m, 10m, 15m, 30m, 1h, 2h, 4h, 1D, 1W
★
Pro tip:Validate without : dslx_cli --validate -s strategy.json errors and warnings with paths, and the builder's shows the same messages inline as you type.

See also

Related articles

  • Condition Evaluator

    Automation / Strategy Builder / Reference

    How a condition becomes true on a bar: series computed up front, no value during warm-up, the exact cross and rising rules, and the order of work on each…

  • Step 5 — Entry Signals

    Automation / Strategy Builder / Wizard Steps

    Where the strategy is actually written. Conditions, operators, nesting, order configuration, multiple entry sets, and the re-entry engine behind Grid, DCA…

  • Strategy DSL — Conditions That Can Never Be True

    Coding / Strategy DSL

    Which conditions the engine and the editors reject because no bar could ever satisfy them, how the check works, what it deliberately does not reject, and…

  • Strategy DSL — Execution Model

    Coding / Strategy DSL

    What the engine does on every bar: protective exits, exit signals, entries, layers and re-entries, sizing and costs, and where every statistic in the result…

  • Strategy DSL — The Engine

    Coding / Strategy DSL

    The native C++ engine (dslx) that parses, validates, backtests and runs strategy DSL: its modules, the catalog the editors are generated from, indicator…

  • Strategy DSL — The Live Engine

    Coding / Strategy DSL

    How deployed DSL strategies run: one engine process, one connection per client, shared bar feeds and indicators per symbol and timeframe, the request…

  • Writing DSL by Hand

    Coding / Strategy DSL

    Authoring strategy JSON directly: the minimum document, small constructors that keep it readable, validating before anything runs, generating variants, and…

  • Strategy DSL Format

    Automation / Strategy Builder / Reference

    The engine JSON a strategy saves as. The form, node and JSON editors all edit this one document, and the C++ engine runs it unchanged in backtests and live.

  • Building Custom Indicators

    Coding / Custom Indicators

    Composing new indicators from existing ones, the recursive shapes that need care, warm-up handling, and how to check a custom indicator is actually correct.

Browse all knowledge base articles →