Appearance

Personalize your experience

Mode
Accent Color
Direction
Strategy DSL — Conditions That Can Never Be True

Conditions That Can Never Be True

Reference

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 how to fix each case.

Why they are errors

A condition that can never be true does not crash anything. It makes its signal silent: the backtest shows zero , the never acts, and nothing at the cause. RSI > 120 looks like a typo for 20, and RSI < 30 AND RSI > 70 usually meant OR. Both are easy to write and slow to find, so the engine refuses them when the is parsed, with the JSON of the condition or the AND group.

The same check runs in the browser (form, node and JSON editors) with the same messages and paths, so a problem shows on the condition row, the node or the JSON line before anything is saved or backtested.

dslx_cli --validate
{
  "valid": false,
  "errors": [{
    "path": "entry.signals[0].conditions",
    "message": "'RSI(14, close) < 30' and 'RSI(14, close) > 70' can never both be true"
  }]
}

What is rejected

ShapeExampleWhy
A constant outside the output’s rangeRSI > 120 · WilliamsR > 5 · Close < 0 · ATR < 0 is 0…100, %R −100…0, prices are positive, is never negative
A an event or direction cannot takeDoji == 2 · Doji == 0.5 · Supertrend.direction == 2Events are 0 or 1; directions are −1, 0 or +1
A clock or calendar that does not existHourOfDay == 7.5 · HourOfDay >= 24 · TimeOfDay == 975 · DayOfWeek == 8Whole numbers only; HHMM minutes are 00…59; Monday = 1 … Sunday = 7
A through a level the series cannot passRSI crossesAbove 100 · Supertrend.direction crossesAbove 1Crossing above 100 needs a above 100
rising / falling longer than a series can moveDoji rising 2A 0 / 1 series can rise for one bar at most
A series against itselfEMA(20) > EMA(20) · Close crossesAbove closeEqual on every bar (>= and <= are always true and are allowed)
Bar-range factsHigh < Low · Low > close · High crossesBelow closeOn one bar High is the largest price and Low the smallest
Ranges that never meetWilliamsR > StatRSquared−100…0 is never above 0…1
An AND whose conditions exclude each otherRSI < 30 AND RSI > 70 · RSI == 50 AND RSI != 50 · EMA9 > EMA21 AND EMA21 > EMA9No satisfies both
A that contradicts the previous barRSI crossesAbove 30 AND RSI[1] > 30A above 30 needs the previous bar at or below 30
A with no whole number insideHourOfDay > 9 AND HourOfDay < 10There is no hour strictly between 9 and 10
A switch case that never matchesswitch DayOfWeek, case 9Reported at the case’s

Nested ANDs are checked as one group (RSI < 30 AND (RSI > 40) is caught). A contradiction inside one branch of an OR is reported at that branch's , because that branch can never contribute.

What is allowed on purpose

  • Edges of the range. RSI >= 100 and RSI crossesAbove 99 can happen, so they pass.
  • Different bars or timeframes. EMA(20) > EMA(20)[1], High[1] < Low (a gap) and RSI < 30 AND 1h RSI > 70 different values.
  • OR and NOT. RSI < 30 OR RSI > 70 is fine, and a NOT is never treated as a contradiction.
  • Anything it cannot prove. Unbounded values (MACD, ROC, formulas, QuaScript series) have no declared range and are never on range grounds. The check has no false positives: every rejection is a condition no market could satisfy.
ℹ
Note:Comparing values in unrelated units — RSI > close, Volume > EMA(20), against Williams %R — is legal but almost never meant. It is reported as a warning, not an error.

How the check works

Every output declares the values it can take: a range ( 0…100), a ( ≥ 0, prices > 0), a set (events 0 / 1, directions ±1) or whole numbers (clock values). For one condition the checker whether any in that range satisfies the operator; for a it needs a value on each side of the level. For an AND it collects, per series (and per pair of series), the bounds each condition demands and intersects them — a cross also bounds the previous bar. An empty intersection is a contradiction, and the message names the two conditions that clash.

The engine's check is apps/hft/dsl/src/dsl/satisfiability.cpp; the browser mirror is strategy-builder/dsl/satisfiability.ts. A test (scripts/verify-conditions.mts) generates thousands of random condition trees and confirms the two agree on every verdict and , and that every condition rejected as never true is in fact false on every bar of several synthetic markets.

How the editors avoid them

  • Picking an indicator in a - side that can be true: < 30, == 1, Close > (20), Volume > VolumeSMA(20), TimeOfDay >= 930.
  • Changing the operator or the output repairs a constant that would become impossible ( line → direction switches the to 0 for a ).
  • Events and directions are chosen from a list of their possible values; numbers outside the range are back when the field loses focus.
  • --side modes that cannot work are hidden — there is no “Field” option for .
  • Conflicting AND groups show an error on the group (form) or the logic node (node editor).

See also

Related articles

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

  • Debugging Strategies

    Coding / Debugging

    A method for diagnosing strategies that do nothing, do too much, or do the wrong thing — plus the specific symptoms that have specific causes.

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

  • Built-in Indicators & Overlays

    Coding / IDE / Reference

    Quatick ships with a full library of pre-built indicators and overlays. You can use these out of the box, or study their implementations as reference for…

  • Coding for Trading — Fundamentals

    Coding / Fundamentals

    The concepts every strategy rests on, whether you write it in the condition builder or in code: series, bar indexing, the difference between a value and a…

Browse all knowledge base articles →