# Volatility Based Trailing Stop for ThinkorSwim

#### Miket

##### Member
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.

https://tos.mx/mE3lJU

### thinkScript Code

Code:
``````# Volatility-Based Trailing Stop
#
# 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;
switch(Style){
case Close:
type=1;
case HighLow:
type=0;
}
#
# 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:
#
long.SetDefaultColor(color.dark_green);
long.SetStyle(curve.points);
long.SetLineWeight(5);
short.SetDefaultColor(color.dark_red);
short.SetStyle(curve.points);
short.SetLineWeight(5);
#
#
def alerttrigger= if direction[1]<=0 and longswitch then 1
else if direction[1]>=0 and shortswitch then 1 else 0;
# BLOCK CODE BELOW
input UseAlerts = {false, default true};
input AlertType = {default "BAR", "ONCE", "TICK"};
input AlertSound = {"Bell", "Chimes", default "Ding", "NoSound", "Ring"};

Last edited by a moderator:
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?

Code:
``````#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:
"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.

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

Ruby:
``````#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.
#
#https://www.motivewave.com/studies/volatility_stops.htm
#
#INSTRUCTION
#set isLong to yes or no. default is long yes. (set to no for short)
#

declare upper;

#INPUTS
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;

#LOGIC
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;

# ARROWS
plot pUP = showArrows and buy;
pUP.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
pUP.SetDefaultColor(Color.GREEN);
pUP.SetLineWeight(2);

plot pDown = showArrows and sell;
pDown.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
pDown.SetDefaultColor(Color.RED);
pDown.SetLineWeight(2);

#PLOTS
plot pVT = vs;
pVT.SetPaintingStrategy(PaintingStrategy.POINTS);
pVT.SetDefaultColor(GetColor(5));

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

#END OF Volatility Stops (VT)``````

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

@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

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

Code:
``````## Line
input arbitrary_number = 2800;

plot data2 = arbitrary_number;

data2.hide();

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);

data3.setpaintingStrategy(paintingStrategy.LINE_VS_TRIANGLES);

data3.setdefaultColor(color.gray);

data3.setlineWeight(2);``````

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

Ruby:
``````#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.setpaintingStrategy(paintingStrategy.LINE_VS_TRIANGLES);
pLevel1.setdefaultColor(color.gray);
pLevel1.setlineWeight(2);
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.setpaintingStrategy(paintingStrategy.LINE_VS_TRIANGLES);
plevel2.setdefaultColor(color.gray);
plevel2.setlineWeight(2);
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.setpaintingStrategy(paintingStrategy.LINE_VS_TRIANGLES);
plevel3.setdefaultColor(color.gray);
plevel3.setlineWeight(2);
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.setpaintingStrategy(paintingStrategy.LINE_VS_TRIANGLES);
plevel4.setdefaultColor(color.gray);
plevel4.setlineWeight(2);
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.setpaintingStrategy(paintingStrategy.LINE_VS_TRIANGLES);
plevel5.setdefaultColor(color.gray);
plevel5.setlineWeight(2);
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.setpaintingStrategy(paintingStrategy.LINE_VS_TRIANGLES);
plevel6.setdefaultColor(color.gray);
plevel6.setlineWeight(2);
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``````

I found a chandelier trailing stop on tradingview that I thought looked good code-wise and converted it to thinkorswim. I changed the ATR length period to 7 because 22 didn't make sense. Also it becomes Wilder's original volatility stop if you change both the lowest low and highest high to just closing prices, and you make the ATR length the same as the lookback length.
Code:
``````#Chandelier Volatility Trailing Stop

#SparkyFlary

#Code taken and re-edited to thinkorswim from pipCharlie, who got it from LazyBear

input AtrMult = 3.0;
input ATRlength = 7;
input lookbackLength = 22;
input highestHigh = high;
input lowestLow = low;
input AvgType = AverageType.WILDERS;
input PaintBars = no;

def ATR = MovingAverage(AvgType, TrueRange(high, close, low), ATRlength);
def longstop = Highest(highestHigh,lookbackLength)-AtrMult*atr;
def shortstop = Lowest(lowestLow,lookbackLength)+AtrMult*atr;

def shortvs = if isNaN(shortvs[1]) then shortstop else if close>shortvs[1] then shortstop else min(shortstop,shortvs[1]);
def longvs = if isNaN(longvs[1]) then longstop else if close<longvs[1] then longstop else max(longstop,longvs[1]);

def longswitch= if close>=shortvs[1] and close[1]<shortvs[1] then 1 else 0;
def shortswitch = if close<=longvs[1] and close[1]>longvs[1] then 1 else 0;

def direction = 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];

def pc = if direction>0 then longvs else shortvs;

plot VolatilityStop = pc;
VolatilityStop.AssignValueColor(if direction < 0 then Color.RED else Color.GREEN);
AssignPriceColor(if PaintBars and direction < 0
then Color.RED
else if PaintBars and direction > 0
then Color.GREEN
else Color.CURRENT);``````

This is great, exactly what I was looking for! Does this script automatically enter a buy/sell order when you have an open position and the price crosses the indicator line? If not, how do I set that up?

So - from my screenshot - this keeps me in a long position even after 4 down candles - Please see screenshot

I am grateful for any comments

Thank you for your reply - I should have asked - why isn't the indicator turning red dots once the pullback starts? Or am I misunderstanding the purpose of the indicator?

@MatthewTherrien Ahhhh... And therein lies the definition of lagging indicators. They are slow to get in on the party and they are slow to leave...

Just to add to the collection...Volatility Trailing Stop by Steve Coombs

Where I found it

This post (Volatility Trailing Stop by Steve Coombs) has

While Scribd offers the use of this indicator. The agreement upon download is that it will not be shared.

Please do not post proprietary content.

Last edited by a moderator:
I have a Volatilty Stop indicator (Similar to ATR Trailing Stop) I would like to smooth out like a moving average (ex 20-Exp MA). Anyone could assist.

Thank you kindly
## Volatility Trailing Stop
## Version 1.1
## By Steve Coombs
## This ATR Trailing Stop is calculated using the Highest Close in an uptrend or
## the Lowest Close in a downtrend, rather than just the Close that is used
## in the standard TOS ATRTrailing Stop

Where I found it

This post (Volatility Trailing Stop by Steve Coombs) has

While Scribd offers the use of this indicator. The agreement upon download is that it will not be shared.

Please do not post proprietary content.

Last edited by a moderator:
Didn't know it was proprietary. My Apologies

87k+ Posts
322 Online

## The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
• Exclusive indicators
• Proven strategies & setups
• Private Discord community
• Exclusive members-only content
• 1 full year of unlimited support

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?