Quick Create — NLP Expression Reference

Type natural language or structured dot-notation to instantly build trading signal expressions.

Contents
  1. Basic Syntax
  2. Canonical Generation Rules
  3. Indicators (200+)
  4. Candle Patterns (60+)
  5. Price & Market Data
  6. Price Patterns (40)
  7. Trend, Channel, Price Move, Fibonacci, Pivot
  8. Date & Time
  9. Operators
  10. Timeframes
  11. Dot-Notation Mode
  12. Complete Examples
  13. Unary Expressions
  14. History (Previous Bars)

1. Basic Syntax

Expressions follow the pattern: LEFT   OPERATOR   RIGHT with optional symbol and timeframe.

bullish engulfing > 0                 // unary — candle / pattern flag (compare > 0)
doji > 0 15min
RSI(14) < 30
SMA(50) > SMA(200)
Close > SMA(200) 5min
You can omit parameters — defaults from the native GTS indicator registry are used.

2. Canonical Generation Rules

When an AI/model generates expression JSON or dot-notation from this page, use these rules first.

CaseCanonical Output
Regular indicators: RSI, SMA, EMA, MACD, ATR, BBANDS, STOCH, ADX, SAR...Use GTSIndicators for every regular indicator.
Extended/subsystem indicators: InertialRsi, AdaptiveCentricMa, AdaptiveMacdR2, BreakOfStructure...Use ExtendedIndicators.
Decimal parameters such as SAR(0.02,0.2)Use function syntax. Do not encode decimal params in dot notation because dots are separators.
Single value on a multi-param extended indicatorThe value fills the first configured parameter; remaining parameters use defaults.
Subfields with spacesPrefer compact aliases in text/dot notation: Upper, Lower, SenkouA, AroonUp. JSON may use the runtime field name.
Subfield caseUse the documented convention in generated dot notation: regular GTSIndicators subfields are capitalized (.Signal, .SlowK); ExtendedIndicators outputs are lowercase (.signal, .value).
Candle patternsCanonical natural order is trend pattern, e.g. bullish engulfing. Dot notation is TA_CandlePatterns.PATTERN.Trend.Frame.
Negative fixed valuesUse natural/formula syntax: openpnl < -500. Dot notation may use FixedVal.-500 for integers.
Strict NLP generation rules (read before generating)
  1. Every expression must resolve to LEFT OPERATOR RIGHT (or a single unary operand). Arithmetic (+ - * /) is not supported by this parser — use an indicator, field, or saved expression directly, not a calculation. This limit is scoped to Quick Create only. GTS itself has arithmetic operators: the visual builder lists math (+ − × ÷) alongside compare and logic, and JSON Import accepts them in Expression_left_operation. To use arithmetic, build the calculation as its own expression there, save it, then reference it by name here. See the expression model.
  2. LEFT and RIGHT must each be a single numeric field, fixed value, indicator, pattern, account field, or date/time value.
  3. Pattern and event flags (candle patterns, price patterns, structure events) are compared to 0 — use > 0 or != 0, never == 100.
  4. Use only the subfields listed for each indicator (e.g. .signal, .value); do not invent subfields.
  5. Candle-pattern trend defaults to Bullish when unspecified; write bearish <pattern> or both <pattern> to change it.
  6. If the timeframe is omitted, the strategy/alert's configured frame is used. If the symbol is omitted, the configured symbol(s) are used.

3. Indicators

Two different element types. Regular indicators use GTSIndicators (RSI, SMA, EMA, MACD, ATR, BBANDS, STOCH...). Extended Indicators use ExtendedIndicators: advanced / subsystem indicators (adaptive smoothers, SMC-ICT structure, ML/regime).

Regular Indicators — GTSIndicators (RSI · SMA · MACD · ...)

Use NAME(param) or NAME(p1,p2,p3) syntax. Subfields use .SubField.

IndicatorSyntaxDefault ParamsSubfields
RSIRSI(14)14
SMASMA(200)20
EMAEMA(50)30
MACDMACD(12,26,9)12, 26, 9Macd, Signal, Hist
BBANDSBBANDS(20,2)20, 2Upper Band (Upper), Middle Band (Middle), Lower Band (Lower)
STOCHSTOCH(14,3,3)14, 3, 3SlowK, SlowD
ATRATR(14)14
ADXADX(14)14
CCICCI(20)14
WILLRWILLR(14)14
SUPERTRENDSUPERTREND(10,3)10, 3Trend, Direction, Long, Short
ICHIMOKUICHIMOKUTenkan, Kijun, Senkou A (SenkouA), Senkou B (SenkouB), Chikou
AROONAROON(25)25Aroon Up (AroonUp), Aroon Down (AroonDown)
SARSAR(0.02,0.2)0.02, 0.2
MFIMFI(14)14
OBVOBV
MACD(12,26,9).Signal > 0         // MACD signal line
BBANDS(20,2).Upper > Close        // Bollinger upper band
STOCH(14,3,3).SlowK < 20        // Stochastic %K
ICHIMOKU.Tenkan > ICHIMOKU.Kijun  // Ichimoku crossover

Timeframes — how to add one

Append a timeframe token at the end of the expression. With no timeframe, the expression runs on whatever frame the alert/strategy is configured for. (Full token list in §10 Timeframes.)

RSI(14) < 30 5min            // 5-minute RSI
EMA(50) > EMA(200) 1h        // hourly EMA cross
SMA(200) > Close Daily        // daily SMA
MACD(12,26,9).Signal > 0 15min    // 15-minute MACD signal
ATR(14) > 5 4h               // 4-hour ATR

Symbols — with vs without

Expressions are symbol-agnostic on Trading — the symbol is bound by the strategy/handler at deploy, not on the expression. Write just the condition (and an optional timeframe); don’t add on SYMBOL.

// WITHOUT a symbol — runs on the configured symbol(s)
RSI(14) < 30
RSI(14) < 30 5min

// WITH a symbol (typical for alerts) — name the market, then the frame
RSI(14) < 30 5min
Close > SMA(200) 1h

Different notations

The same signal can be written in plain formula or in structured dot-notation.

NotationExample
Natural / formulaRSI(14) < 30 5min
Dot-notationGTSIndicators.RSI.14.5Min < FixedVal.30
Multi-param + frameGTSIndicators.MACD.12.26.9.15Min.Signal > FixedVal.0
In dot-notation the frame goes after the params: GTSIndicators.NAME.param(s).FRAME.subfield. See §11 Dot-Notation.

All GTS Indicator Categories

CategoryIndicators
Overlap / Moving AvgALMA, DEMA, EMA, FWMA, HMA, JMA, KAMA, RMA, SMA, TEMA, TRIMA, VWAP, VWMA, WMA, ZLMA, T3, SUPERTREND, ...
MomentumRSI, MACD, STOCH, STOCHRSI, CCI, MOM, ROC, WILLR, TSI, KDJ, QQE, SQUEEZE, TD_SEQ, AO, BOP, ...
VolatilityATR, BBANDS, KC, DONCHIAN, NATR, TRUE_RANGE, RVI, SQUEEZE_PRO, ...
VolumeOBV, MFI, AD, ADOSC, CMF, EFI, KVO, NVI, PVI, VPT, ...
TrendADX, AROON, ICHIMOKU, SAR, VORTEX, CHOP, DPO, LINREG, CKS, ...
StatisticsSTDDEV, VARIANCE, ZSCORE, SKEW, KURTOSIS, ENTROPY, MAD, ...
Smart Money (SMC)BOS, CHOCH, FVG, ORDER_BLOCK, SWING_HIGH, SWING_LOW, MSB, ...

Extended Indicators (200+) — ExtendedIndicators

Advanced / subsystem indicators (adaptive smoothers, SMC-ICT structure, ML / regime). Use NAME(param) syntax in natural/formula input; use ExtendedIndicators.NAME... in dot notation. Each indicator exposes named subfields such as .signal, .value, .trend, .upper — use only the subfields listed for that indicator.

IndicatorSyntaxDefault ParamsSubfields
InertialRsiInertialRsi(14).signal5, 21, 3, 9signal, rsi
AdaptiveCentricMaAdaptiveCentricMa(200).value14, 2, 2, 0.01, 0.5value
AdaptiveEmaSlopeBandAdaptiveEmaSlopeBand(50).trend20, 80, 2trend, upper, lower
AdaptiveMacdR2AdaptiveMacdR2(20,12,26,9).signal20, 12, 26, 9macd, signal, histogram
QuantileVolatilityBandsQuantileVolatilityBands(100,2).upper100, 2upper, mid, lower
InertialStochasticInertialStochastic(5,34,3,3).signal5, 34, 3, 3signal, k, d
TrueRangePercentileTrueRangePercentile.percentiledefaultpercentile
BreakOfStructureBreakOfStructure(5,5).signal5, 5signal
ChangeOfCharacterChangeOfCharacter(5,5).signal5, 5signal
SuperTrendAiClusteringSuperTrendAiClustering.signaldefaulttrend, signal
KalmanTrendFilterKalmanTrendFilter.trenddefaulttrend, value
VolumeZscoreImpulseVolumeZscoreImpulse.signaldefaultsignal, zscore
AdaptiveMacdR2(20,12,26,9).signal > 0       // native MACD-style signal
QuantileVolatilityBands(100,2).upper > Close // upper volatility band
InertialStochastic(5,34,3,3).signal < 20 // native stochastic-style signal
BreakOfStructure(5,5).signal != 0       // structure break event

Extended Indicator Categories

CategoryIndicators
Adaptive SmoothersAdaptiveCentricMa, AdaptiveEmaSlopeBand, KalmanTrendFilter, Trama, TrendRegularityAdaptiveMa, ...
OscillatorsInertialRsi, AdaptiveMacdR2, InertialStochastic, MultiLookbackRsiConsensus, StochasticAdaptiveD, ...
VolatilityTrueRangePercentile, QuantileVolatilityBands, StatisticalTrailingStop, VolatilityConeProjection, VolatilityOfVolatility, ...
VolumeVolumeZscoreImpulse, SignedVolumePressure, VolumePercentileRank, VolumeWeightedTrendScore, VolumeProfileMatrix, ...
Regime / TrendMarketStateMatrix, DirectionalMatrix, BayesianTrendProbability, SmaDirectionalMatrix, VolatilityStateMachine, ...
StatisticsReturnMadZscore, RollingSkewKurtosis, RollingPercentileRank, PermutationEntropyRegime, IsotonicRegression, ...
Smart Money (SMC)BreakOfStructure, ChangeOfCharacter, FvgDetector, OrderBlockDetector, LiquiditySweepReversal, ...

4. Candle Patterns (60+)

Specify pattern name with optional trend (Bullish/Bearish). Compare against 0 to detect formation.

doji > 0                           // any doji
bullish engulfing > 0 15min
bearish doji > 0                   // bearish doji only
hammer > 0
morningstar > 0 4h

Popular Patterns

DOJI, HAMMER, ENGULFING, MORNINGSTAR, EVENINGSTAR, SHOOTINGSTAR, HANGINGMAN, HARAMI, HARAMICROSS, SPINNINGTOP, MARUBOZU, PIERCING, DARKCLOUDCOVER, 3WHITESOLDIERS, 3BLACKCROWS, ABANDONEDBABY, INVERTEDHAMMER, DRAGONFLYDOJI, GRAVESTONEDOJI, HIKKAKE, KICKING, BELTHOLD, COUNTERATTACK, ...

5. Price & Market Data

Price Aliases (OHLC Bar)

AliasMaps ToAliasMaps To
closeCLOSE_PRICEvolumeVOLUME
openOPEN_PRICEbody_lenBODY_LEN
highMAX_PRICEtypical_priceTYPICAL_PRICE
lowMIN_PRICEdirectionDIRECTION

Quotes

AliasMaps ToAliasMaps To
bidBidmidMidPrice
askAskspreadSpreadInTicks

Heikin Ashi

AliasMaps ToAliasMaps To
ha_closeCLOSE_PRICEha_highHIGH_PRICE
ha_openOPEN_PRICEha_lowLOW_PRICE
Close > AdaptiveCentricMa(200).value  // price above native smoother
bid > 1.1000                        // bid price check
spread > 5                           // spread filter
ha_close > ha_open                    // Heikin Ashi bullish bar
TrueRangePercentile.percentile > 80       // range/volatility pressure

6. Price Patterns (40)

Chart patterns detected automatically. Compare against 0 to detect formation.

DoubleBottom > 0
HeadAndShoulders > 0
BullFlag > 0
AscendingTriangle > 0 1h

DoubleBottom, DoubleTop, TripleBottom, TripleTop, HeadAndShoulders, InverseHeadAndShoulders, AscendingTriangle, DescendingTriangle, SymmetricalTriangle, BullFlag, BearFlag, BullPennant, BearPennant, RisingWedge, FallingWedge, CupAndHandle, DiamondTop, DiamondBottom, VBottom, WBottom, MTop, GapUp, GapDown, ...

Pattern Fields

OnFormationDone — the only field: a true/false flag that fires when the pattern completes. Compare against 0 (e.g. DoubleBottom > 0).

7. Trend, Channel, Price Move, Fibonacci, Pivot

Trend Object

AliasFieldDescription
trendsideTrendSide1=Up, -1=Down, 0=None
trendspeedperhourTrendSpeedPerHourTrend speed in ticks/hour
fastpriceFastPriceFast EMA current price
slowpriceSlowPriceSlow EMA current price
trendside == 1                       // uptrend active
trendside == -1                      // downtrend active
fastprice > slowprice                  // fast EMA above slow
TicksPerPeriod (the "Quote Updates" tile) has no Quick Create syntax at all. There is no alias for it — it is visual builder or JSON Import only. See schema §22.5 for the one-expression form.

Price Move

Expressions carry no symbol — and that is why "100 ticks" needs a moment's thought. There is no symbol field on an expression. The strategy binds the instrument when it is deployed, so one expression runs against every symbol you attach to it — think of the expression as a class and the strategy as the instance. The engine resolves that instrument's tick size itself (it divides the raw price distance by the symbol's tick size), so you never convert anything. The one value that does not auto-scale is a threshold you typed. 100 ticks is not the same economic move on EURUSD as on BTCUSDT. Either choose a number that suits the instruments you intend to attach, or read Symbol.TicksInPoint and scale it inside the logic so the threshold becomes instrument-relative too.

A price move is a directional move measured from where it started: its width in ticks, its speed in ticks per second, and how long it has been running. Use this when you mean "price travelled N ticks" — not when you mean "N quote updates arrived".

AliasAlso acceptsFieldDescription
price_movepricemove, on_price_move, price_moved, price_moves, price_move_eventonPriceMoveMove detected (boolean event)
price_move_upprice_moves_up, price_moved_up, price_going_up, price_moving_uponPriceMoveUp move — direction preset for you
price_move_downprice_moves_down, price_moved_down, price_going_down, price_moving_downonPriceMoveDown move — direction preset for you
price_move_widthmove_size, move_width, price_width, price_move_size, price_move_distance, move_distance, price_move_rangegetCurrentWidthDistance from the base, in ticks — live and continuous, and signed: negative while price moves against the configured direction
move_speedprice_speed, price_move_speed, price_velocity, speed, ticks_per_second, ticks_per_secgetCurrentSpeedTicks per SECOND (width ÷ duration, both in their stated units)
price_move_durationmove_duration, price_move_time, price_move_secondsgetCurrentDurationHow long the move has run, in seconds
price_move_directionmove_direction, price_directionDirection1=Up, -1=Down
price_move_volumemove_volumeVolumeVolume traded during the move
price_move_basemove_base_price, price_move_start_pricegetBasePricePrice the move started from
price_move_startprice_move_start_timegetStartTimeWhen the move started
Two ways to write a price move here — only one of them works. ✔ The full phrase does work: price moves 100 ticks up within 120 sec. The parser recognises it and prefills the width, the direction and the time limit for you. It loads as a unary operand; the one thing text cannot supply is the source expression, so the builder asks for that before you Save. ✘ The field aliases on their own do not: move_size > 50 resolves a field but leaves the mandatory width, direction and source unset, so Save fails with Expression_left_ElementValue is required. The alias table above is a field reference for the builder and for JSON — not a way to build the operand by comparison. Remember the width and the time limit are parameters, not comparisons: never write width > 100 and duration < 120.
price moves 100 ticks up within 120 sec   // ✔ prefills value=100, dir=Up, limit=120s
price move down 25 ticks                    // ✔ distance-only (no time limit)
price moved up 15 ticks in 3 seconds          // ✔ same shape, other wording
move_size > 50                             // ✘ no width/direction/source — Save fails
What starts a move, and what resets it — this decides when it ever fires. The base is set from the first quote after the strategy starts. From then on the move is measured from that base and waits indefinitely — there is no reversal tolerance and no timeout that quietly re-bases it. It stays armed until the width is reached. When the width IS reached, the detection completes and the base immediately re-arms at the current price with a fresh start time — so it fires once per move, not on every subsequent quote. That happens whether the move qualified (inside Max Seconds) or failed (too slow): either way the base moves on. One exception: if the width is met in the wrong direction, there is no detection and no reset — it keeps tracking from the same base.
Consequences worth knowing. price_move_width (getCurrentWidth) is signed relative to your configured direction — positive as price moves the way you asked, negative while it moves against. It is live and continuous, never zero-when-idle and never a stale copy of the last move. And because detection is quote-driven, a timeframe token on a price-move expression does not gate the move logic — it only sets how often the source expression yields a new value, which is why a coarse frame blinds a short move.
Default reading: "price move" means TICKS OF PRICE DISTANCE. If someone asks for a price move of N, assume N ticks travelled — that is this operand. Only if they explicitly mean quote updates arriving is it TicksPerPeriod ("Quote Updates"). When in doubt, price move.

Three ways to express the same rule — pick by resolution

A · Tick source (recommended for seconds-scale rules). Quotes.MidPrice updates on every quote and takes no timeframe:

[
  { "ExpressionName": "SRC_MID",                     // tick-resolution getter
    "Expression_left_ElementType": "Quotes",
    "Expression_left_ElementValue": "MidPrice" },      // no Frame — Quotes is not frame-required

  { "ExpressionName": "PM_UP_100_IN_120S",
    "Expression_left_ElementType": "UserExpression",
    "Expression_left_ElementValue": "SRC_MID",
    "Expression_left_FieldName": "onPriceMove",
    "Expression_left_PriceMoveValue": 100,
    "Expression_left_PriceMoveDirection": "Up",
    "Expression_left_TimeLimitSeconds": 120 }
]

B · Bar source. Same shape, but the getter is a bar field and needs a Frame. Detection can only advance once per bar, so keep the frame well below the time limit:

[
  { "ExpressionName": "SRC_CLOSE_1Min",             // bar-resolution getter
    "Expression_left_ElementType": "OHLC_Bar",
    "Expression_left_ElementValue": "CLOSE_PRICE",
    "Expression_left_Frame": "1Min" },            // 5Min here would blind a 120s rule

  { "ExpressionName": "PM_UP_100_IN_120S_BAR",
    "Expression_left_ElementType": "UserExpression",
    "Expression_left_ElementValue": "SRC_CLOSE_1Min",
    "Expression_left_FieldName": "onPriceMove",
    "Expression_left_PriceMoveValue": 100,
    "Expression_left_PriceMoveDirection": "Up",
    "Expression_left_TimeLimitSeconds": 120 }
]

C · Quick Create (NLP). The phrase form prefills width, direction and time limit — you then pick the source getter in the builder and Save:

price moves 100 ticks up within 120 sec   // -> value=100, dir=Up, limit=120s
price move down 25 ticks                    // -> distance only, no time limit
A and B differ only in the getter. The price-move object is identical — swapping a tick source for a bar source changes what it can see, nothing else. That is the whole reason the source is a separate expression.
"Either direction" needs two expressions plus an OR. PriceMoveDirection accepts Up or Down — there is no "both" setting. The normal solution is PM_UP_100_IN_120S, PM_DOWN_100_IN_120S, then a third combining them with OR. Both reference the same source getter.
This is an anchored move, not a rolling window. The base does not reset when the time limit elapses — it re-arms only once the width is reached. So "100 ticks within 120s" means a directional move of 100 ticks completed within 120 seconds of the base arming, not "high minus low over any rolling 2-minute window". A slow drift can consume the base and leave the fast leg you cared about undetected. Rolling high-low range is a different calculation and this operand does not provide it.
Pick the source by resolution. Quotes.MidPrice updates on every quote and needs no timeframe — the right default for short windows. A 1Min bar close updates once a minute; a 5Min close may produce no new sample at all inside a 120-second window, so it cannot detect the move. The move only sees what the source samples.

How a price move is actually built

SettingRequired?Meaning
Source expressionMandatoryA saved value expression supplying the price series (e.g. a 5-minute OHLC close getter). This becomes Expression_left_ElementValue.
Price Move FieldMandatoryonPriceMove for the event; or a value field like getCurrentWidth / getCurrentSpeed.
Min Width (ticks)Mandatory, must be > 0How far price must travel to trigger. This is the "100 ticks".
DirectionMandatoryUp or Down.
Max SecondsOptional0 = distance only, any duration. > 0 = must cover the width within that many seconds. This is the "in 2 minutes" — 120.
FrameMandatoryPrice move is a frame-required operand.

So "price moved 100 ticks up within 2 minutes" is one expression, not a comparison:

{
  "ExpressionName": "PM_UP_100_IN_120S",
  "Expression_left_ElementType": "PriceMoveObject",
  "Expression_left_ElementValue": "SRC_OHLC_Close_5Min",   // source expression
  "Expression_left_Frame": "5Min",
  "Expression_left_PriceMoveValue": 100,              // the 100 ticks
  "Expression_left_PriceMoveDirection": "Up",
  "Expression_left_TimeLimitSeconds": 120             // the 2 minutes
}
Speed units differ by object — this is the most common mistake. Price move is ticks/second. Trend (trend_speed) is ticks/hour. Tick-reversal legs (ab_speed, bc_speed) and ABC waves (abc_speed) are ticks/minute. Convert before comparing them to a number.
"100 ticks in 2 minutes" — which one do you mean? Price travelling 100 ticks is price move (this section). 100 quote updates arriving is TicksPerPeriod, a different operand about market activity. Both are built in the visual builder or via JSON Import.

Any price-move field also works in the generic form pricemove_<field> — e.g. pricemove_getcurrentwidth.

Channel Object

AliasField
upperchannelUpperChannel
lowerchannelLowerChannel
channellengthChannelLength (width in ticks)
upperchannel > close                  // price below upper channel
close < lowerchannel                  // breakdown below channel

Pivot Points

AliasFieldAliasField
ppPivot Pointr1Resistance 1
s1Support 1r2Resistance 2
s2Support 2r3Resistance 3
s3Support 3
pp > close                            // price below pivot
s1 < low                              // low broke support 1
close > r1                            // price above resistance 1

Account Object

AliasFieldDescription
balanceBalanceAccount balance
openpnlOpenPNLOpen position profit/loss
closedpnlClosedPNLClosed profit/loss
usedmarginUsedMarginUsed margin
availablemarginAvailableMarginAvailable margin
openunitsOpenUnitsTotal open units
balance >= 10000
openpnl < -500

Open Position

Every field of LastOpenPositionObject — the strategy's most recent open position — is reachable as last_pos_<field>.

AliasFieldDescription
last_pos_currentprofitticksCurrentProfitTicksUnrealised profit in ticks
last_pos_currentprofitpercentCurrentProfitPercentUnrealised profit as a percent of the position's own open price
last_pos_openpnlOpenPNLUnrealised profit in account currency
last_pos_openpriceOpenPriceEntry price
last_pos_currentdurationminutesCurrentDurationMinutesMinutes since the position opened
last_pos_positionsidePositionSideSide as a number (BID=0, ASK=1)

Both profit fields are signed by side: positive means the position is winning, for a BID and an ASK alike — so one expression covers both directions. Percent is 0.2 for 0.2%.

The two profit getters also have short aliases: profit_percent / pos_profit_pct and profit_ticks / pos_profit_ticks.

profit_percent >= 0.2                      // take profit at +0.2%
profit_percent <= -0.2                     // stop at -0.2% — put BOTH in Close Bid and Close Ask
last_pos_currentprofitpercent > 0.5       // winner: up 0.5% of entry
last_pos_currentprofitpercent < -0.2      // loser: percent stop, same on every symbol
last_pos_currentprofitpercent >= 0.1      // give-back level (see warning below)
last_pos_currentprofitticks > 50          // same idea in ticks

Careful with a bare profit threshold. A position opens at ~0% profit, so last_pos_currentprofitpercent < 0.1 is already true at entry and would close it immediately. For "profit dropped below 0.10%", AND it with proof the position reached that level first — the peak (unary MAX) at or above 0.1. MIN cannot express this: it reports the worst point, never that profit had risen.

8. Date & Time

AliasTypeField
datetimeDateValueCurrentSysDateTime
dayDateValueCurrentSysDay
timeDateValueCurrentSysTime
14:00HourValueSpecific hour
datetime > DateValue.2026-01-01       // current date/time after fixed date
time < 14:00                         // before 2 PM (intraday hour check)

9. Operators

OperatorMeaningExample
>Greater thanInertialRsi(14).signal > 70
<Less thanInertialRsi(14).signal < 30
>=Greater or equalbalance >= 10000
<=Less or equalTrueRangePercentile.percentile <= 50
==Equaltrendside == 1
!=Not equaltrendside != 0
ANDBoth saved expressions must be trueUserExpression.RSI_Below_30 AND UserExpression.Balance_GT_100
OREither saved expression may be trueUserExpression.RSI_Below_30 OR UserExpression.Price_Above_SMA
crossed / crosses [above]Up-cross: was below last bar, above nowRSI(14) crossed 30
crossed below / crosses underDown-cross: was above last bar, below nowClose crossed below EMA(50)
+ - * /Not available in Quick Create. Arithmetic is a real operator in the visual builder and JSON Import, where it returns a value rather than a boolean — build the calculation as its own expression there, then reference it here by name.builder / JSON only
Referencing a saved expression by name. Anything Quick Create can't express directly — save it as its own expression, then refer to it by name as an operand. Three equivalent forms: If a bare name isn't an exact saved name, the parser fails rather than guessing — use the exact name or the exp. prefix.
Compound conditions. Just type the whole thing — RSI(14) < 30 and balance > 100 auto-builds the two legs plus the combiner for you (no need to pre-save anything). You can also combine already-saved expressions by name with AND/OR (any of the reference forms above) when you want to reuse them.
Three or more, mixed AND/OR, with parentheses. A GTS expression is binary, so a multi-way condition auto-expands bottom-up into intermediate steps plus a final combiner — built for you when you type it. Precedence: AND binds tighter than OR, so a AND b OR c AND d means (a AND b) OR (c AND d). Use parentheses to group explicitly and override precedence — (a OR b) AND c, even nested: a OR (b AND (c OR d)). Function calls like RSI(14) / MACD(12,26,9) / exp(X) are understood as operands, not grouping. The final loads in the builder; the intermediate step(s) are created automatically on Save. A leg can be a saved-expression name, a single operand, or a raw comparison — e.g. (bullish engulfing > 0) and RSI(14) > 50 auto-builds each condition into its own building-block expression, then combines them.
// Input  —  (Trend_Up OR Reversal) AND RSI_Below_30
( exp.Trend_Up OR exp.Reversal ) AND exp.RSI_Below_30

// step1 (intermediate, auto-created on Save)
exp.Trend_Up OR exp.Reversal

// final (loaded for approval)
UserExpression.[step1] AND exp.RSI_Below_30
// Leg 1
RSI(14) < 30                  // save as RSI_Below_30

// Leg 2
balance > 100                 // save as Balance_GT_100

// Combiner
UserExpression.RSI_Below_30 AND UserExpression.Balance_GT_100
[
  {
    "ExpressionName": "RSI_Below_30",
    "Expression_left_ElementType": "GTSIndicators",
    "Expression_left_ElementValue": "RSI",
    "Expression_left_Frame": "5Min",
    "Expression_left_Size1": 14,
    "Expression_left_operation": "<",
    "Expression_right_ElementType": "FixedVal",
    "Expression_right_ElementValue": "30"
  },
  {
    "ExpressionName": "Balance_GT_100",
    "Expression_left_ElementType": "AccountObject",
    "Expression_left_ElementValue": "Balance",
    "Expression_left_operation": ">",
    "Expression_right_ElementType": "FixedVal",
    "Expression_right_ElementValue": "100"
  },
  {
    "ExpressionName": "RSI_Below_30_AND_Balance_GT_100",
    "Expression_left_ElementType": "UserExpression",
    "Expression_left_ElementValue": "RSI_Below_30",
    "Expression_left_operation": "AND",
    "Expression_right_ElementType": "UserExpression",
    "Expression_right_ElementValue": "Balance_GT_100"
  }
]
Crossings. A cross is not a single condition — it is a two-bar event. a crossed b means a was below b on the previous bar AND a is above b now. Leg 1 indexes both sides (a[1] < b[1]) — it compares prev against prev, and leg 2 compares now against now. How much that matters depends on the right side: against a fixed number (RSI(14) crossed 30) the index is a no-op, since a constant is identical on every bar. When both sides are dynamic (EMA(50) crossed EMA(200)) it is essential — comparing a[1] to a live b fires false crosses whenever the slow line is moving. Typing a cross in Quick Create auto-expands it into two history-indexed legs plus an AND combiner (built bottom-up). The combiner loads into the builder for you to review; the two legs are created automatically when you click Save. crossed below / crosses under flips it (was above, now below).
// Input
RSI(14) crossed 30

// Leg 1 — prev vs prev  (a[1] < b[1]; index is a no-op if b is a constant)
RSI(14)[1] < 30            // RSI_14_below_30_prev

// Leg 2 — now above  (a > b)
RSI(14) > 30               // RSI_14_above_30_now

// Combiner (loaded for approval)
UserExpression.RSI_14_below_30_prev AND UserExpression.RSI_14_above_30_now

10. Timeframes

Append the timeframe at the end, e.g. 15min. (Expressions carry no symbol on Trading — the symbol is set on the strategy.)

InputResolves ToInputResolves To
1min 1mins 1m1Min1hour 1hours 1h1Hour
5min 5mins 5m5Min2hour 2hours 2h2Hours
10min 10mins 10m10Min4h 4hour 4hours4Hour
15min 15mins 15m15Min12hour 12hours 12h12Hours
30min 30mins 30m30Mindaily 1dDaily
weekly 1wWeeklymonthly 1moMonthly

11. Dot-Notation Mode

For precise control, use structured TYPE.FIELD.PARAMS.FRAME syntax.

Dot-notation runs through the same parser, so it has the same limit: no arithmetic here either. GTSIndicators.EMA.50.1Hour - GTSIndicators.EMA.200.1Hour will not parse. Dot-notation is a precise way to name one operand — it does not add operators the parser lacks.

Arithmetic — what the engine accepts, and where

Expression_left_operation accepts all twelve of these values (they are exactly the operator buttons in the visual builder):

GroupAccepted valuesExpression returnsQuick Create?
Compare< > == != <= >=booleanYes
LogicAND ORbooleanYes
Math- + * /value (a getter)No — builder / JSON only

A concrete, real example — this is how the bundled EMA_DIFF_H1_ABS Community expression is built. Note operation is "-" and the result is a number, so it is a helper, not an alert:

{
  "ExpressionName": "EMA_DIFF_H1_ABS",
  "Expression_left_ElementType": "UserExpression",
  "Expression_left_ElementValue": "EMA_1H_50_GETTER_H1",
  "Expression_left_operation": "-",          // math operator — returns a value
  "Expression_left_applyABS": true,
  "Expression_right_ElementType": "UserExpression",
  "Expression_right_ElementValue": "EMA_1H_200_GETTER_H1"
}

Then a second expression turns that number into a condition — UserExpression.EMA_DIFF_H1_ABS > FixedVal.0.0002. That two-step shape is the answer to every "calculated condition".

// Regular indicators
GTSIndicators.RSI.14.5Min < FixedVal.30
GTSIndicators.MACD.12.26.9.15Min.Signal > FixedVal.0
OHLC_Bar.CLOSE_PRICE.Daily > GTSIndicators.SMA.30.Daily

// Extended indicators / subsystems
ExtendedIndicators.InertialRsi.14.5Min.signal > FixedVal.30
ExtendedIndicators.AdaptiveMacdR2.20.12.26.9.15Min.signal > FixedVal.0
ExtendedIndicators.QuantileVolatilityBands.100.2.1Hour.upper > OHLC_Bar.CLOSE_PRICE.1Hour

// Candle patterns
TA_CandlePatterns.DOJI.Bullish.5Min > FixedVal.0

// Price bars
OHLC_Bar.CLOSE_PRICE.Daily > ExtendedIndicators.AdaptiveCentricMa.200.Daily.value
HeikinAshiBar.CLOSE_PRICE.5Min > HeikinAshiBar.OPEN_PRICE.5Min

// Objects
TrendObject.TrendSide == FixedVal.1
ChannelObject.UpperChannel > OHLC_Bar.CLOSE_PRICE
PivotObject.S1.Daily > OHLC_Bar.MIN_PRICE.Daily

// Account & date
AccountObject.Balance >= FixedVal.10000
AccountObject.OpenPNL < FixedVal.-500
DateValue.2026-06-01 > DateValue.2026-01-01
HourValue.14:00 > DateValue.CurrentSysDateTime

// Price patterns
PricePattern.DoubleBottom.OnFormationDone > FixedVal.0
Dot-notation is auto-detected when input starts with TYPE.FIELD format.
Do not use dot notation for decimal params or decimal fixed values. Use formula syntax instead, for example SAR(0.02,0.2) > Close 5min or bid > 1.1000.

12. Complete Examples

Momentum Signals

InertialRsi(14).signal < 30                 // oversold-style momentum
InertialRsi(14).signal > 70                 // overbought-style momentum
AdaptiveMacdR2(20,12,26,9).signal > 0     // MACD-style signal positive
InertialStochastic(5,34,3,3).signal < 20   // stochastic-style oversold
BreakOfStructure(5,5).signal != 0         // structure event

Trend Following

Close > AdaptiveCentricMa(200).value daily // above native smoother
AdaptiveCentricMa(50).value > AdaptiveCentricMa(200).value // fast above slow
KalmanTrendFilter.trend > 0              // strong trend
trendside == 1                         // GTS uptrend active

Staged Unary + History

EMA on RSI, then compare the last 3 EMA(RSI) values. Builder recipe, not one flat primitive: RSI returns one value, EMA(RSI) returns one smoothed value, then history reads previous outputs from the saved EMA(RSI) expression. The final boolean fires only when a > b > c.
// Step 1 — helper getter: one RSI value from close
RSI_Close = RSI applied to Close, collection size 15, frame 5Min

// Step 2 — helper getter: one EMA value applied to the RSI output
EMA9_RSI_Close = EMA applied to UserExpression.RSI_Close, collection size 9

// Step 3 — compare current EMA(RSI) to previous EMA(RSI)
EMA9_RSI_Close > EMA9_RSI_Close[1]          // a > b

// Step 4 — compare previous EMA(RSI) to two-bars-back EMA(RSI)
EMA9_RSI_Close[1] > EMA9_RSI_Close[2]     // b > c

// Final expression — true only when the last 3 EMA(RSI) values are rising
UserExpression.EMA9_RSI_now_gt_prev AND UserExpression.EMA9_RSI_prev_gt_prev2
// Exact JSON shape for the same recipe
[
  {
    "ExpressionName": "RSI_Close",
    "Expression_left_ElementType": "OHLC_Bar",
    "Expression_left_ElementValue": "CLOSE_PRICE",
    "Expression_left_Frame": "5Min",
    "Expression_left_UseRSI": true,
    "Expression_left_collectionSize": 15,
    "Expression_left_numElement": 15
  },
  {
    "ExpressionName": "EMA9_RSI_Close",
    "Expression_left_ElementType": "UserExpression",
    "Expression_left_ElementValue": "RSI_Close",
    "Expression_left_UseEMA": true,
    "Expression_left_collectionSize": 9,
    "Expression_left_numElement": 9
  },
  {
    "ExpressionName": "EMA9_RSI_now_gt_prev",
    "Expression_left_ElementType": "UserExpression",
    "Expression_left_ElementValue": "EMA9_RSI_Close",
    "Expression_left_operation": ">",
    "Expression_right_ElementType": "UserExpression",
    "Expression_right_ElementValue": "EMA9_RSI_Close",
    "Expression_right_UseHistoryElem": true,
    "Expression_right_historyIndex": 1,
    "Expression_right_collectionSize": 2
  },
  {
    "ExpressionName": "EMA9_RSI_prev_gt_prev2",
    "Expression_left_ElementType": "UserExpression",
    "Expression_left_ElementValue": "EMA9_RSI_Close",
    "Expression_left_UseHistoryElem": true,
    "Expression_left_historyIndex": 1,
    "Expression_left_collectionSize": 2,
    "Expression_left_operation": ">",
    "Expression_right_ElementType": "UserExpression",
    "Expression_right_ElementValue": "EMA9_RSI_Close",
    "Expression_right_UseHistoryElem": true,
    "Expression_right_historyIndex": 2,
    "Expression_right_collectionSize": 3
  },
  {
    "ExpressionName": "EMA9_RSI_last3_rising",
    "Expression_left_ElementType": "UserExpression",
    "Expression_left_ElementValue": "EMA9_RSI_now_gt_prev",
    "Expression_left_operation": "AND",
    "Expression_right_ElementType": "UserExpression",
    "Expression_right_ElementValue": "EMA9_RSI_prev_gt_prev2"
  }
]

Volatility & Bands

Close > QuantileVolatilityBands(100,2).upper // above upper band
TrueRangePercentile.percentile > 80       // high range percentile
VolatilityStateMachine.state != 0         // volatility regime active

Pattern Detection

bullish engulfing > 0 4h  // candle pattern
DoubleBottom > 0                        // chart pattern
hammer > 0 1h              // hammer on hourly

Support & Resistance

close > r1                              // above resistance 1
s1 < low                                // broke support 1
close > upperchannel                    // channel breakout

Risk Management

balance >= 10000                       // min balance
openpnl < -500                         // max open loss
spread < 3                             // max spread filter
Expressions are case-insensitive for aliases and pattern names. On Trading, expressions are symbol-agnostic — the symbol is set on the strategy, not the expression.

13. Unary Expressions

A unary expression is a single operand with no comparison — it fires on its own when the operand is truthy / non-zero. Just type the operand by itself (no operator, no right side):

bullish engulfing                  // candle pattern — fires on formation
doji 1h                 // pattern on a timeframe
UserExpression.My_Signal           // a saved expression, on its own
KalmanTrendFilter.trend            // fires when the value is non-zero
Add a comparison only when you need a threshold (e.g. RSI(14) < 30). A bare numeric indicator (e.g. RSI(14)) becomes a unary getter — valid as a building block, but you usually want a comparison.

14. History (Previous Bars)

Append [N] to any operand to read it N bars back — the same notation the builder shows in dot-notation. [0] or no suffix = the current bar.

Close[1] > Close[2]                // previous close above the one before
RSI(14)[1] < 30                // RSI on the previous bar
direction[1] > 0               // previous bar closed up
high[1] > SMA(20)                  // prior high vs current SMA(20)
A true cross (a<b then a>b) needs two bars of state, which one single-condition expression can't hold. You don't have to build it by hand — type a crossed b (or crossed below) and it auto-expands into the two history-indexed legs (a[1] < b[1] and a > b) plus an AND combiner — prev vs prev, then now vs now. Against a fixed number the index on the right side does nothing; when both sides move it is what stops false crosses. See the cross rows in Operators.
GTS — Global Trading Station • Quick Create NLP Reference