Indicator · Pine Script v5 · On the chart

Volatility Stop MTF

by ivansoft· code credited to TradingView

An indicator on the price chart that plots an ATR-based volatility stop taken from a higher timeframe.

View on GitHub

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code285
Settings26inputs
LicenceNone statedfile: MPL-2.0
Last update1 year ago1 Mar 2025

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

285 lines of Pine Script v5 from edu_std/volatility_stop_mtf.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

volatility_stop_mtf.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © TradingView

//@version=5

// Volatility Stop MTF
// v3, 2022.05.29

// This code was written using the recommendations from the Pine Script™ User Manual's styleInput Guide:
//   https://www.tradingview.com/pine-script-docs/en/v5/writing/Style_guide.html



indicator("Volatility Stop MTF", "VStop MTF", true)

import PineCoders/Time/1 as pcTimeLib



// ———————————————————— Inputs and Constants {


color  GREEN1         = #00FF00FF
color  DARKLIME       = #00FF0080
color  RED1           = #FF0000FF
color  DARKRED        = #FF0000b0
color  DEEPSKY        = #00C0FFFF
color  DEEPBLUE       = #00C0FF80
color  DEEPPINK       = #FF0080FF
color  DARKPINK       = #FF008080
color  ORANGE         = #FF8000FF
color  DARKORANGE     = #FF8000d0
color  CLEARBLACK     = #00000000

string SI1 = "tiny"
string SI2 = "small"
string SI3 = "normal"
string SI4 = "large"
string SI5 = "huge"
string SI6 = "auto"
string CS0 = "Lime/Red"
string CS1 = "Aqua/Pink"
string ST0 = "Line"
string ST1 = "Circles"
string ST2 = "Diamonds"
string ST3 = "Arrows"             

string TP1 = "top"
string TP2 = "middle" 
string TP3 = "bottom" 
string TP4 = "left"
string TP5 = "center" 
string TP6 = "right"

string TF0 = "None"            
string TF1 = "Discrete Steps (60min, 1D, 3D, 1W, 1M, 12M)"           
string TF2 = "Multiple Of Current TF"      
string TF3 = "Fixed TF"         


string A1             = alert.freq_once_per_bar
string A2             = alert.freq_once_per_bar_close

string SIZE_TT        = "Changes the size of the display table."
string POS_TT         = "Changes the position of the display table on the screen."
string REV_TT         = "Triggers an alert on changes of the trend's direction. If a delay is used, the alert will be delayed until the close has remained crossed over the stop for the number of minutes defined in the 'Delay' setting."
string UP_TT          = "Triggers an alert on a cross up of a short stop. If a delay is used, the alert will be delayed until the close has remained crossed over the stop for the number of minutes defined in the 'Delay' setting."
string DN_TT          = "Triggers an alert on a cross down of a long stop. If a delay is used, the alert will be delayed until the close has remained crossed under the stop for the number of minutes defined in the 'Delay' setting."
string SEC_TT         = "Minutes for which price must breach the line before an alert triggers. Use '0.5' for 30 seconds."
string EDN_TT         = "Triggers an alert on an 'Early Breach' cross up of a higher timeframe short stop. If a delay is used, the alert will be delayed until the close has remained crossed above the stop for the number of minutes defined in the 'Delay' setting."
string EUP_TT         = "Triggers an alert on an 'Early Breach' cross down of a higher timeframe long stop. If a delay is used, the alert will be delayed until the close has remained crossed below the stop for the number of minutes defined in the 'Delay' setting."


string GRP1           = "═════════ Stop Calculations ═════════"
float  srcInput       = input.source(close, "Source",     group = GRP1)
int    lenInput       = input.int(20,       "Length",     group = GRP1, minval = 2)
float  atrInput       = input.float(2.0,    "ATR Factor", group = GRP1, minval = 0.25, step = 0.25)

string GRP2                = "══════════  HTF Selection  ══════════"
string typeInput           = input.string(TF2,    "Higher Timeframe Selection",      group = GRP2, options = [TF0, TF1, TF2, TF3])
float  type2Input          = input.float(3.,      "  Multiple of Current TF",        group = GRP2, minval  = 1)
string type3Input          = input.timeframe("D", "  Fixed TF",                      group = GRP2)
bool   detectBreachesInput = input.bool(true,     "Detect Breaches By Chart Bars",   group = GRP2)
bool   breachesMrkrInput   = input.bool(true,     "  Show Chart Breaches",           group = GRP2)
bool   breachedBarsInput   = input.bool(false,    "  Color Bars in Limbo",           group = GRP2)
bool   breachedBgInput     = input.bool(false,    "  Highlight Background in Limbo", group = GRP2)
bool   repaintsInput       = input.bool(false,    "Repainting HTF",                  group = GRP2)

string GRP3           = "═════════  Alert Conditions  ═════════"
bool   revInput       = input.bool(false, "Trend Reversal",                group = GRP3, tooltip = REV_TT)
bool   upInput        = input.bool(false, "Change to Uptrend",             group = GRP3, tooltip = UP_TT)
bool   dnInput        = input.bool(false, "Change to Downtrend",           group = GRP3, tooltip = DN_TT)
bool   eDnInput       = input.bool(false, "Chart Breach of HTF Downtrend", group = GRP3, tooltip = EDN_TT)
bool   eUpInput       = input.bool(false, "Chart Breach of HTF Uptrend",   group = GRP3, tooltip = EUP_TT)
float  delayInput     = input.float(0.0,  "Delay in Minutes",              group = GRP3, tooltip = SEC_TT, minval = 0.0, step = 0.5)
string freqInput      = input.string(A1,  "Alert Frequency",               group = GRP3, options = [A1, A2])

string GRP4           = "════════════  Visuals  ═══════════"
string colSchemeInput = input.string(CS1, "Color Scheme",              group = GRP4, options = [CS0, CS1])
string styleInput     = input.string(ST0, "Style",                     group = GRP4, options = [ST0, ST1, ST2, ST3])
int    thicknessInput = input.int(2,      "Line Thickness",            group = GRP4, options = [0, 1, 2, 3])
bool   colorBarsInput = input.bool(false, "Color Bars on Trend State", group = GRP4)

string GRP5           = "═══════════  Display HTF  ══════════"
bool   showHTFInput   = input.bool(false,      "Show HTF Used",  group = GRP5)
string textSizeInput  = input.string("large",  "Text Size",      group = GRP5, tooltip = SIZE_TT, options = [SI1, SI2, SI3, SI4, SI5, SI6])
string tableYposInput = input.string("bottom", "Position  ",     group = GRP5, tooltip = POS_TT,  options = [TP1, TP2, TP3], inline = "41")
string tableXposInput = input.string("right",  "",               group = GRP5,                    options = [TP4, TP5, TP6], inline = "41")


bool defaultScheme    = colSchemeInput == CS0
bool showCircles      = styleInput     == ST1
bool showDiamonds     = styleInput     == ST2
bool showArrows       = styleInput     == ST3
bool htfOn            = typeInput      != TF0
// }



// ———————————————————— Functions {


// @function        Calculates a value from the ATR, which is offset from price action to use as a stop loss or trend detection. 
// @param source    (series int/float) The source to calculate the stop value from.  
// @param atrLength (simple int) The length over which to calcualte the RMA of the true range. (number of bars back).
// @param atrInput (series int/float) A multiplier to allow adjustment of the stop as a function of the ATR value. Example: 1 is 100% of the calculated ATR value. 
// @param offset    (series int) The first half of the offset calculations required to achieve repainting/non-repainting data when used in `request.security()`.
// @returns         ([float, bool]) A tuple of the volatility stop value and the trend direction as a bool. 
vStop(series float source, simple int atrLength, series float atrInput, series int offset = 0) =>
    float src = nz(source, close)
    var bool  trendUp = true
    var float max = src
    var float min = src
    var float stop = 0.0
    float atrM  = nz(ta.atr(atrLength) * atrInput, ta.tr)
    max  := math.max(max, src)
    min  := math.min(min, src)
    stop := nz(trendUp ? math.max(stop, max - atrM) : math.min(stop, min + atrM), src)
    trendUp := src - stop >= 0.0
    if trendUp != nz(trendUp[1], true)
        max  := src
        min  := src
        stop := trendUp ? max - atrM : min + atrM
    [stop[offset], trendUp[offset]]


// @function        Converts a timeframe in minutes to a next step higher timeframe. 
// @param tf        (simple int) Timeframe in minutes.    
// @returns         Returns a higher step timeframe from the input `tf`. 
tfNextStep(simple int tf) =>
    string result = switch 
        tf <= 1     => "60" 
        tf <= 60    => "1D" 
        tf <= 360   => "3D" 
        tf <= 1440  => "1W" 
        tf <= 10080 => "1M" 
        =>             "12M"
// }



// ———————————————————— Calculations {


// Get current tf in minutes.
int tfInSec = timeframe.in_seconds()

// Get HTF from user-defined mode.
string htf = switch typeInput 
    TF1 => tfNextStep(tfInSec / 60) 
    TF2 => pcTimeLib.secondsToTfString(tfInSec, type2Input) 
    =>     type3Input

// ————— Stop calcs
int offset = not htfOn ? 0 : not repaintsInput and barstate.isrealtime ? 1 : 0
[stopChartTf, trendUpChartTf] = vStop(srcInput, lenInput, atrInput, offset)

[stopSec, trendUpSec] = request.security(syminfo.tickerid, htf, [stopChartTf, trendUpChartTf])

float stopHTF    = stopSec[repaintsInput or barstate.isrealtime ? 0 : 1] 
bool  trendUpHTF = trendUpSec[repaintsInput or barstate.isrealtime ? 0 : 1] 

float stop       = not htfOn ? stopChartTf    : stopHTF
bool  trendUp    = not htfOn ? trendUpChartTf : trendUpHTF
var bool inLimbo = false

// Get conditions for colors, plotting, and alerts.
bool trendReversal   = trendUp != trendUp[1]
bool trendChangeToUp = trendUp and not trendUp[1]
bool trendChangeToDn = not trendUp and trendUp[1]
bool htfBreach       = htfOn and detectBreachesInput and not inLimbo and ta.cross(close, stop)
bool earlyBreachUp   = htfBreach and not trendReversal and trendUp
bool earlyBreachDn   = htfBreach and not trendReversal and not trendUp
inLimbo := (inLimbo or htfBreach) and trendUp == trendUp[1]

// Get duration of each condition.
float secondsUp  = pcTimeLib.secondsSince(trendChangeToUp, false)
float secondsDn  = pcTimeLib.secondsSince(trendChangeToDn, false)
float secondsEBU = pcTimeLib.secondsSince(earlyBreachUp,   false)
float secondsEBD = pcTimeLib.secondsSince(earlyBreachDn,   false)

// Timed alerts. 
bool alertUp      = secondsUp  >= delayInput * 60
bool alertDn      = secondsDn  >= delayInput * 60
bool alertRev     = alertUp    or alertDn
bool alertEarlyUp = secondsEBU >= delayInput * 60
bool alertEarlyDn = secondsEBD >= delayInput * 60
// }



// ———————————————————— Plots {


// ————— Coloring
color colorUp      = inLimbo  ? defaultScheme ? DARKLIME : DEEPBLUE : defaultScheme ? GREEN1  : DEEPSKY
color colorDown    = inLimbo  ? defaultScheme ? DARKRED  : DARKPINK : defaultScheme ? RED1    : DEEPPINK
color schemeColor  = inLimbo  ? defaultScheme ? trendUp  ? DARKLIME : DARKRED       : trendUp ? DEEPBLUE : 
                     DARKPINK : defaultScheme ? trendUp  ? GREEN1   : RED1          : trendUp ? DEEPSKY  : DEEPPINK
color lineColor    = trendReversal or htfBreach ? CLEARBLACK : schemeColor

// ————— Plotting

// Diamonds and arrows. 
plotshape(showDiamonds or showCircles ? stop : na, "Diamonds & Circles", showDiamonds ? shape.diamond : shape.circle, location.absolute, schemeColor)
plotchar(showArrows and trendUp ? stop : na, "Arrows Up", "⮝", location.absolute, colorUp)
plotchar(showArrows and not trendUp ? stop : na, "Arrows Dn", "⮟", location.absolute, colorDown)

// Line and beginning circles.
plot(thicknessInput != 0 ? stop : na, "V-Stop", lineColor, thicknessInput)
plot(trendReversal  ? stop : na, "Beg. Circle", schemeColor, math.max(thicknessInput, 1) + 2, plot.style_circles)
plot(trendReversal  ? stop : na, "Beg. Small circle", #000000ff, math.max(thicknessInput, 1), plot.style_circles)

// Early breaches.
plotshape(breachesMrkrInput and earlyBreachUp, "Breach of HTF Uptrend", shape.triangledown, location.abovebar, RED1, size = size.tiny)
plotshape(breachesMrkrInput and earlyBreachDn, "Breach of HTF Downtrend", shape.triangleup, location.belowbar, RED1, size = size.tiny)

// Bars.
bool barUp = close > open
barcolor(breachedBarsInput and inLimbo ? barUp ? ORANGE : DARKORANGE : not colorBarsInput ? na : trendUp ? barUp ? GREEN1 : DARKLIME : barUp ? RED1 : DARKRED)

// Background.
bgcolor(breachedBgInput and inLimbo ? color.new(color.silver, 90) : na)

// Create error if tf is greater than tf requested by security. 
if htfOn and tfInSec >= timeframe.in_seconds(htf)
    runtime.error("Chart timeframe must be < " + htf)

// Display tf using a table. 
if barstate.islastconfirmedhistory and htfOn and showHTFInput
    // Declare a basic table once.
    var table tfDisplay = table.new(tableYposInput + "_" + tableXposInput, 1, 1)
    // Set table to show tf on last historical bar.
    table.cell(tfDisplay, 0, 0, htf, text_color = color.silver, text_size = textSizeInput)
// }



// ———————————————————— Alerts {


bool  timed    = delayInput != 0 
float duration = trendChangeToUp ? secondsUp : secondsDn


if alertRev and revInput
    string alertMsg = "Trend Reversal. " + (timed ? "Close crossed stop for " + str.tostring(duration / 60, "#.##m") : "")
    alert(alertMsg, freqInput)

if alertUp and upInput
    string alertMsg = "Change to uptrend. " + (timed ? "Close was above stop for " + str.tostring(secondsUp / 60, "#.##m") : "")
    alert(alertMsg, freqInput)
  
if alertDn and dnInput
    string alertMsg = "Change to downtrend. " + (timed ? "Close was below stop for " + str.tostring(secondsDn / 60, "#.##m") : "")
    alert(alertMsg, freqInput)

if alertEarlyUp and eUpInput
    string alertMsg = "Chart breach of HTF uptrend. " + (timed ? "Close was below stop for " + str.tostring(secondsEBU / 60, "#.##m") : "")
    alert(alertMsg, freqInput)

if alertEarlyDn and eDnInput
    string alertMsg = "Chart breach of HTF downtrend. " + (timed ? "Close was above stop for " + str.tostring(secondsEBD / 60, "#.##m") : "")
    alert(alertMsg, freqInput)
// }

Overview

The higher timeframe is picked in discrete steps, as a multiple of the chart timeframe, or as a fixed timeframe. It can detect when chart bars breach the higher timeframe stop, mark those breaches, colour bars or the background, and trigger alerts with an optional delay. A repainting option exists for the higher timeframe values, and an optional table shows the timeframe used.

Details

Published by

ivansoft on GitHub

Code credit

TradingView, as written in the script's header

Draws

On the price chart

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.

Topics

pinescripttradingvew

Settings

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

SettingTypeDefaultVariable
SourcesourceclosesrcInput
Lengthint20lenInput
ATR Factorfloat2.0atrInput
Higher Timeframe SelectionstringTF2typeInput
  Multiple of Current TFfloat3.type2Input
  Fixed TFtimeframeDtype3Input
Detect Breaches By Chart BarsbooltruedetectBreachesInput
  Show Chart BreachesbooltruebreachesMrkrInput
  Color Bars in LimboboolfalsebreachedBarsInput
  Highlight Background in LimboboolfalsebreachedBgInput
Repainting HTFboolfalserepaintsInput
Trend ReversalboolfalserevInput
Show all 26 settings
SettingTypeDefaultVariable
Change to UptrendboolfalseupInput
Change to DowntrendboolfalsednInput
Chart Breach of HTF DowntrendboolfalseeDnInput
Chart Breach of HTF UptrendboolfalseeUpInput
Delay in Minutesfloat0.0delayInput
Alert FrequencystringA1freqInput
Color SchemestringCS1colSchemeInput
StylestringST0styleInput
Line Thicknessint2thicknessInput
Color Bars on Trend StateboolfalsecolorBarsInput
Show HTF UsedboolfalseshowHTFInput
Text SizestringlargetextSizeInput
Position  stringbottomtableYposInput
tableXposInputstringrighttableXposInput
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

Chandelier Exit

by everget
947 stars

This indicator plots an ATR-based Chandelier Exit trailing stop on the price chart. It tracks a long stop under recent highs and a short stop above recent lows, then switches direction when price crosses the opposite stop. Buy and sell labels mark those flips.

Indicator v6 Volatility & bandsTrend Repaints
Updated 11 days ago · GPL-3.0 GitHub repository of Chandelier Exit

The Momentum Setup is a multi-indicator visual tool designed for trend and momentum analysis directly on the price chart. It combines Relative Strength Index (RSI), Money Flow Index (MFI), Commodity Channel Index (CCI), Supertrend, and a 250-bar percentage cha

Indicator v5 Oscillators & momentumTrend
Updated 1 year ago · MPL-2.0 GitHub repository of Momentum Setup - Ankush Bajaj Momentum Investing Setup
330 stars

Range Filter [Alorse] is a technical indicator overlay for TradingView designed to filter market volatility and identify price trends. It calculates a smoothed range based on historical volatility using a configurable sampling period and multiplier applied to

Indicator v5 TrendVolatility & bands
Updated 2 months ago · None stated GitHub repository of Range Filter [Alorse]
318 stars

This indicator calculates an ATR trailing stop line derived from the highest high minus an average true range multiple over a specified lookback period. It plots the trailing stop line directly on the price chart and colors price bars based on whether the clos

Indicator v5 TrendVolatility & bands
Updated 2 months ago · MIT GitHub repository of ATR Trailing Stoploss

NVDA Trend Ribbon

by longsurf-ai
280 stars

This indicator plots three exponential moving averages and ATR volatility envelopes on the price chart. It compares the fast and slow EMAs to shade a trend ribbon and marks confirmed upward and downward crossovers with triangle labels. Settings change the thre

Indicator v6 TrendMoving averages
Updated 2 days ago · MIT GitHub repository of NVDA Trend Ribbon

[RS]Donchian Fans

by ricardosantos79
261 stars

This indicator plots Donchian Channel boundary lines along with dynamic fan projections directly on the price chart. It calculates the highest high, lowest low, and median price over a customizable lookback period. Whenever price establishes a new channel high

Indicator v4 Support & resistanceTrend
Updated 4 years ago · None stated GitHub repository of [RS]Donchian Fans

More Volatility & bands scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

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

Compare brokers