Indicator · Pine Script v5 · On the chart

Exhaustion Reversal

by milocaetano

Exhaustion Reversal identifies potential market exhaustion and reversal points on the price chart by detecting strong force bars followed by price give-back patterns.

View on GitHub

GitHub stars48on the repository
Pine versionv5runs as is
Lines of code452
Settings18inputs
LicenceMIT
Last updateyesterday27 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

452 lines of Pine Script v5 from crates/app/scripts/exhaustion_reversal.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

exhaustion_reversal.pine
//@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.

Details

Published by

milocaetano on GitHub

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

Candlestick patterns, Mean reversion

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
1 Force bar: body average window (bars)int20body_len
1 Force bar: min body (×average)float1.5body_factor
1 Force bar: reaches the extreme of (bars)int10extreme_len
1 Force bar: must close in the direction of the pushbooltrueneed_direction
2 Run: mark a give-back by consecutive candlesbooltrueuse_run
2 Run: opposite candles in a rowint3run_len
2 Run: window after the force bar (bars)int5window_len
2 Run: min give-back of the force barfloat0.7coverage
3 Cover: mark a give-back by one opposite candlebooltrueuse_cover
3 Cover: window after the force bar (bars)int5cover_window
3 Cover: min overlap with the force barfloat0.7cover_fraction
4 Display: mark top reversals (sell side)booltrueshow_top
Show all 18 settings
SettingTypeDefaultVariable
4 Display: mark bottom reversals (buy side)booltrueshow_bottom
5 Calibration: min force-bar candle range (points, 0 = off)float0.0min_range_points
5 Calibration: run measures the body, not the rangebooltruerun_body_only
5 Calibration: cover measures the body, not the rangebooltruecover_body_only
5 Calibration: paint the bars that arm a pushboolfalsepaint_force
6 Invalidation: a close past the force bar's far end kills the setupbooltrueinvalidate_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.

Similar Pine Scripts

285 stars

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

Indicator v4 Mean reversionCandlestick patterns
Updated 3 years ago · None stated GitHub repository of Mean Reversion Study

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

Indicator v6 Mean reversionSupport & resistance
Updated yesterday · MIT GitHub repository of Signal Quality Engine [WavesUnchained]
948 stars

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

Indicator v4 Candlestick patterns
Updated 10 days ago · GPL-3.0 GitHub repository of Heikin-Ashi Chart Identifier
575 stars

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

Indicator v6 SMC / ICT / price actionCandlestick patterns
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Displacement Candles Indicator

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

Indicator v4 Volatility & bandsOscillators & momentum
Updated 2 months ago · None stated GitHub repository of Bollinger Bands Winner IND [Alorse]

All Candlestick Patterns

by shunjizhan
292 stars

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

Indicator v4 Candlestick patternsTrend
Updated 3 years ago · None stated GitHub repository of All Candlestick Patterns

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers