Exhaustion Reversal identifies potential market exhaustion and reversal points on the price chart by detecting strong force bars followed by price give-back patterns.
//@version=5
// Exhaustion reversal — the small arrow where a push ran out of buyers.
//
// The shape it looks for is one move in two acts. First a FORCE BAR: a bar
// whose body dwarfs the recent average AND which reaches the extreme of the
// last N bars. That is a push spending itself at the edge of the move, not a
// bar that merely happens to be large in the middle of one. Then the
// GIVE-BACK, which arrives in one of two shapes — either is enough, and each
// has its own switch and its own settings:
//
// THE RUN (section 2) several consecutive opposite candles, with price
// back below (or above) a set fraction of the force
// bar by the close of the last of them.
// THE COVER (section 3) ONE opposite candle whose body sits on top of
// most of the force bar's range.
//
// They are not the same test with different numbers, which is why they are
// two sections instead of one. The run is about TRAVEL: where price ended up,
// relative to the extreme. The cover is about OVERLAP: how much of the force
// bar a single body actually covers, wherever price ends up. A slow drift
// travels without covering; a wide bar can cover the force bar and close only
// just past it. Each shape catches what the other misses.
//
// HOW TO READ THE CHART:
//
// red triangle above a bar a buying push at a new high was given back.
// Exhaustion of the up move may be at hand.
// teal triangle below a bar the mirror: a selling push at a new low was
// given back.
// no triangle no completed give-back. Most bars have no
// triangle, and that is the point — a chart
// where every bar is marked has told you
// nothing. (Measured: ~3% of bars at these
// defaults on a 2 000-bar random walk.)
//
// The triangle sits above/below the bar and never covers it. Its colour and
// width are on the indicator dialog's STYLE tab, per plot, where every other
// indicator's colours live — not in the inputs below.
//
// HONEST ABOUT THE DELAY: the mark cannot appear at the extreme, and how late
// it is depends on which shape fired. A cover can mark the very next bar
// after the force bar; a run needs at least its own length. The latest either
// can be is that shape's own window. So with the defaults a triangle is
// between 1 and 5 bars behind the extreme it is about. You are being shown a
// reversal that has already partly happened, which is the only kind that can
// be proven from closed bars. Nothing is drawn on a forming bar, so no mark
// ever appears and then disappears: what you see has committed.
//
// WHY THE WINDOWS: without a ceiling, "opposite candles eventually showed up"
// is true of almost every force bar if you wait long enough — the give-back
// would just be the tape drifting sideways in a micro range. The window is
// what makes the give-back a REACTION to the push rather than a coincidence
// that followed it. Widen it and you buy more signals with less meaning; that
// trade is yours to make, not the indicator's.
//
// HOW THE RUN IS MEASURED — two conditions, deliberately independent:
// (a) the last `run` candles all closed against the push, and
// (b) at this bar's CLOSE, price has given back `give-back` of the force
// bar's range, measured from the force bar's extreme.
// It does NOT check that the run itself did the travelling. A gap that hands
// back the whole force bar in one bar, followed by three tiny down-closes,
// satisfies both and marks. That is intentional — the question being asked is
// "is price back, and is the tape still leaning that way?", not "which bar
// carried it" — but it is worth knowing, because the streak can be cosmetic.
//
// HOW THE COVER IS MEASURED: the overlap between the opposite candle's BODY
// (open to close) and the force bar's range, as a fraction of that range. A
// full 1.0 means one body covers the force bar end to end. Because it is an
// overlap it cannot exceed 100%, which is why that slider stops there while
// the run's does not (a run can travel past the far side entirely).
//
// Note what "overlap" allows: a candle whose whole range sits INSIDE the
// force bar counts, if its body still covers enough of it. That is not a
// classical engulfing candle, and it is not called one here — a small bar
// that erases most of a large one is exactly the exhaustion this is looking
// for, whether or not it pokes out the ends.
//
// BODY-ONLY REFERENCE: both fractions above are measured, by default, against
// the force bar's full RANGE (high to low). Each has its own switch in
// section 5 — "run measures the body, not the range" and its cover
// counterpart — to measure against the force bar's BODY (open to close)
// instead, ignoring its wicks. This is the fix for a specific misreading: a
// force bar with a long wick makes the range wider than the body, so a candle
// that visibly erases most of the BODY can still fall short of a threshold
// judged against the whole wick-to-wick range. Switch it on and that same
// candle is judged only against what it actually erased. The two references
// can disagree in either direction — body-only is not simply "easier" — the
// wick shrinks both the numerator and the denominator, not one alone.
//
// The force bar's body is judged against the average of the bars BEFORE it
// (same discipline as force_bar.pine): a huge bar must not be allowed to
// inflate the very average that is deciding whether it is huge.
//
// Reaching the extreme is `>=`, not `>`: on futures the offer parks at a
// price and highs tie constantly, and a push that shoves into a level the
// tape touched N bars ago is the same event as one that clears it by a tick.
// The body test is what keeps a flat, quiet stretch from anchoring — a run of
// tied highs has no body behind it and never becomes a force bar.
//
// ONE MARK PER PUSH: a force bar arms once and is spent by the first signal
// it produces, whichever shape produced it. Without that, a run of four
// opposite candles inside the window would mark the second, third and fourth
// as separate reversals of the same push. A newer force bar re-arms the side.
//
// Both shapes draw the same triangle, so switching one off is how you find
// out which one is speaking — but read the result carefully: the switches do
// not only silence marks, they can MOVE one. If a cover spends a push on the
// bar after the force bar, the run never sees that push at all; switch the
// cover off and the same tape may mark three bars later, where the run
// finally completes. A mark that jumps when you flip a switch is those two
// shapes disagreeing about when the push ended, not an inconsistency.
//
// AN ELEPHANT HAS A SIZE, NOT ONLY A RATIO. The body test above is a
// RATIO — this body against the average of the recent ones — and a ratio
// alone is honest on time candles and promiscuous on activity-cut bars. When
// the tape goes quiet the average it multiplies collapses, so an unremarkable
// bar clears 1.5× of almost nothing and arms a push that nobody watching the
// chart would call one. This is measured, not suspected: on a live WINV26
// session the same bare band marked 247 of 1 355 volume bars as force bars;
// an absolute floor of 100 points left 7 (see docs/ux/strategy-anchors.md,
// which is why the strategy kernel's force ruler carries a floor at all).
//
// The floor measures the WHOLE CANDLE (`high - low`), the same measurement
// the kernel's `min_range` uses. It measured the body until the trader asked
// for the candle instead; both moved together, on purpose. A chart that
// paints a force bar and an armed instance that fires on one must mean the
// same thing by the word, or a trader calibrates against this script and
// then watches the bot take a bar the chart left unmarked.
//
// So section 5 adds a floor in POINTS, `and`ed with the ratio above: a
// bar must be big relative to its neighbours AND big in the instrument's own
// units. It ships at 0 — disabled, the ratio alone, exactly what this script
// did before the floor existed — because the right number is a property of
// the instrument and nothing else: ~100 points on WIN mini index, a different
// order of magnitude on BTC. Turn the paint below on and raise the floor
// until only bars you would call pushes stay coloured.
//
// SEEING WHICH BARS ARMED: section 5 carries a diagnostic switch — "paint
// the bars that arm a push". Off by default. Switch it on and every bar this
// script accepted as a force bar is painted: ORANGE for a top (sell-side)
// push, BLUE for a bottom (buy-side) one. Nothing else changes; the paint
// reports what the state machine already decided, it does not decide it.
//
// It is there because the arrows alone cannot answer "is it reading the
// right bars?". An arrow needs a push that was BOTH armed AND given back, so
// a force bar nothing faded leaves no trace at all — and neither does a bar
// that armed when it should not have. Paint them and calibration becomes a
// visual question: if bars you would never call a push come out coloured,
// `min body (×average)` is too low for this instrument, the points floor is
// still at 0, or the extreme window is too short. Worth knowing while you
// read it: the default 1.5× is the same multiple force_bar.pine calls the
// FLOOR of its force band, not its exhaustion threshold (2.5×). This section
// deliberately sets the lower bar, because the give-back is the other half of
// the test — but on a quiet tape the average it multiplies is small, and 1.5×
// of small is small.
//
// A bar that anchors both sides at once — possible only with the direction
// filter off — is painted for the top. One bar, one colour, priority fixed
// rather than left to evaluation order.
//
// HONEST ABOUT THE FORMING BAR: paint is drawn from the preview, so the bar
// being built can take a colour and lose it again before it closes (the same
// rule force_bar.pine states). A closed bar's colour never changes.
//
// Every threshold below is an input: this is a shape, and where the shape
// begins and ends is a judgement about the instrument in front of you.
// Defaults are a starting point measured on nothing in particular —
// calibrate on recorded sessions. Information, not advice: the last decision
// belongs to the trader.
indicator("Exhaustion reversal", overlay=true)
// 1 — the force bar: what counts as a push worth fading?
body_len = input.int(20, "1 Force bar: body average window (bars)", minval=1, maxval=500)
body_factor = input.float(1.5, "1 Force bar: min body (×average)", minval=0.1, maxval=20.0, step=0.1)
extreme_len = input.int(10, "1 Force bar: reaches the extreme of (bars)", minval=1, maxval=500)
need_direction = input.bool(true, "1 Force bar: must close in the direction of the push")
// 2 — the run: several opposite candles, and price back off the extreme.
use_run = input.bool(true, "2 Run: mark a give-back by consecutive candles")
run_len = input.int(3, "2 Run: opposite candles in a row", minval=1, maxval=20)
window_len = input.int(5, "2 Run: window after the force bar (bars)", minval=1, maxval=100)
coverage = input.float(0.7, "2 Run: min give-back of the force bar", minval=0.05, maxval=3.0, step=0.05)
// 3 — the cover: one opposite candle sitting on top of the force bar.
// Shorter window than the run by default: a single bar answering a push is an
// immediate response, and five bars later it is a different bar reacting to
// a different thing.
use_cover = input.bool(true, "3 Cover: mark a give-back by one opposite candle")
cover_window = input.int(5, "3 Cover: window after the force bar (bars)", minval=1, maxval=100)
cover_fraction = input.float(0.7, "3 Cover: min overlap with the force bar", minval=0.05, maxval=1.0, step=0.05)
// 4 — display: which side to mark. These gate the two TRIANGLES only. The
// state machine below runs whatever they say, so flipping a side back on
// never changes what the indicator concluded while it was off.
//
// They deliberately do NOT gate section 5's paint. The triangles are the
// reading; the paint is the ruler being checked, and a trader who silenced
// one side and then went looking for why nothing arms there would be misled
// by a diagnostic that had silenced itself along with the marks.
//
// Colour and width are deliberately NOT inputs: they live on the dialog's
// Style tab, per plot, which is what the chart actually reads. An
// `input.color` handed to a plot in this dialect does not fold, and the mark
// silently comes out amber — so a colour slider here would be a dead control.
show_top = input.bool(true, "4 Display: mark top reversals (sell side)")
show_bottom = input.bool(true, "4 Display: mark bottom reversals (buy side)")
// 5 — calibration: the rulers this shape is measured with, and the paint that
// shows what they accepted. Every one of them ships OFF (or at 0), so a fresh
// load behaves exactly like the first version of this script.
//
// THIS SECTION IS LAST FOR A REASON, and new inputs belong at the end of it.
// A saved preset is a list of values matched to inputs BY POSITION: the app
// walks the declared inputs and takes the saved value at the same index when
// its type matches. Insert an input in the middle and every preset saved
// before it silently shifts — the value a trader stored for "opposite candles
// in a row" lands on whatever now sits at that index, and a bool switch can
// be turned ON by a preset that never knew it existed. Appending keeps every
// older index pointing at the input it was saved for; the new ones simply
// find nothing and take their defaults. A test pins this order.
// No `maxval` on purpose. Every other float here is a scale-free multiple
// over a tight range, and the panel renders a float with BOTH bounds as a
// slider quantised to its step — which on this input would put the ~100 a WIN
// contract wants in the first 0.1% of the track. Bounded below only, it is a
// typed field with a floor of zero, which is what an absolute quantity in the
// instrument's own units wants to be. `step` is then no longer a quantiser at
// all, only the drag speed, and 1 point per pixel beats the 0.1 default:
// dragging to 100 should not take a thousand pixels. That speed is chosen for
// an index future, where a point is the unit the floor is thought in; on an
// instrument priced in fractions a drag of 1 per pixel is far too coarse and
// the number is typed instead. A script cannot ask what a tick is worth here,
// so one of the two has to be the dragged case.
min_range_points = input.float(0.0, "5 Calibration: min force-bar candle range (points, 0 = off)", minval=0.0, step=1.0)
run_body_only = input.bool(true, "5 Calibration: run measures the body, not the range")
cover_body_only = input.bool(true, "5 Calibration: cover measures the body, not the range")
paint_force = input.bool(false, "5 Calibration: paint the bars that arm a push")
// 6 — invalidation: when the give-back went too far to be a give-back.
//
// A candle that closes BEYOND the far end of the force bar — below its low on
// a top, above its high on a bottom — has not faded the push, it has replaced
// it. That candle is itself a force bar candidate in the other direction, and
// what comes next is the exhaustion of the exhaustion. The trade this
// indicator is about is fading the green bar, not chasing the red one that
// buried it.
//
// It kills the setup on the spot, whichever shape was about to mark and
// whenever inside the window it happens: a candle that covers 70% AND closes
// past the far end is not a mark, and the push does not get a second chance
// from a later bar either. The far end is the force bar's own extreme, wick
// included — what the eye reads off the chart — not the body, even when the
// two shapes above are measuring against the body.
invalidate_beyond = input.bool(true, "6 Invalidation: a close past the force bar's far end kills the setup")
// ---------------------------------------------------------------- measures
// Every stateful ta.* call is hoisted to the top level and fed on every bar:
// kernels have call-site identity and `and` short-circuits, so a kernel
// behind a condition would warm up late and read a gapped series. This
// applies to the four below and to nothing else — the arithmetic further
// down is current-bar only, and is deliberately left behind its guards.
body = math.abs(close - open)
avg_body_before = ta.sma(body[1], body_len)
high_before = ta.highest(high[1], extreme_len)
low_before = ta.lowest(low[1], extreme_len)
// A window shorter than the run it must contain would mean "never" — an
// input that silently cannot fire is a trap, so the window is at least the
// run. (Same spirit as force_bar.pine reordering its min/max multiples.)
run_window = math.max(window_len, run_len)
// How long a force bar stays armed: the longer of the two shapes' windows,
// and deliberately NOT conditional on their switches. If the state machine
// forgot the push sooner with one shape switched off, the other shape would
// answer differently depending on a checkbox it has nothing to do with.
arm_window = math.max(run_window, cover_window)
// A zero average is warm-up or a dead tape, not a bar that beats it. The
// `not na` guards are what keep the opening stretch unmarked.
// The ratio and the floor, in that order: the ratio rejects most bars on its
// own, so the floor is a comparison the short-circuit rarely reaches. A floor
// of 0 is `high - low >= 0`, true for every bar including a doji — the ratio is
// what still decides, exactly as it did before this input existed.
big_enough = not na(avg_body_before) and avg_body_before > 0 and body >= body_factor * avg_body_before and (high - low) >= min_range_points
new_high = not na(high_before) and high >= high_before
new_low = not na(low_before) and low <= low_before
bull_bar = close > open
bear_bar = close < open
// A doji closes neither way and breaks a run: it is a pause, not a give-back.
var int bear_run = 0
var int bull_run = 0
bear_run := bear_bar ? bear_run + 1 : 0
bull_run := bull_bar ? bull_run + 1 : 0
top_anchor = big_enough and new_high and (not need_direction or bull_bar)
bottom_anchor = big_enough and new_low and (not need_direction or bear_bar)
// ------------------------------------------------------------------- state
// One armed force bar per side, with its own age and its own rulers. The two
// sides are independent: the bar that gives back a buying push may itself be
// the selling push that arms the other side.
//
// The rulers are RESOLVED WHEN THE BAR ARMS, not read per bar: the two
// body-only switches pick between the force bar's wick-to-wick extremes and
// its body, and that choice cannot change while a push is armed — editing any
// input rebuilds the indicator and replays the whole history, so there is no
// live tape on which a stored ruler could go stale. Resolving it here keeps
// eight ternaries and four subtractions off every bar, armed or not, and puts
// them on the rare bar that actually arms. Measured on the commit path (the
// 100k-bar interpreter bench): the version that read the switches per bar
// cost about 20% more per bar, this one about 5%. What that bench does NOT
// cover is the preview path, which runs per print rather than per bar and
// clones every global slot — and this shape holds six more of them than the
// per-bar one did. The trade is a win on the measured path and unmeasured on
// the other; that is the honest statement of it. Each shape stores its own pair
// because the run and the cover choose independently: a wide-wick push can be
// judged by its body for one and by its range for the other.
var bool top_armed = false
var int top_age = 0
var float top_run_high = na
var float top_run_low = na
var float top_run_range = na
var float top_cover_high = na
var float top_cover_low = na
var float top_cover_range = na
var float top_bar_low = na
var bool bottom_armed = false
var int bottom_age = 0
var float bottom_run_high = na
var float bottom_run_low = na
var float bottom_run_range = na
var float bottom_cover_high = na
var float bottom_cover_low = na
var float bottom_cover_range = na
var float bottom_bar_high = na
// Age first, test second, arm last. Ageing before the test is what makes the
// bar `run_len` bars after the force bar read as age `run_len`; arming after
// it is what stops a force bar from being faded by the very bar that made it.
if top_armed
top_age := top_age + 1
if top_age > arm_window
top_armed := false
if bottom_armed
bottom_age := bottom_age + 1
if bottom_age > arm_window
bottom_armed := false
// ----------------------------------------------------------------- signals
// Invalidation first, because it outranks both shapes: a bar that closes past
// the force bar's far end kills the setup even when that same bar would have
// marked. `top_armed` short-circuits it away on the bars where nothing is
// armed, which is most of them.
top_killed = invalidate_beyond and top_armed and close < top_bar_low
bottom_killed = invalidate_beyond and bottom_armed and close > bottom_bar_high
// Every ruler below was resolved when its push armed, and it KEEPS that value
// after the push is spent — nothing writes `na` back on disarm or expiry. So
// `top_armed` / `bottom_armed` is the only thing standing between a stale
// ruler and this arithmetic, and it is deliberately first in every chain
// below. The `> 0` tests guard against a zero denominator, not a stale one;
// reordering the chain so one of them runs first would read a spent push.
//
// The divisions and the overlap arithmetic sit BEHIND the guards on purpose.
// `and` short-circuits, and on the large majority of bars no push is armed —
// so on those bars this line stops at `top_armed` and the maths never runs.
// (Measured: ~17% of the script's commit cost, and this runs again for every
// preview of the forming bar.) Nothing here is a `ta.*` kernel, so unlike the
// measures above there is no warm-up to protect by hoisting it.
sell_run = use_run and top_armed and top_age >= run_len and top_age <= run_window and bear_run >= run_len and top_run_range > 0 and (top_run_high - close) / top_run_range >= coverage
buy_run = use_run and bottom_armed and bottom_age >= run_len and bottom_age <= run_window and bull_run >= run_len and bottom_run_range > 0 and (close - bottom_run_low) / bottom_run_range >= coverage
// The cover: the overlap of two intervals — this candle's body against the
// force bar's range (or body) — so it is bounded by the force bar and cannot
// be inflated by a candle that is merely enormous somewhere else. A body that
// does not reach the force bar at all makes the overlap negative, which
// fails on its own.
sell_cover = use_cover and top_armed and top_age <= cover_window and bear_bar and top_cover_range > 0 and (math.min(open, top_cover_high) - math.max(close, top_cover_low)) / top_cover_range >= cover_fraction
buy_cover = use_cover and bottom_armed and bottom_age <= cover_window and bull_bar and bottom_cover_range > 0 and (math.min(close, bottom_cover_high) - math.max(open, bottom_cover_low)) / bottom_cover_range >= cover_fraction
// Either shape marks, unless the setup was killed on this very bar.
sell_signal = (sell_run or sell_cover) and not top_killed
buy_signal = (buy_run or buy_cover) and not bottom_killed
// A push is spent by the signal it produced OR by the close that invalidated
// it — a killed push gets no second chance from a later bar in the window.
if sell_signal or top_killed
top_armed := false
if buy_signal or bottom_killed
bottom_armed := false
// Arming is also where each shape's ruler is measured out, once, from the
// force bar that is being armed — see the state block above for why storing
// it is safe and what it saves.
if top_anchor
top_armed := true
top_age := 0
top_run_high := run_body_only ? math.max(open, close) : high
top_run_low := run_body_only ? math.min(open, close) : low
top_run_range := top_run_high - top_run_low
top_cover_high := cover_body_only ? math.max(open, close) : high
top_cover_low := cover_body_only ? math.min(open, close) : low
top_cover_range := top_cover_high - top_cover_low
top_bar_low := low
if bottom_anchor
bottom_armed := true
bottom_age := 0
bottom_run_high := run_body_only ? math.max(open, close) : high
bottom_run_low := run_body_only ? math.min(open, close) : low
bottom_run_range := bottom_run_high - bottom_run_low
bottom_cover_high := cover_body_only ? math.max(open, close) : high
bottom_cover_low := cover_body_only ? math.min(open, close) : low
bottom_cover_range := bottom_cover_high - bottom_cover_low
bottom_bar_high := high
// ------------------------------------------------------------------- marks
// Closed bars only. The forming bar's preview is rolled back, so a mark that
// appeared there would be a promise the tape had not yet made.
sell_mark = sell_signal and barstate.isconfirmed
buy_mark = buy_signal and barstate.isconfirmed
plotshape(show_top and sell_mark, "Exhaustion reversal: sell", style=shape.triangledown, location=location.abovebar, color=color.red)
plotshape(show_bottom and buy_mark, "Exhaustion reversal: buy", style=shape.triangleup, location=location.belowbar, color=color.teal)
// ------------------------------------------------------------------- paint
// The diagnostic, and the only thing in this script that draws on a bar that
// produced no signal. `na` on every other bar leaves the chart's own candle
// colours alone — an unpainted bar is this script saying "not a push", which
// is the answer on the large majority of them.
//
// ONE PAINTER WINS PER BAR, AND IT IS THE LAST ONE ADDED. The chart resolves
// the bar paint channel by walking the indicator stack backwards and taking
// the first colour it finds (`resolve_bar_paint`), so a script added AFTER
// this one hides it wherever both paint. force_bar.pine paints every body at
// or above 1.5x its average — which is nearly every bar this diagnostic is
// about — so run this one alone while calibrating, or add it last. The two
// colours here being ones force_bar.pine does not use settles which script a
// colour came from; it does not make both visible on one bar.
paint = na
if paint_force
if top_anchor
paint := color.orange
else if bottom_anchor
paint := color.blue
barcolor(paint)
Overview
A force bar is defined by an above-average body reaching recent extreme highs or lows. The script checks for price give-backs through consecutive opposite candles or a single overlapping cover candle. Reversal setups trigger top and bottom visual triangle markers on the price chart. Users can adjust force bar thresholds, run or cover sensitivity windows, and setup invalidation rules. Signals lag the extreme by several bars to ensure closed-bar confirmation.
Force bar detection based on body size and extreme range
Run give-back pattern via consecutive opposite candles
Cover give-back pattern via single-candle body overlap
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
1 Force bar: body average window (bars)
int
20
body_len
1 Force bar: min body (×average)
float
1.5
body_factor
1 Force bar: reaches the extreme of (bars)
int
10
extreme_len
1 Force bar: must close in the direction of the push
bool
true
need_direction
2 Run: mark a give-back by consecutive candles
bool
true
use_run
2 Run: opposite candles in a row
int
3
run_len
2 Run: window after the force bar (bars)
int
5
window_len
2 Run: min give-back of the force bar
float
0.7
coverage
3 Cover: mark a give-back by one opposite candle
bool
true
use_cover
3 Cover: window after the force bar (bars)
int
5
cover_window
3 Cover: min overlap with the force bar
float
0.7
cover_fraction
4 Display: mark top reversals (sell side)
bool
true
show_top
Show all 18 settings
Setting
Type
Default
Variable
4 Display: mark bottom reversals (buy side)
bool
true
show_bottom
5 Calibration: min force-bar candle range (points, 0 = off)
float
0.0
min_range_points
5 Calibration: run measures the body, not the range
bool
true
run_body_only
5 Calibration: cover measures the body, not the range
bool
true
cover_body_only
5 Calibration: paint the bars that arm a push
bool
false
paint_force
6 Invalidation: a close past the force bar's far end kills the setup
bool
true
invalidate_beyond
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
Mean Reversion Study is an indicator that identifies trade setups combining exponential moving averages, RSI extremes, and engulfing candlestick patterns. It highlights bullish setups when a bullish engulfing candle forms below the EMA while RSI is oversold, a
Signal Quality Engine [WavesUnchained] is a range-fade indicator that identifies exhaustion at range extremes and signals potential reversals. It applies an ADX and EMA slope regime gate to stand down during strong trends. Using distance, structure, and moment
The Heikin-Ashi Chart Identifier is an indicator that checks if the current chart uses Heikin-Ashi candles. It tracks matched candles where open equals the average of previous open and close, and verifies no gaps between bars. When conditions match, it display
The indicator plots ICT displacement candles on the price chart and can switch to retracement scanning. Displacement requires a move larger than a set share of the 14-bar average high-low range, lasting at least a chosen number of bars, with optional close, pr
This indicator plots trade entry and exit signals on the price chart by combining Bollinger Bands with optional filter conditions. It calculates standard Bollinger Bands along with RSI, Aroon, and moving average filters. Reversal signals trigger when price bre
All Candlestick Patterns detects and highlights a wide range of bullish, bearish, and neutral candlestick patterns directly on the price chart. It features optional trend filtering using either a 50-period simple moving average or a combination of 50-period an