Appearance

Personalize your experience

Mode
Accent Color
Direction
Condition Evaluator

Condition Evaluator

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 bar. Backtests and live strategies run the same code.

One evaluator for backtest and live

The C++ engine evaluates conditions the same way in a backtest and on the . , it appends each closed bar to the shared feed and runs the same bar step. A difference between a backtest and live therefore comes from the , the timing or the costs, never from the conditions being evaluated differently. The engine's own tests run every DSL bot both ways and compare the exits.

Series are computed once, before the first bar

When a is loaded the engine collects every operand it uses (indicator, parameters, output, timeframe, candle type) and computes each distinct series once over the whole history. Two conditions on EMA(20) share one series; several strategies on the same symbol and timeframe share them too. Evaluating a condition on a bar is then a few array reads and one comparison.

★
Pro tip:Because of this, the order of conditions inside an AND or OR does not change speed or . Write them in the order that reads best. What does cost time is the number of distinct series and very long windows.

Order of work on each bar

What happens when a bar closes
Before bar 1: every series the strategy uses is computed once
              over the whole history (no value during warm-up)

Bar N closes
│
├─1─ Protective exits for positions opened on earlier bars
│      stop → targets → time exit / max loss → session square-off
│
├─2─ Exit signals: conditions true → repetition → cooldown → flow
│      └─ acts → every open position closes at the close
│
├─3─ Entry signals: conditions true → repetition → cooldown → flow
│      └─ position rules: maxPositions, session window,
│         daily loss limit, re-entry rules when already holding
│      └─ all pass → position opens at the close
│
├─4─ Layered entry sets: own signals + gap from the previous layer
│
└─5─ Equity marked to market; daily loss limit checked
ℹ
Note:A true is necessary but not enough. Repetition, cooldown, , the position limit, the and the daily loss limit all sit between the conditions and a trade. The signal in the result count both fired (conditions true) and acted (a position opened or closed). A gap between them at one of these rules, not at the conditions.

Operators, exactly

OperatorTrue on bar t when
> < >= <=the comparison holds on bar t
== !=equal (or not) within a relative tolerance of 1e-9; meant for events, directions and clock values
crossesAboveleft[t−1] ≤ [t−1] and left[t] > right[t]
crossesBelowleft[t−1] ≥ [t−1] and left[t] < right[t]
crosseseither of the two
rising Nleft[t−k] > left[t−k−1] for every k from 0 to N−1
falling Nleft[t−k] < left[t−k−1] for every k from 0 to N−1

Both of a are read on both bars, so crossing a moving line such as Close crossesAbove EMA(20) works. An operand with an offset or a higher timeframe is read the same way: the previous bar of the signal's timeframe.

Crossover detection

A compares this bar with the previous one and is true only on the transition. That one bar of memory is the whole difference between crossesAbove and >, and it decides how often a .

The transition rule
crossesAbove — what "once" means
────────────────────────────────────────────────────────

  Bar N-1:  left = 28   right = 30    left <= right   (at or below)
  Bar N:    left = 32   right = 30    left >  right   (above)
  ⇒ fires on bar N

  Bar N+1:  left = 35   right = 30    still above
  ⇒ does NOT fire; there was no fresh crossing


RSI(14) crossesAbove 30 — a real sequence
────────────────────────────────────────────────────────

  bar  97    RSI 27.3    below 30
  bar  98    RSI 29.1    below 30
  bar  99    RSI 31.8    crossed        ← fires
  bar 100    RSI 34.2    still above
  bar 101    RSI 28.5    back below     (arms the next cross)
  bar 102    RSI 32.1    crossed        ← fires again
RSI(14) crossesAbove 30309727.39829.19931.810034.210128.510232.110336.410433.0FIRESFIRESstill above — no fresh crossing, no signalbarthe value must first go back below 30 to arm the next cross
RSI crossing 30 twice. Between the crossings it must return to 30 or below to arm the next one.
  • The previous bar must be at or below the level and the current bar strictly above it. Landing exactly on the level does not count as crossed; starting from exactly the level does.
  • A cannot fire twice without going back. If the stays above the level for forty bars, that is one signal, not forty.
  • On the first bar, and on the first bar after an indicator's warm-up, there is no valid previous , so no can fire.
!
Caution:Two crosses in one AND need both transitions on the same bar. That is rare, so the signal looks fine in the builder and almost never . Keep one as the and write the other as a comparison. A cross combined with a condition on the previous bar that contradicts it (RSI crossesAbove 30 AND RSI[1] > 30) can never be true and is by the parser.

Positions

  • Entry signals keep being evaluated while a position is open. With the default maxPositions of 1 an while holding does nothing. With a higher limit each entry signal that acts opens another position, at most one per bar; re-entry rules (cooldown, grid, DCA, pyramid, a maximum count) restrict when those adds are allowed.
  • Stops and targets are checked on every bar against the bar's high and low, separately from the exit signals. A stop still protects a position whose exit condition never becomes true.
  • A position opened on a bar is first checked against its stop and targets on the next bar. Exits run before entries, so a can exit and re-enter on the same bar.

Warm-up and missing values

An indicator has no until it has enough bars. During warm-up its value is NaN (no value, not zero), and any condition reading it is false. The same applies to an offset that reaches before the first bar and to a higher-timeframe operand before its first closed bar. The simply does not trade until every series it needs has a value.

!
Caution:This is a quiet source of misleading backtests. A using SMA(200) on a three-month daily range has almost no valid bars, so it produces almost no and those few are unrepresentative. Start the test at least the longest earlier than the range you care about. The result warns when an indicator never produced a .

See also

Related articles

  • DSL Bots

    Automation / Strategy Builder / Reference

    The 49 ready-made strategy-DSL bots: where to find them, how to load and adapt one, the file format, and what every bot is tested for.

  • Indicator Reference

    Automation / Strategy Builder / Reference

    All 94 indicators the strategy engine computes, grouped as in the builder's picker, with their parameters, outputs and the range of values each output can take.

  • Pitfalls & Anti-Patterns

    Automation / Strategy Builder / Reference

    The failure modes that show up repeatedly, what each one looks like from inside the builder, and the change that actually fixes it.

  • Strategy Builder FAQ

    Automation / Strategy Builder / Reference

    The questions that come up most often, answered with what the engine actually does rather than what would be convenient.

  • Strategy DSL — Language Reference

    Coding / Strategy DSL

    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…

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

  • Variables Reference

    Automation / Strategy Builder / Reference

    What can appear on either side of a condition — bar fields, earlier bars, higher timeframes, statistics, clock and calendar values, and formulas — and how…

  • Script Best Practices

    Coding / IDE / Best Practices

    Follow these guidelines to write performant, reliable, and maintainable trading scripts.

  • 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…

Browse all knowledge base articles →