Volatility Based Trailing Stop for ThinkorSwim


This Thinkscript indicator is a volatility-based trailing stop, similar to the Chandelier Stop. When direction switches from short to long (or vice versa), the initial stop level is a specified number of multiples of the Average True Range (ATR) of the last ‘n’ bars. Then the value is trailed, getting tighter should volatility decrease or price move to new extremes. A close through the stop level signifies a trend change in this indicator; crossing the value and closing back on the other side does not.


thinkScript Code

# Volatility-Based Trailing Stop
# By Prospectus @ http://readtheprospectus.wordpress.com
# Input Declarations:
input mult = 3.0; #Multiple of Average True Range to use
input length = 10; #Average True Range period
# Input to select Close or High/Low for switching:
input Style={default Close, HighLow};
def type;
case Close:
case HighLow:
# Set parameters based on switch selection:
def uu=if type then close else high;
def ll=if type then close else low;
def na=double.nan;
# Calculate average range for volatility:
def atr = expaverage(high-low,length);
# Calculate initial short and long volatility stop values:
def svs =low+ceil(mult*atr/ticksize())*ticksize();
def lvs =high-ceil(mult*atr/ticksize())*ticksize();
# Set up the trailing stop logic:
rec shortvs=if isnan(shortvs[1]) then svs else if uu>shortvs[1] then svs else min(svs,shortvs[1]);
rec longvs=if isnan(longvs[1]) then lvs else if ll<longvs[1] then lvs else max(lvs,longvs[1]);
# Detect if we breached the trailing stop (close or high/low):
def longswitch=if uu>=shortvs[1] and uu[1]<shortvs[1] then 1 else 0;
def shortswitch=if ll<=longvs[1] and ll[1]>longvs[1] then 1 else 0;
# This logic remembers the direction and changes when needed:
rec direction= compoundvalue(1,if isnan(direction[1]) then 0 else
if direction[1]<=0 and longswitch then 1
else if direction[1]>=0 and shortswitch then -1
else direction[1],0);
# Set up the two plots. "na" makes the current value disappear
# if we�re trading in the opposite direction:
plot short=if direction>0 then na else shortvs;
plot long=if direction<0 then na else longvs;
# Formatting:
# Alerts:
def alerttrigger= if direction[1]<=0 and longswitch then 1
else if direction[1]>=0 and shortswitch then 1 else 0;
input alerttext="Alert Text";
input UseAlerts = {false, default true};
input AlertType = {default "BAR", "ONCE", "TICK"};
def at=AlertType;
input AlertSound = {"Bell", "Chimes", default "Ding", "NoSound", "Ring"};
alert(alerttrigger AND UseAlerts, alerttext, if at==1 then Alert.ONCE else if at==2 then Alert.TICK else Alert.BAR, AlertSound);
Last edited by a moderator:


New member
Hi Thanks.
Is there a script to allow to show both sides of this ATR stop or any other ATR stop?


Well-known member
2019 Donor
Hi Everyone.

what do you think? is this similar or equivalent to the Vol Stop in trading view? with all the VIX work and trading system, this indicator comes up as a way to exit the trades. if not, is it worth porting?

#Volatility Stop
study("Volatility Stop", shorttitle="VStop", overlay=true)
length = input(20)
mult = input(2)
atr_ = atr(length)
max1 = max(nz(max_[1]), close)
min1 = min(nz(min_[1]), close)
is_uptrend_prev = nz(is_uptrend[1], true)
stop = is_uptrend_prev ? max1 - mult * atr_ : min1 + mult * atr_
vstop_prev = nz(vstop[1])
vstop1 = is_uptrend_prev ? max(vstop_prev, stop) : min(vstop_prev, stop)
is_uptrend = close - vstop1 >= 0
is_trend_changed = is_uptrend != is_uptrend_prev
max_ = is_trend_changed ? close : max1
min_ = is_trend_changed ? close : min1
vstop = is_trend_changed ? is_uptrend ? max_ - mult * atr_ : min_ + mult * atr_ : vstop1
plot(vstop, color = is_uptrend ? green : red, style=cross, linewidth=2)
Last edited:


Active member
2019 Donor
"input Style={default Close, HighLow};"

My understanding based on the code is that it can be set based on the Close or High/Low, but for what period?

Also, can someone convert this to TOS? https://www.motivewave.com/studies/volatility_stops.htm The one from MotiveWave is based on a price action around a moving average, which seems more straightforward and useful since most trading systems use popular MAs.


Well-known member
2019 Donor
there has been interest in Volatility Stops (VT) indicators recently, @john3 here is a port of the VT as requested:


#Volatility Stops (VT) from MotiveWave V1.2
#VT was authored by Welles Wilder. The VT identifies exit points for
#long and short positions. First, an exponential moving average (EMA)
#of the input is taken to determine the current trend. Then,
#the Average True Range (ATR) is calculated and multiplied by a user
#defined factor.
#If the EMA is increasing (uptrend), the ATR product is subtracted
#from the highest price for the period or, if the EMA is decreasing
#(down trend), it is added to the lowest price for the period.
#This final value of the VT is displaced to one future bar.
#The user may change the position (long), input (close), method (EMA)
#period lengths and percent factor.
# @john3 request
# 2019.12.16 @diazlaz - initial port/interpretation.
#set isLong to yes or no. default is long yes. (set to no for short)

declare upper;

input isLong = yes; #user defined, default is long (set to no for short)
input price = close;
input maP = 63;
input atrP = 21;
input fac = 3;
input showArrows = yes;
input showLabels = yes;

def longP = isLong;
def shortP  = !isLong;
def ma = ExpAverage(price, maP);

def upTrend = price > ma;
def dnTrend = price <= ma;

def na = Double.NaN;

def atrUp;
def atrDn;
def sic;
def vstop;

if (longP and upTrend) then {
    atrUp = ATR(atrP);
    atrDn = na;
    sic = highest(price, atrP);
    vstop = sic - (fac * atrUp);
} else
if (shortP AND dnTrend) then {
    atrUp = na;
    atrDn = ATR(atrP);
    sic = lowest(price, atrP);
    vstop = sic + (fac * atrDn);
} else {
    atrUp = na;
    atrDn = na;
    sic = na;
    vstop = na;

def prevP = price[1];
def vs = if !isNaN(vstop) then vstop else vs[1];
def sell = prevP > vs AND price < vs AND longP AND upTrend;
def buy = prevP < vs AND price > vs AND shortP AND dnTrend;

plot pUP = showArrows and buy;

plot pDown = showArrows and sell;

plot pVT = vs;

 if isLong then "(VT) LONG" else "(VT) SHORT",
 if isLong then COLOR.GREEN else COLOR.RED);

#END OF Volatility Stops (VT)


Well-known member
2019 Donor
@Trading51, thank you, I appreciate it. Just to confirm, the default settings are EMA 63, ATR Period 21, ATR Factor 3. Correct?

Correct. Feel free to try different settings and timeframes.

//position = pos, user defined, default is long
//input = price, user defined, default is close
//method = moving average (ma), user defined, default is EMA
//period1 = maP, user defined, default is 63
//period2 = artP, user defined, default is 21
//factor = fac, user defined, default is 3
//art = Average True Range
//index = current bar number, prev = previous
//shortP = short position, longP = long position


Active member
2019 Donor
@diazlaz, I have a code that plots one Horiztonla line like a fixed level, i wanted to have a few more lines added like this do you think you could do it if I post the code thansk a bunch


Active member
2019 Donor
Sure please post and we will try.
This is it, I want to be able to have at least 5 specific areas that i can have marked off sort of like my own pivot the main area and 2 levels above and 2 levels below below is the code

## Line
input arbitrary_number = 2800;

plot data2 = arbitrary_number;


plot data3 = highestall(if isnan(close[-1])then round(data2[1] / ticksize(),0) * ticksize()                        else double.nan);

addchartBubble(isnaN(close[3]) && !isnaN(close[4]),"price location" = data3, text = "Price = " + data3, color = Color.White);





Well-known member
2019 Donor
Hi @Trading51, what you can do also, is save this as a study, then add it to your chart as many times as many mark off zones you need in the chart. then edit the arbitrary number with the levels that you want to show in the chart.

will this work for you?


Active member
2019 Donor
Hi @Trading51, what you can do also, is save this as a study, then add it to your chart as many times as many mark off zones you need in the chart. then edit the arbitrary number with the levels that you want to show in the chart.

will this work for you?
i was thinking one indictor with a few inputs verse having to load that many indicators not sure if its an overload having 5 plus other indicators, if you can do it, it would be cool


Well-known member
2019 Donor
Here you go @Trading51, please set the input to greater than 0 and it will render up to 6 manual S&R lines.

#Manual S&R
# @diazlaz - 2019.12.19 - uTS request

declare upper;

input level1 = 2800;
input level2 = 0;
input level3 = 0;
input level4 = 0;
input level5 = 0;
input level6 = 0;

def sLevel1 = level1;
def sLevel2 = level2;
def sLevel3 = level3;
def sLevel4 = level4;
def sLevel5 = level5;
def sLevel6 = level6;

#level 1
plot pLevel1 = highestall(if isnan(close[-1])then round(sLevel1[1] / ticksize(),0) * ticksize() else double.nan);
pLevel1.SetHiding(!level1 > 0);
addchartBubble(isnaN(close[3]) && !isnaN(close[4]),"price location" = pLevel1, text = "Price = " + pLevel1, color = Color.White);

#level 2
plot plevel2 = highestall(if isnan(close[-1])then round(slevel2[1] / ticksize(),0) * ticksize() else double.nan);
plevel2.SetHiding(!level2 > 0);
addchartBubble(isnaN(close[3]) && !isnaN(close[4]),"price location" = plevel2, text = "Price = " + plevel2, color = Color.White);

#level 3
plot plevel3 = highestall(if isnan(close[-1])then round(slevel3[1] / ticksize(),0) * ticksize() else double.nan);
plevel3.SetHiding(!level3 > 0);
addchartBubble(isnaN(close[3]) && !isnaN(close[4]),"price location" = plevel3, text = "Price = " + plevel3, color = Color.White);

#level 4
plot plevel4 = highestall(if isnan(close[-1])then round(slevel4[1] / ticksize(),0) * ticksize() else double.nan);
plevel4.SetHiding(!level4 > 0);
addchartBubble(isnaN(close[3]) && !isnaN(close[4]),"price location" = plevel4, text = "Price = " + plevel4, color = Color.White);

#level 5
plot plevel5 = highestall(if isnan(close[-1])then round(slevel5[1] / ticksize(),0) * ticksize() else double.nan);
plevel5.SetHiding(!level5 > 0);
addchartBubble(isnaN(close[3]) && !isnaN(close[4]),"price location" = plevel5, text = "Price = " + plevel5, color = Color.White);

#level 6
plot plevel6 = highestall(if isnan(close[-1])then round(slevel6[1] / ticksize(),0) * ticksize() else double.nan);
plevel6.SetHiding(!level6 > 0);
addchartBubble(isnaN(close[3]) && !isnaN(close[4]),"price location" = plevel6, text = "Price = " + plevel6, color = Color.White);

#END OF Manual S&R


Active member
2019 Donor
This is perfect thanks a bunch for taking the time have a great weekend Merry Christmas & Happy Holiday

Is it possible to get these horizontal lines to sit to the right of the chart by a smaller margin verse across the whole chart? If it's minor you can post the input and I can update it, either way, let me know and thanks again

is there an input for the code that I could add that would make the price sit to the right of the chart verse across the whole chart, not sure if it's complicated adjusting the code? thanks


Active member
2019 Donor
Hi @Trading51, so you would like to limit the lines to the right and to the left only by a number of bars to the left? is that correct?
yes, verse across the whole chart, i was thinking like 10 bar are so enough to see the price level.

hello, any chance of getting these lines shorter and sitting to the right of the chart? thanks a bunch

Similar threads