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
# 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;
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);
#
# 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";
# BLOCK CODE BELOW
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:

diazlaz

Well-known member
2019 Donor
VIP
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
#https://www.tradingview.com/script/oRK5JwIm-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:

john3

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.
 

diazlaz

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

HMNhbaj.png


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.
#
#LINK
#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
AddLabel(showLabels,
 if isLong then "(VT) LONG" else "(VT) SHORT",
 if isLong then COLOR.GREEN else COLOR.RED);

#END OF Volatility Stops (VT)
 

diazlaz

Well-known member
2019 Donor
VIP
@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
 

Trading51

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

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

diazlaz

Well-known member
2019 Donor
VIP
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
#https://www.tradingview.com/script/mjBdRGXe-Chandelier-Stop/

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

retro31337

New member
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

zOiU1DM.png


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?
 

MerryDay

Administrative
Staff member
Staff
VIP
Lifetime
@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...
 

jpmcewen

Member
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
been cited for COPYRIGHT INFRINGEMENT.

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:

Similar threads

Top