Volatility-Based Trailing Stop for Think or Swim

UPDATE 18 May 2009: Fixed error as noted in comments below (Thanks, Jeff!)

UPDATE 23 Feb 2009: Added option to use High/Low as well as Close as the volatility stop switching trigger. Also changed “AverageTrueRange” to exponential average of High-Low so it works on tick charts.


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.

The part of this indicator that was tricky is the trailing stop logic, as well as switching the direction of the indicator–long or short. Thinkscript runs in very linear fashion, and you can’t define an indicator at one point and then change the value at another point. The workaround is to put complicated logic gates into the definition itself.

There are two inputs here: The ATR factor, and the length for the ATR calculation. These can be reset from the studies window without changing the Thinkscript. If you want a different default value, change the code below to the value you want.

The code can be found on my Google site.

Tags: , , ,

39 Responses to “Volatility-Based Trailing Stop for Think or Swim”

  1. AI Says:

    a very cool thing would be to have this atr stop based on heikin ashi candle values….. I would donate at least $50 to see that happen thanks =)

  2. Prospectus Says:

    I’ll get on that soon, then!

  3. evolnomis Says:

    thanks a lot for the code. can you please explain to me the difference between the “close” setting and the “high/low close”? my guess is that it changes the price used when subtracting the ATR multiple from it.

    also, i calculated some stops based on ATR and the high price of the current leg but the values are different from yours. i tried it with both “average true range” and “ATRwilder” but still the numbers are off. instead of getting a 2.5 ATR factor with the code’s results, they are more like 3-3.5. can you please help explain this? thanks.

  4. Prospectus Says:


    The setting of “High/Low” and “Close” is for the reversal logic. If set to “Close”, it won’t reverse direction unless a candle closes across the stop level. On “High/Low”, if price touches the stop, the indicator will reverse. This way it acts truly like a stop loss order.

    My script used to use the actual true range calculation, but for some reason Think or Swim’s ATR function didn’t work for me on tick charts. So I changed it to just an exponential average of the high-low. The ATR is different in that it takes gaps into account in the calculation by choosing the maximum of high-low or close-close[1]. On an intraday chart with no gaps, the calculation should be the same.

    One more subtlety is that the calculated “ATR” range in my indicator is multiplied by the factor and then subtracted from the opposite extreme. Say we just switched from short to long with a 2 ATR stop. You take that ATR, multiply by 2, then subtract it from that bar’s HIGH, not that bar’s low. Like the chandelier stop, the stop is hung from the highest point in the direction of the indicator. A new high will result in the stop moving up. A volatility contraction will also result in a smaller move up. As it’s a trailing stop, it can never move in the opposite direction of the trade.

    Hope that clarifies a bit!

  5. Tutorial: Trailing Stop Strategies for Think or Swim « Read the Prospectus Says:

    […] way to make trailing stop strategies work is similar to the way I made my “Volatility-based trailing stop” indicator. The key is to reproduce the entry logic in your stop strategy routine. In that indicator, I had […]

  6. Jeff J Says:


    After looking at your volatility based trailing stop, I think I found an error in the code. From your explanation from 5/1/09, you state,”One more subtlety is that the calculated “ATR” range in my indicator is multiplied by the factor and then subtracted from the opposite extreme. Say we just switched from short to long with a 2 ATR stop. You take that ATR, multiply by 2, then subtract it from that bar’s HIGH, not that bar’s low.” From the code posted above”def lvs = low – mult*atr;”. With this code(I think) it is calculating the long vol stop from the low of the candle not the high. When I change it to “def lvs = high – mult*atr;” it changes the stop value to one that matches if I calculate it manaully using Tos ATR. This also means that SVS needs to be changed. Please let me know if I am looking at this incorrectly. Thanks

  7. Prospectus Says:

    Holy crap, Jeff, you are correct. Good catch! Thanks for pointing it out. I mean, I was testing you all, yes, testing you…

    I’ve updated the code on my Google site.

  8. Andy Says:

    To take this indicator to the next level, it should have a mechanism to tighten the ATR multiple as profits accrue. For this example upon, say we just switched to LONG entry:

    * Switch day – trail with a 3 ATR multiple
    * After 3 ATRs of profit since the Switch day, tighten the trail to a 2 ATR multiple
    * After 5 ATRs of profit since the Switch day, tighten the trail to a 1 ATR multiple


  9. Jeff J Says:

    I agree with Andy. If that is possible in Thinkscript, I would love it.

    Jeff J

  10. Andy Says:

    I have incorporated Prospectus’ most excellent Volatility TS indicator onto the TOS graphs… but am unable to use it for setting up Alerts (even with the new release from this weekend, which allows complex studies).

  11. Prospectus Says:

    Wow, sounds like I have some work to do! I’m on vacation over the next week and a half, and I’ve got some comissioned work backed up on me, but I’ll get to this too as I can.

  12. Dan Says:

    I enjoy reading your posts. I’ve scripted a few strategies and feel like I’m pretty proficient, but I admit I’m stuck trying to do a complex stop in TOS. Maybe you can tell me an approach to try.

    I call my stop a “head-fake” stop. You buy in, anticipating a reversal. Price slips a few cents, and you track the lowest low. Then price rises x% and you treat this as the reversal. You set a stop at the previous lowest low. If price falls back down then you guessed wrong and you’re stopped out.

    Problem is I can get lowest low…

    rec lowestLow = if trigger then
    if low[0] headFakePercentage then (lowestLow – 0.01)
    else 0;

    But they are at best moving targets. As soon as headFakeStop breaches Lowest low by x% then I want headFakeStop to quit changing. Do you have an approach that you use for this type of thing?

  13. Dan Says:

    Code above got mangled when I posted. Sorry, disregard it.

  14. Prospectus Says:


    Email me your code and I’ll take a look.

  15. Raph Says:

    Hi Prospectus! I have a request: Do you think you could post a thinkscript that will automatically change the background color or candlestick color (to differentiate it from other charts that are open side-by-side) where the previous candlestick’s open minus it’s close is less than or equal to 25% of it’s high minus it’s low? Thanks!

  16. Webby Says:

    Hi Prospectus, I was unable to get this to work with tick charts. I am using a 144T chart and changing the value to be be based on “HighLow” rather than “close” I was still unable to get the indicator to paint/display on the chart. It works fine in minutes though.

    Am I missing something else for tick chart setup ?

  17. Prospectus Says:

    It used to work on tick charts. It must have broken during the latest release. I’ll need to fix it.

  18. John Says:

    How do I get to version 2?

  19. Volatility-Based Trailing Stop Strategies for Think or Swim « Read the Prospectus Says:

    […] is my Volatility-Based Trailing Stop indicator implemented as strategies. These are only exit strategies at the moment, so if you use […]

  20. evolnomis Says:

    thank you again for the code.

    I am considering using this stop but got confused on what the “length” is…is the length the ATR value? and is mult = the multiple of the ATR below the high / low which is the stop price?


  21. Prospectus Says:

    Yes, length is the number of periods to calculate the ATR. Mult is a factor on the ATR.

  22. evolnomis Says:

    I tried to calculate the stop value myself and it never comes out exactly as your code.

    here is what i did on 1/22/11: (6month, daily chart of DIS)

    mult = 3.0, length = 10, style = high/low

    and when i did it myself:

    current high = 40
    ATR (10) value = 0.5705

    calculated stop = 40-(3*0.5705) = 38.2885

    code’s stop = 38.18

    it is off by quite a lot. can you tell me where my calculations are wrong? am i using the wrong ATR. i am just using the default “AverageTrueRange” on think of swim. also, why is the code’s calculations also very different from think or swim’s “ATRtrailing stop”? I thought they are the same concept.


  23. Prospectus Says:

    My ATR isn’t really an average true range. It’s an average of the (high-low) for the last N bars. For intraday charts it should be close, but on daily charts the average true range will take into account any gaps, while mine will not. So that’s probably the difference you are seeing.

  24. evolnomis Says:

    thank you so much for the quick reply.

    I love the interface of your code + want to use it over anything TOS has out there. the best part is the ability to use alerts + the custom fields.

    but i feel weird using a code that i can’t calculate quickly and precisely just from looking at the chart.

    would you happen to still have your old code that uses the standard ATR or know how i can tweak it to an ATR…I noticed in an above reply to me that you said originally you used the standard ATR.

    thank you!

  25. Raph Says:

    Is there code that can calcuate a 20 period (past 20 days) average of open minus closing prices range for Custom Studies in the Marketwatch tab? If not, is there code to make this into a “lower study” on a chart? Thanks!

  26. Prospectus Says:

    For a lower study on a daily chart:

    Declare lower; Def omc = open – close; Plot avg = average(omc,20);

    Marketwatch tab, this might work:


    If not, try this:

    (Open(period=”day”)[20] -Close(period=”day”)[20] + Open(period=”day”)[19] – Close(period=”day”)[19] +

    … and so on until

    Open(period=”day”)[1] – Close(period=”day”)[1] ) /20;

  27. Raph Says:

    Hey thanks! Your code works! =0)

    Hmmm… If/when you have time I would like some input on an off topic question about Excel macros, etc… if you have info on the like? I have come up with the code below, and am basically trying to auto-extract open, high, low, close data from Yahoo! Finance for 250 ticker symbols per workbook. I have managed to make the script run properly for the first worksheet, however, am not sure how to make it loop so all 250 worksheets contain recent quotes for all the symbols found in column A of worksheet #1? Cheers!


    Sub getData()

    ‘ getData Macro

    Dim x As Integer
    For x = 1 To 250

    With ActiveSheet.QueryTables.Add(Connection:= _
    “TEXT;C:\Users\Raph\Desktop\Yahoo! Finance Quotes – 1 of 3.txt”, Destination _
    :=Range(“A1” & x))
    .Name = “Yahoo! Finance Quotes – 1 of 3”
    .FieldNames = True
    .RowNumbers = False
    .FillAdjacentFormulas = False
    .PreserveFormatting = True
    .RefreshOnFileOpen = False
    .RefreshStyle = xlInsertDeleteCells
    .SavePassword = False
    .SaveData = True
    .AdjustColumnWidth = True
    .RefreshPeriod = 0
    .TextFilePromptOnRefresh = False
    .TextFilePlatform = xlWindows
    .TextFileStartRow = 1
    .TextFileParseType = xlDelimited
    .TextFileTextQualifier = xlTextQualifierDoubleQuote
    .TextFileConsecutiveDelimiter = False
    .TextFileTabDelimiter = True
    .TextFileSemicolonDelimiter = False
    .TextFileCommaDelimiter = False
    .TextFileSpaceDelimiter = False
    .TextFileColumnDataTypes = Array(1)
    .Refresh BackgroundQuery:=False
    End With
    Range(“A1” & x).Select
    ActiveCell.FormulaR1C1 = “”
    Sheets(“Sheet” & x).Select
    With ActiveSheet.QueryTables.Add(Connection:= _
    “URL;http://finance.yahoo.com/q/hp?s=A“, Destination:=Range(“A1” & x))
    .Name = “hp?s=A”
    .FieldNames = True
    .RowNumbers = False
    .FillAdjacentFormulas = False
    .PreserveFormatting = True
    .RefreshOnFileOpen = False
    .BackgroundQuery = True
    .RefreshStyle = xlInsertDeleteCells
    .SavePassword = False
    .SaveData = True
    .AdjustColumnWidth = True
    .RefreshPeriod = 0
    .WebSelectionType = xlSpecifiedTables
    .WebFormatting = xlWebFormattingNone
    .WebTables = “15”
    .WebPreFormattedTextToColumns = True
    .WebConsecutiveDelimitersAsOne = True
    .WebSingleBlockTextImport = False
    .WebDisableDateRecognition = False
    .Refresh BackgroundQuery:=False
    End With

    Next x

    End Sub

  28. JD Says:

    Wow Pro. Stumbled upon this site…you have some very cool stuff here and learning materials. I especially like this stop…but wished it toggled between ATR and EMA. I also thought the montecarlo sim was great…but I’m not exactly sure how to use it with my parameters though.

    In anycase, I was hoping you could answer a few ThinkScript questions when you have a moment. I tried ToS, but though I followed up with 3 emails, I haven’t gotten a reply…so I guess their not sure.

    Question 1 :
    Is there anyway to dynamically use something like AddChartLabel (or other) so that when my cursor moves over different bars, the AddChartLabel value changes.

    If this isn’t possible, is there anyway to show the values either in the below or above study without showing the graph ? ie. for every bar, I want to know a few values at a blance that is a multiple of the ATR. While I know how to chart the ATR, I want to save chart space and only want to see the values and not the ugly squiggly lines.

    Question 2 :
    Within the same study, I would like to use previously defined plots (or defs) in order to create a new plot only if certain conditions are true.

    eg. within a study let’s say I write the following :

    plot Signal_A = if ( Close > Close[3], 0 , double.NaN); # note : I will manually color the properties green
    plot Signal_B = if ( Low > Low[3], 0 , double.NaN); # note : I will manually color the properties green

    I would like to create a new plot based on the above plots such that if Signal_A is True today (ie. green at close) and Signal_B is also True (ie. green) at close of today or within the previous 2 days, then a Green Arrow will appear…otherwise double.nan

    I tried something like :
    plot Final_Signal = if ((Signal_A double.nan) and (Signal_A[0] double.nan or Signal_A[1] double.nan or Signal_A[2] double.nan), 0 , double.NaN);

    I tried variations of this but doesn’t seem to work. I know the code seems simple, but in the real study I plan to put together, ‘Signal_A’ … ‘B’….etc. are far more lengthy and involves multiple signals and the use of not (!) will also be needed, which is why I would like to call on plots (or defs) previously defined instead of copying & combining the logic.

    Is there a way to do this ?

    3. Is there an easy way to reference my studies (ie. indicators) in the Strategies ?

  29. Raph Says:

    Hi Prospectus,

    This is in regards to your reply posted on January 23, 2011 at 10:56 am… Is it possible to only calculate the Open minus Close 20 SMA ONLY for days where the close is > than the open? i.e., code for the Marketwatch tab for custom studies, and/or lower studies for UP days only (filter out the down days so that only the previous 20 bars that had closed up are used)?

  30. daily news Says:

    news source…

    […]Volatility-Based Trailing Stop for Think or Swim « Read the Prospectus[…]…

  31. http://bonhamstrand.hk Says:

    Hmm it looks like your blog ate my first comment (it was extremely long) so
    I guess I’ll just sum it up what I submitted and say, I’m thoroughly enjoying your
    blog. I too am an aspiring blog blogger but I’m still new to the whole thing. Do you have any tips and hints for rookie blog writers? I’d definitely appreciate it.

  32. Alex Dumitriu (@alex_dumitriu) Says:

    Prospectus any chance of a ninjascript version of this? I would really appreciate it

  33. Bennie Schuppert Says:

    I am really delighted to read this web site posts which includes
    lots of valuable facts, thanks for providing these statistics.

  34. Ky Says:

    Good day Prospectus.
    Are you able to convert NT script into TOS?
    I have a couple common DoubleStochastics, I’d like to have in TOS.
    Unfortunately TOS only has a Double Smooth Stochastic, and it plot very differently.

  35. Prospectus Says:

    I can. Send me the code and I’ll give you a quote

  36. Ky Says:

    Prospectus, post the code here?

  37. Prospectus Says:

    Email me readtheprospectus at gmail


  38. bhompla Says:

    Love your Volatility-based Trailing Stop Loss Code. Standard TOS allows us to set trailing stop loss based on a fixed dollar value or fixed percentage; it does not allow us to set trailing stop loss values which can be dynamically changed…

    Can you help with code which will dynamically change the tralling stop loss value to a dynamic using your Volatility-based-Trailing Stop logic). In a long Trade, we know that the Trailing SL will either be revised upwards or will stay the same value. I would like the system to not just calculate the new Trailing Stop Loss Value based on a custom calculation, but also automatically with every open of a new bar, update the Tr SL Value if required (i.e. unless it will stay the same). This means automatically make a change to an existing Trailing Stop Loss Order!


  39. thuyqpham Says:

    Do you know how to create an AggragatedPeriod to this script?

    What I want is to look at 1H chart but see the plot from D so I don’t have to have 2 charts on screen

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: