Phrasing families
Ways of saying a condition beyond a plain comparison: range position, streaks, recency, relative volume and volatility-scaled moves.
Most conditions are a plain comparison: a value against a number or another series. But a lot of real trading ideas are not shaped like that. They talk about a window, where price sits in its yearly range, how long ago something happened, whether a state held for five bars, how big a move is relative to current volatility.
Each of those is a phrasing family: a way of saying a condition that gets compiled into exact maths on your bars. They are not a special mode or a separate syntax, write them in an ordinary strategy sentence and combine them freely with everything else (AND/OR, direction, sessions, higher-timeframe gates, stops and targets).
Each example below is a working phrase. The wording in bold is what the parser keys on, keep it and swap the asset, the numbers and the window. Every family has a ready-to-run card in the templates gallery under Windows & streaks.
Where a value sits in a window#
| Say this | What the engine checks |
|---|---|
| price is in the bottom 20% of its 52-week range | close ≤ lowest(low, N) + 0.20 × (highest(high, N) − lowest(low, N)) |
| price trades in the top 10% of the 20-day range | the same band, measured from the top |
| price is in the lower quartile of its 100-bar range | quartile / third / half / decile all work |
| price is 20% below its all-time high | close ≤ 0.80 × all-time high |
| price is within 5% of the 52-week high | proximity to one extreme |
The window is read on your timeframe: a 52-week range on the 1d is 364 bars; a 6-month range on the 4h is 1080.
"20% below the high" anchors on one extreme. "The bottom 20% of the range" anchors on the whole range: high and low. In an asymmetric range these are different conditions, and the parser keeps them apart. Say the one you mean.
Where the bar closed inside itself#
A close-strength (close-location) filter, for when a bar closing on its high means something different from a bar closing on its low.
| Say this | What the engine checks |
|---|---|
| the candle closes in the top 25% of its range | close ≥ low + 0.75 × (high − low) |
| price closes in the lower third of the bar | close ≤ low + 0.333 × (high − low) |
| the bar closes near its high | the top quarter of the bar (the documented convention) |
The deciding difference from the family above is the window: a bar/candle range (or no window at all) is this one; an N-day / N-week / N-bar range is range position.
How long ago something happened#
| Say this | What the engine checks |
|---|---|
| at least 10 bars since RSI was above 70 | bars since (RSI > 70) ≥ 10 |
| fewer than 5 bars since the MACD crossed its signal | bars since (cross) < 5 |
| more than 20 bars since price closed above the 200 EMA | bars since (close > EMA200) > 20 |
"10 bars since RSI was above 70" does not mean RSI is above 70 now, it means it isn't, and
hasn't been for a while. Use at least / more than for a cooldown and fewer than / within for
freshness.
A state or a direction that has to persist#
| Say this | What the engine checks |
|---|---|
| RSI has been above 50 for 5 consecutive bars | the comparison holds on every one of the last 5 bars |
| price has stayed above the 20 EMA for 3 bars in a row | same, against a series |
| the 50 EMA has been rising for 5 consecutive bars | the EMA is higher than the bar before on each of those 5 steps |
| RSI has been falling for 3 bars | the mirror |
Compare with the proportion form, which is a different question: 60% of the last 20 bars closed above the 50 EMA counts bars in a state; for 5 consecutive bars requires all of them.
"the 10-bar ROC is positive" is a level (ROC > 0). "the 10-bar ROC is rising" is a
direction. Adding "for 3 bars" to either one makes it persist; it does not turn one into the other.
Volume, normalised#
Raw volume thresholds don't travel between assets or across years. These do.
| Say this | What the engine checks |
|---|---|
| relative volume is above 2 (or RVOL > 2) | volume ≥ 2 × mean(volume, 20), twice normal participation |
| relative volume above 1.5 over the last 50 bars | the same, averaged over 50 bars |
| dollar volume is above $10 million | close × volume ≥ 10,000,000 |
| turnover above $5M | same as dollar volume |
| volume is twice its 20-bar average | volume ≥ 2 × mean(volume, 20) |
"relative volume above 2" means twice the average, not two units, which would be true on every
bar. If you want an absolute floor, say volume is above 1,000,000.
A series at its own extreme#
For any non-price series (RSI, ADX, ATR, volume, MACD) this adapts instead of waiting for a fixed level a strong asset may never reach.
| Say this | What the engine checks |
|---|---|
| RSI is at its lowest in 50 bars | RSI ≤ lowest(RSI, 50) |
| volume is the highest of the last 20 bars | volume ≥ highest(volume, 20) |
| ADX is at a 100-bar high | ADX ≥ highest(ADX, 100) |
For price extremes, use the breakout wording instead: price makes a new 20-day high,
price breaks above the 20-bar high, which routes to the breakout/Donchian logic.
Moves measured in volatility#
The same percentage means something different in a calm month and a violent one. Measuring in ATR keeps the rule honest across regimes.
| Say this | What the engine checks |
|---|---|
| price has fallen more than 2 ATR in the last 5 bars | close − close[5] ≤ −2 × ATR(14) |
| price has risen more than 1.5 ATR(20) over the last 10 bars | with an explicit ATR period |
| price has moved more than 3 ATR over the last 10 bars | undirected, both tails fire |
| price closes more than 2 ATR above the previous close | the single-bar form |
| price is 2 ATR below the 20 EMA | an overextension band around an indicator |
Intraday anchors: the opening range and today's levels#
These read the CURRENT day, and reset at each new day.
| Say this | What the engine checks |
|---|---|
| price breaks above the high of the first 30 minutes | the first-N-bars range of the day, broken |
| price breaks below the low of the first 4 bars | the same range, downside |
| price is above today's open | close > day_open |
| price hits the day's high / the low of the day | the running extreme so far today |
| price is down more than 3% on the day | close ≤ 0.97 × day_open |
"Today's high" is the running extreme so far today; "yesterday's high" is a completed previous-day level. They are different conditions, and the parser keeps them apart. And if you name a session, "the New York session opening range", that anchors to the session open instead of the day open, which is a separate (also supported) level.
Until the first N bars of the day have printed, the range is undefined and the condition is false. That is deliberate: a breakout judged against a range still being built would be reading bars the strategy has not traded through.
Gaps, coils and bar shape#
| Say this | What the engine checks |
|---|---|
| price fills yesterday's gap / the gap closes | price trades back through the previous day's close |
| the last 10 bars have a range under 3% | highest(high,10) − lowest(low,10) ≤ 0.03 × close |
| the 20-bar range is tighter than 5% | the same, wider window |
| the candle range is more than 1.5 ATR | (high − low) ≥ 1.5 × ATR(14) |
| the body is bigger than 1 ATR(20) | |close − open| ≥ 1 × ATR(20) |
| price is within 0.1% of a round 1000 level | distance to the nearest multiple of 1000 |
"Fills the gap" says nothing about which way the gap went, so the condition fires when price touches the previous close from either side. Say "gaps down 2%" separately if you want to detect the gap itself as well.
"A round number" could mean 100, 1000 or 10000, the parser will ask rather than guess, so say which ("a round 1000 level", "multiples of 500"). And because the tolerance is a percent of price, it must be tighter than half the increment: at BTC prices, "within 1% of a round 1000 level" is wider than the gap between levels, so every bar qualifies.
Ranking a series against its own history#
| Say this | What the engine checks |
|---|---|
| RSI is in the bottom 10% of its last 100 readings | percent rank of RSI over 100 bars ≤ 10 |
| ATR is in the top 5% of the last 200 bars | percent rank ≥ 95 |
| volatility is in its bottom quartile | the regime filter (no explicit window needed) |
The explicit "of its last N readings" form works in exits too, and composes inside larger expressions, the shorter regime phrasing is an entry filter.
How this asset moves against another one#
These are relationships, not filters. "Only while BTC is above its 200 EMA" asks about BTC; these ask how the two assets move together.
| Say this | What the engine checks |
|---|---|
| the 30-day correlation between ETH and BTC drops below 0.5 | correlation of the two return series over 30 bars |
| the correlation to BTC is above 0.8 | the same, against the asset you are trading |
| ETH has outperformed BTC over the last 30 days | ETH's 30-bar growth ≥ BTC's 30-bar growth |
| it is underperforming SPY over 60 bars | the mirror |
| ETH outperforms BTC by more than 5% over 20 days | with an excess-return margin |
| the ETH/BTC ratio is at a 50-bar high | the pair ratio at its own rolling extreme |
| the 60-day beta to SPY is above 1.5 | the OLS slope of this asset's returns on the benchmark's |
Two assets that both trend up have a price correlation near 1 no matter how differently they behave, so a price-based answer would be meaningless. These conditions compare the return series, which is what the words mean to a trader.
"Beats the market" and "correlated with everything" have no series behind them, so the
parser will not invent one. Say the symbol: outperformed BTC, beta to SPY,
correlation between ETH and BTC.
Exits that depend on the trade, not on a price#
Most exits are a level, a stop, a target, an indicator crossing. These four depend on how the trade itself has behaved, which no price condition can express.
| Say this | What the engine does |
|---|---|
| exit if the trade isn't profitable after 10 bars | at bar 10 onward, close on the first bar that is not in profit |
| give it 20 candles to work then cut it | the same, in the other phrasing |
| exit if it gives back half of the open profit | close once the open profit falls to half its peak |
| close it if it retraces 30% of the gain | the same, at 30% |
| exit on the first profitable close | close on the first bar strictly beyond your entry |
| hold for a maximum of 5 days | a hard time cap, converted to bars for your timeframe |
| exit when price closes below the lowest low of the last 5 bars | a structure trail |
"Exit after 10 bars" closes the trade no matter what, winners included. "Exit if it isn't profitable after 10 bars" spares the winner and cuts only the trade that failed to work. Both are supported; they are different strategies, so say the one you mean.
A trailing stop follows price by a fixed distance. A give-back is a fraction of the profit the trade has already shown, so it tightens automatically as the winner grows. It also arms only once the trade has genuinely been green, the peak is measured on closes, so a wick through your entry cannot turn it into a second stop-loss.
The engine's clock is bars. "A maximum of 5 days" on a 4-hour chart becomes 30 bars, but only because you said days. If you write "5 bars", you get 5 bars.
This week, this month, this year#
The day anchors have week, month and year siblings. These are the current period's running values, and they reset at each boundary.
| Say this | What the engine checks |
|---|---|
| price breaks above this week's high | the running high of the current week |
| price hits the low of this month | the running low of the current month |
| BTC is down more than 5% this week | close ≤ 0.95 × the week's open |
| it is up 20% year to date | close ≥ 1.20 × the year's open |
| price makes a new weekly high | this bar takes out the week's high so far |
| price is in the bottom 20% of this week's range | where in the week's range it is trading |
"This week's high" is the running high of the week you are in; "last week's high" is a completed level from a different week. Both work, they are different conditions, and the parser keeps them apart on exactly that wording.
"Down 5% this week" is measured from the week's open and starts again every Monday. "Down 5% over the last 10 bars" slides forward every bar and never resets. Pick the one that matches how you think about the trade.
Two timeframes in one condition#
Saying "the daily RSI is above 50" moves that whole condition to the daily chart, which is usually exactly right. These three are the cases where the two sides of the comparison live on different timeframes, which a single higher-timeframe filter cannot express.
| Say this | What the engine checks |
|---|---|
| the 1h RSI is above the daily RSI | this chart's RSI vs the daily RSI, in one condition |
| price is more than 3% below the daily 200 EMA | the current price against a daily level |
| price is 2 ATR above the weekly VWAP | the same, measured in volatility |
| price is above where it closed 3 daily bars ago | this chart's price vs a daily close from three days back |
"Price is above the 200 EMA on the daily" asks whether the daily bar is above its daily EMA, a trend filter, and the right reading. "Price is 3% below the daily 200 EMA" asks how far the price is right now from that level. Adding the distance is what tells the parser you mean the second one.
"Where it closed 3 daily bars ago" is an earlier value of the same series. RSI(3) is a
different indicator entirely. The parser keeps them apart, but the wording matters.
Who is actually doing the buying#
| Say this | What the engine checks |
|---|---|
| the cumulative volume delta over the last 20 bars is positive | each bar's volume signed by whether it closed up or down, summed |
| CVD turns negative over 50 bars | the same, other side |
| up volume is more than twice down volume over the last 20 bars | the two sides summed separately and compared |
| dollar volume is in the top 10% of the last 100 bars | participation ranked against its own history |
| the bar range is in the top 5% of the last 200 bars | the same, on range |
| bullish OBV divergence, bearish volume divergence | divergence measured on that series |
Divergence works on obv, volume, cci, mfi, roc, williams %r and stochastic as well as rsi and macd. If you were told otherwise before, that guidance was out of date.
True cumulative volume delta needs tick data to know which side each trade hit. On bars, the standard approximation is each bar's volume signed by whether it closed up or down which is what these conditions use. It is a good proxy, not the real thing.
Volatility and regime#
These describe how the asset is behaving right now, rather than where its price is. They are unit-free, so the same number means the same thing on every asset and in every year.
| Say this | What the engine checks |
|---|---|
| 20-day realized volatility is below 40% | the standard deviation of returns, annualised, as a percentage |
| historical volatility is above 80% | the same (window defaults to 20) |
| the 20-bar efficiency ratio is above 0.6 | how much of the distance travelled actually went somewhere |
| a 3 standard deviation down move | the size of the return against the asset's own recent spread |
| the move is more than 3 sigma | the same, either direction |
| the 20-day autocorrelation is negative | whether yesterday's move tends to be given back |
| returns are positively autocorrelated over 30 days | the same, other side |
"Volatility below 40%" and "ATR below 40" are different conditions. ATR is measured in the asset's own currency, so 40 means something different for every asset and every year. Realized volatility is the annualised percentage every options desk quotes, write the % and you get the comparable one.
Both answer "is this trending or chopping". The efficiency ratio is bounded between 0 and 1 1.0 is a straight line, 0 is noise that ends where it started, so a threshold you pick on one asset transfers to another. ADX does not have that property.
"2 standard deviations below VWAP" is a band around VWAP, not the size of a move, the sigma points at a reference series. "a 2 standard deviation down move" is the size of the return. Both work; naming the reference series is what tells them apart.
Candle geometry#
Named candlestick patterns already work: hammer, doji, engulfing, morning star, marubozu, shooting star and around sixty more. Name one and you get it. These phrasings are for when you'd rather describe the shape than name the pattern.
| Say this | What the engine checks |
|---|---|
| a long lower wick, a long tail | the lower shadow is at least twice the body |
| the upper wick is at least 60% of the range | that shadow against the whole bar |
| the lower wick is more than twice the body | the multiple you state |
| the body is more than 70% of the range | how much of the bar the body fills |
| a wide-bodied candle | the same, at 70% |
| the body is the largest of the last 10 bars | against the ten bars before this one |
| an inside bar, an outside bar, an outside reversal | this bar's range against the previous bar's |
| gaps up more than 2%, opens 1% above the previous close | the open against the previous close |
"A long lower wick" and "a hammer" select different bars. A hammer additionally requires a prior downtrend and a small upper wick, so naming the pattern narrows the strategy. Say whichever one you actually mean, both work.
An outside bar takes out both extremes of the previous bar, it compares full ranges. A bullish engulfing compares bodies. Different conditions, both supported; say the one you want.
A gap is the open against the previous close, so it only exists where trading stops overnight, stocks. On 24/7 crypto the tape is continuous and every bar opens where the last one closed, so there is nothing to measure. Ask for a gap on a crypto pair and the phrase is read the way a crypto trader means it: the bar closed that far above the previous close.
Volatility, persistence and shape#
| Say this | What the engine checks |
|---|---|
| ATR is above 3% of price, ATR% below 1.5 | ATR divided by price, as a percentage |
| RSI has been above 50 for the last 3 days | every bar in those three days |
| price stayed above the 200 EMA for two weeks | the same, in weeks |
| three consecutive narrowing bars, a coil | each bar's range against the one before it |
| the range has expanded two bars in a row | the mirror |
| the 50 and 200 EMA are converging, pulling apart | the gap against its own value a few bars ago |
"ATR above 3" and "ATR above 3% of price" are different conditions. ATR is quoted in the asset's own currency, so a bare number is a price: on a $60,000 asset, "ATR above 3" is three dollars: true on every bar. It also drifts as price moves, so a threshold tuned at one price stops working at another. Say the percentage and the filter travels.
A persistence filter can be written in calendar time: "for the last 3 days", "for two weeks", and the timeframe is accounted for: three days is eighteen bars on a 4h chart and three on a daily one. You don't need to do the conversion.
Two averages can be far apart and closing fast, or nearly touching and drifting apart opposite trades. "Converging" asks whether the gap is shrinking; ask for the spread if you want how far apart they are right now.
Everyday conditions#
| Say this | What the engine checks |
|---|---|
| the third touch of the 200 EMA, the second retest of VWAP | the level falls inside the bar, counted |
| only when the daily candle is green | the last completed daily close against its open |
| while the 4h candle is red | the same, other side |
| price is within 1 ATR of the 50 EMA | the gap measured in ATR, not percent |
| stop 1 ATR below entry, take profit at 3 ATR | a stop sized to the asset's own volatility |
"Stop 1 ATR below entry" and "1% stop" are very different orders. Write the word ATR and the stop is sized to volatility; write % and it is a fixed percentage. You can mix them in one strategy, "3 ATR target and a 2% stop" keeps each one as written.
"The third touch" is not the same request as "a touch", it fires on different bars and far less often. A touch means the level fell inside the bar's range, so a bar that merely closed nearby does not count.
"Only when the daily candle is green" on a 1h chart reads the last finished daily candle. The day still forming is not used, because its colour is not knowable at the time the trade would be taken.
The rest of the family list#
These work the same way and are documented alongside the operators:
| Say this | What it means |
|---|---|
| price is within 2% of the 200 EMA | proximity to a level |
| the bar's range is twice the average range | range expansion |
| the z-score is below −2 | standardised distance from the mean |
| the 50 EMA is more than 5% above the 200 EMA | percent spread between two indicators |
| RSI rose 20 points over the last 5 bars | change of a series over a window |
| RSI is 2 standard deviations below its 20-bar mean | a statistical band on any series |
| volatility is in its bottom quartile | percentile rank of a series vs its history |
If a phrase doesn't work#
Two things help more than rewording blindly:
- Check the parse. The terminal shows the parsed conditions before you run, if a clause is missing or reads differently from what you meant, that's the signal.
- Use the wording above verbatim, then change the numbers. The examples are the exact phrasings the parser is trained and tested on.
See also operators & conditions for the comparison vocabulary, and query syntax for the anatomy of a full strategy sentence.