1. Market Shift Levels Strategy Description
Every time the HMA moving average flips its slope, the indicator locks in the high or the low of that exact candle as a "boundary level", colors every candle relative to it, and flags the moments price pokes through the level and immediately fails.
1.1 Indicator Concept
The indicator answers one very simple question: "At what price did the market last change direction, and which side of that price are we on right now?" Everything revolves around a single number called level — one horizontal price that gets locked in and then held until the next change of direction.
- How it detects a "change of direction": it compares the HMA against its own value 5 bars ago. The code computes a Hull Moving Average (HMA — a moving-average variant designed to hug price more closely and lag less than a plain MA), then compares today's value to what the same line read 5 bars earlier. If it is higher today while it was lower on the previous bar → the HMA has just turned its slope upward. The reverse is a downward turn. This measures slope with a single comparison — no derivative formula needed.
- How it locks the level: it uses the very candle that caused the turn. Turn UP → take that candle's low as the level. Turn DOWN → take that candle's high. The reasoning: the candle at which momentum officially flipped is the "line in the sand" candle; if price comes back and breaks through its own low/high, that turn has failed.
- How you read the result: the candle colors do the work for you. Close below the level → every candle turns red. At or above the level → candles turn green. You never have to compare anything yourself, you just look at the color.
The underlying belief: the price at which momentum officially flipped is a psychologically meaningful boundary. As long as price stays on the "right" side of it the trend is intact; once it cuts through, the picture has changed. And the moments where price pokes through and snaps back within a single candle are the sign that the boundary is being defended hard — which is exactly what the indicator's labels hunt for.
1.2 Indicator Features
-
Display:
- The boundary level line (Market Shift Level): a horizontal, dashed line, black on a light chart and white on a dark chart (it follows the chart's default text color and is not configurable). It holds its height until the next HMA slope flip, at which point it jumps to a new level and starts a new segment.
- Level-relative candle coloring: every candle on the chart is repainted — green when the close is at or above the level, red when the close is below it. Body, border and wick all change color.
- Possible Reversal labels:
· A red ⬙ label pointing down, placed above the candle — marking a poke above the level that fell straight back on the next candle.
· A bright green ⬘ label pointing up, placed below the candle — marking a poke below the level that bounced straight back.
Each label carries a number: either the combined volume of the 3 candles that formed the poke, or the price at that candle's high — depending on the setting.
- Alerts: The indicator has NO alertcondition() calls. To get notifications you would have to create alerts manually in TradingView, or add the code yourself.
1.3 How to Use the Indicator
- Use the candle color as a directional filter. This is the simplest and strongest use: while candles are green, only look for longs; while they are red, only look for shorts. The indicator does not hand you entries — it tells you which side you should be on.
- Treat the moment the candles flip color as a regime change. A candle closing through the level and changing color means the boundary has just been lost. Many traders use that first color-flip candle as the exit signal for an open position, or as the cue to start looking the other way.
- Use the dashed line as a Stop Loss anchor. Because the level is the low (or high) of a real candle, it is a concrete technical reference rather than an abstract computed number. Long while candles are green → stop below the dashed line. Short while candles are red → stop above it.
- Hunt the ⬘ / ⬙ labels as "failed liquidity sweep" entries. A label only appears when price pokes through the level for exactly one candle and retreats — the classic shape of a failed stop hunt. A ⬘ label under the lows = sellers could not hold below the level, consider buying. A ⬙ label above the highs = buyers could not hold above it, consider selling.
- Read the number on the label to score the quality of the poke. In "Volume" mode (the default), a larger number means the poke-and-fail happened on heavier volume — i.e. more participants got trapped on the wrong side, which makes the signal more trustworthy. A label with tiny volume behind it is usually just noise.
- Tune "Length" to your timeframe and style. Leave it at 55 (default) for balanced signals. Drop it to 20–30 → the HMA flips slope constantly, the level moves often and candles change color frequently — suited to scalping but noisy. Raise it past 100 → the level rarely moves and each one lasts a long time, suited to swing trading a larger trend.
1.4 How the Indicator Works
Inputs & their role
- length ("Length", integer, default 55): the lookback for the HMA. This is the ONLY input that touches the logic — it decides where the level is locked, how often it changes, and therefore drives all the candle coloring and every label position. Example: on XAUUSD M15 at 55, a level may hold for 40–80 bars; drop it to 20 and the level may change every 10–20 bars. The remaining color and dropdown inputs never touch the logic, they only change presentation.
- lbl_data ("Label Data:", dropdown with two values "Volume" / "Price", default Volume): decides the number printed on the reversal labels. Pick "Volume" → prints the combined volume of the 3 candles that formed the poke, in compact notation like 1.234K / 5.6M. Pick "Price" → prints a price with 3 decimals. It has no effect on whether a label appears, only on the text inside it.
- color_shiftUp (color picker, default rgb(36,213,128) — green): the candle color when the close is at or above the level.
- color_shiftDn (color picker, default rgb(225,43,43) — red): the candle color when the close is below the level. Both pickers use inline = "col" with an empty title, so in the Settings dialog they show up as two unlabeled color swatches sitting side by side — confusing the first time you open it. The left swatch is the up color, the right one is the down color.
Hard-coded constants (NOT inputs)
- The 5-bar offset in hma1[5]: the distance used to measure the HMA's slope. Changing it would make the indicator noticeably more or less sensitive, but it requires editing the code.
- The 3-bar window used by vol_sum and by the label pattern: hard-coded, cannot be widened.
- max_labels_count = 500: declared on the first line, the ceiling on how many labels can exist at once. Past that, TradingView silently deletes the oldest ones.
Main logic blocks
📐 Flow 1 — Detecting the HMA slope flip (every bar)
- hma1 = ta.hma(close, length) — a 55-period Hull Moving Average of the close. The HMA is a moving-average variant engineered to be both smooth and less laggy than a plain MA, so it turns earlier.
- hma2 = hma1[5] — that same line, but its value from 5 bars ago. This is not a second line, just a 5-bar-delayed copy of the same one.
- ta.crossover(hma1, hma2) — catches the exact moment hma1 rises above hma2, meaning today's HMA is now higher than it was 5 bars ago while on the previous bar it was not yet. Translated: the HMA has just flipped its slope from falling to rising.
- ta.crossunder(hma1, hma2) — the reverse, the HMA has just flipped to falling.
- Concrete example: the HMA 5 bars ago = 2640. On the previous bar the HMA = 2638 (still below 2640, no cross yet). On this bar the HMA = 2643 (now above 2640) → crossover fires. Because the HMA needs 55 bars to compute and then 5 more to have a delayed copy, roughly the first 60 bars of the chart cannot produce any signal.
📍 Flow 2 — Locking in the boundary level (only on slope-flip bars)
- var level = float(na) — the var keyword means this variable is remembered across bars rather than recalculated from scratch on each one. It keeps its value until a new assignment runs.
- Slope flips UP → level := low, taking the low of the current candle.
- Slope flips DOWN → level := high, taking the high of the current candle.
- On every other bar nothing touches level → it sits still. That is why the dashed line on the chart is always perfectly horizontal.
- At any moment there is ONLY EVER ONE active level. The indicator keeps no history of past levels in memory — old levels survive only as already-rendered pixels on the chart. The plural in "Levels" refers to the succession of levels over time.
🎨 Flow 3 — Coloring the candles (every bar)
- shift_col = close < level ? color_shiftDn : color_shiftUp — a single comparison, re-evaluated on every bar. Close below the level → red, at or above → green.
- The color is applied through two calls at once: barcolor() repaints the chart's native candles, and plotcandle() draws a whole new set of candles over the top (body, border and wick). Doing both sounds redundant, but it guarantees the coloring still shows up even if the user has the chart set to line, Heikin Ashi or bars instead of candlesticks.
- A note on timing: the comparison uses close, and a live candle's close keeps changing. The current candle can flicker back and forth between colors during the session; only on close does the color settle.
➖ Flow 4 — Drawing the dashed level line (every bar)
- plot(level != level[1] ? na : level, style = plot.style_linebr) — reads as: "if the level just changed versus the previous bar, plot a gap, otherwise plot the level". The style_linebr style is what allows the line to contain holes. The purpose: when the level jumps from 2585 to 2640, drawing it continuously would leave an ugly vertical connector between the two heights; inserting a gap exactly on the change bar severs that connector. Side effect: the new level's line segment only starts on the bar AFTER the slope flip, not on the flip bar itself.
- The dashed effect is produced by a trick: the line's color is bar_index % 2 == 0 ? color(na) : chart.fg_color — i.e. one bar drawn in color, the next transparent, alternating. This is not Pine's built-in dashed line style; it is visible/invisible segments alternating per candle column. Which means each dash's length scales automatically with the chart's zoom level.
- chart.fg_color is the chart's default text color, which follows the light/dark theme automatically. That means the level line's color is not covered by any input — changing it requires editing the code.
🏷️ Flow 5 — Detecting the poke-and-fail pattern and placing labels (every bar)
-
BEARISH label (red ⬙) — all 3 conditions required across 3 consecutive candles:
- ① high[2] < level — two candles ago the high was still below the level (no contact yet).
- ② high[1] > level — the middle candle's high pushed above the level (the poke).
- ③ high < level — the current candle's high has dropped back below the level (the poke failed).
- All 3 met → place a label on the middle candle (bar_index − 1) at height high[1], in label_down style so its tip points down into the candle's high.
- BULLISH label (green ⬘) — perfectly symmetric: low[2] > level (the low was still above the level), low[1] < level (poked below), low > level (snapped back above). The label goes at low[1] in label_up style.
- The key thing to understand: this pattern requires the poke to last exactly one candle. If price clears the level and stays there for 2 or more candles, condition ① immediately fails → no label at all. So the labels do NOT mark real breakouts; they only mark very short false breakouts.
- vol_sum = volume[2] + volume[1] + volume[0] — the combined volume of exactly the 3 candles in the pattern, printed on the label in "Volume" mode. It measures "how much force that failed poke consumed".
- Concrete example: the level sits at 2640. Bar 98 high 2635 (below the level ✓). Bar 99 high 2644 (poked above ✓). Bar 100 high 2637 (back below ✓) → on bar 100, a red ⬙ label is attached to bar 99 at height 2644, carrying the combined volume of bars 98+99+100.
Outputs & their role in trading
- The dashed level line: the current technical boundary — used as a Stop Loss anchor and as the level to watch for a break.
- Candle color: a directional filter that instantly answers "am I a buyer or a seller right now". The moment the color flips is the regime-change signal.
- The ⬘ / ⬙ labels with their numbers: on-the-spot reversal signals marking a one-candle false break; the volume figure is there to score how trustworthy it is.
- A BUG in the code: the BULLISH label shows the wrong price in "Price" mode. The bullish label is positioned at low[1] (the middle candle's low), but the text line calls str.tostring(lbl_data ? vol_sum : high[1], ...) — using high[1] rather than low[1]. The result: the label sits at the candle's low while the number it prints is that candle's HIGH. This is almost certainly a copy-paste slip from the bearish block above. "Volume" mode (the default) is unaffected because both blocks share the same vol_sum — so most users will never notice.
- The two color pickers do NOT control the label colors. The label text colors are hard-coded as color.red and color.lime. Change color_shiftUp to blue and your candles turn blue while the labels stay bright green. The two color inputs affect candle coloring and nothing else.
- Before the first slope flip, every candle is GREEN for no meaningful reason. At that point level is still na, and in Pine every comparison against na evaluates to false, so close < level never holds → the indicator falls through to the up-color branch. Roughly the first 60 bars of any chart are therefore green regardless of which way price went. Do not read that stretch as a signal.
- A freshly changed level can manufacture phantom labels. The label conditions compare high[2] and high[1] against the current value of level. If the level just jumped somewhere else on this bar, those two past candles are being measured against a boundary that did not exist back then. A label can appear describing a "poke and fail" that never actually happened. Treat labels sitting immediately after a level change with suspicion.
- Labels can flicker during the session (mild repaint). Condition ③ uses the high / low of the LIVE candle. While price is still moving, the current candle's high/low keeps changing, so a label can appear and vanish several times before the bar closes. Only trust a label once that third candle has fully closed.
- Every level segment starts 1 bar late. Because the level != level[1] ? na : level trick inserts a gap exactly on the bar where the level changes, the new level's dashed line only shows up from the following bar. On the chart you will notice that the very candle that created the level is the one candle with no line running through it.
- The indicator stores no level history. There is only the single level variable. Past levels exist on the chart purely as already-rendered pixels — the program can no longer reach them. If Phase B or Phase D needs to reference an earlier level (say, to place a Take Profit at an old level), an array will have to be added; the original code has nothing of the sort.


