I have received lots of requests for making a trailing stop strategy work in Think or Swim. Unfortunately, due to the way that ToS currently works with strategies, there is no way to make your entry and exit strategies “talk” to each other automatically. But it is possible to get trailing stop strategies to work! It just takes some extra elbow grease.
In general, any intelligent trailing stop must have knowledge of the entry point, so it knows where to start trailing. You can use “dumb” stops, like my experimental “N bar trailing stop” indicator, that just takes the low / high of N bars back and plots the value. This kind of a number is always on, so to speak. But if you want to trail a certain number of points behind your entry, for example, you can’t use the “dumb” stop method. You have to know where the entry took place. So how do you do it?
The 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 the logic for the long side and the short side together in the same set of code. This is needed for the calculation of the new stop loss value once we switch direction. Along with this, you need to define recursive functions that perform the trailing action. In the Volatility Stop, I’m actually always calculating the values of the long side stops and the short side stops according to the ATR. There is logic to check whether that value is outside the current trailed value (ignore it) or inside the current trailed value (update the trailing stop to the tighter level). This is done for both sides at the same time. There is one more set of logic to decide if we are in the long direction or the short direction, and that tells the indicator which one to plot.
Sound complicated? Actually, it’s HARDER to make the study indicator work than it is to make the strategy work! The strategy will automatically decide if you are long or short based on the criteria you give it for entries and exits. All you have to worry about is reproducing the entry logic in your exit, and the trailing logic.
Time for an example. Say you want to trail a stop N-points below your entry price, and then move it up if “low-N” is greater than the prior trailing stop value.
(Tangent–this is different than a true trailing stop like you might have with your broker, but you have to do it this way if you want to get any backtested results out of the indicator. This is because you will get falsely stopped out if your bar range is greater than your trailing N-points value if you track from the highest high, as a true trailing stop order would. If you could plot this on the tape, tick by tick, then it would work, but for any aggregated candles you have to do it this way. Here’s an explanatory picture:
Confusing, I know; comment if you need more explanation.)
The following strategy skeleton, when fleshed out and paired with an entry strategy, will create a simple “N-points below the low” trailing stop:
declare LONG_EXIT;
# input the number of points to trail under the entry:
input trailstop=2.0;
# Reproduce Your Entry Code Below:
#################################def trigger=if XXXXXX then 1 else 0; # check for entry condition
def orderprice=YYYYYYY; # What price? close, low, high, etc
#################################
# Now, initialize Trailing Stop
rec ts=if trigger then orderprice-trailstop else if low-trailstop>ts[1] then low-trailstop else ts[1];
# Send LONG_EXIT order if the low touches the trailing stop (ignore the entry bar):
def stopout=if trigger then 0 else if low<=ts then 1 else 0;
addorder(stopout,ts);
The part about reproducing your entry code should be self explanatory. You put the same code in that you are using for your entry. The strategy skeleton above uses two other lines:
def trigger=if XXXXXX then 1 else 0; # check for entry condition
def orderprice=YYYYYYY; # What price? close, low, high, etc
“Tigger” is the final check for your entry condition. “Orderprice” is where you put the price that you want the trade to be taken at, or the price where you would submit the order.
Now, the part with the recursive trailing logic is trickier, and is done in two parts, like this:
# Now, initialize Trailing Stop
rec ts=if trigger then orderprice-trailstop else if low-trailstop>ts[1] then low-trailstop else ts[1];
In english: If this is the entry bar then set the trailing stop N points below the order price. If it’s not the entry bar, then check if the value of low-N points > the last trailing stop value, and if it is, then that’s the new trailing stop value, but if it’s not, then keep the old one.
Then, you check if you actually get stopped out:
# Send LONG_EXIT order if the low touches the trailing stop (ignore the entry bar):
def stopout=if trigger then 0 else if low<=ts then 1 else 0;
In english: If this is the entry bar, then do nothing. If it’s not the entry bar, then if the low of the bar hit the trailing stop (or went below) then stop out, but if not, then do nothing.
The final step is in the code that actually adds the order:
addorder(stopout,ts);
In english: Add the order if we got a stop out. Use the value of the trailing stop as the order execution price.
This acts like we had an actual stop loss order in the market, and if it was hit we’d get out of the trade. So to wrap it all up, here’s an example set of files I made using a simple EMA Crossover as the entry condition. There are two studies for visualization, and two strategies–one for the entry and one for the exit:
If you add all of this to a chart, it looks something like this:
Trailing Stop Strategy in Think or Swim. Q.E.D.
You could reverse all of this logic to get the short side strategies as well. Now you should know enough to make your own trailing stop strategies. Unfortunately, I can’t create a standalone trailing stop strategy that you can just drop on a chart. There has to be some editing and coding done each time that you want to use a trailing stop with different strategy of your own. Feel free to ask questions if you need a pointer or two while making your own, I’m glad to help out!
Alternatively, if you would like me to do the work for you and create a custom trailing stop strategy to go along with an entry strategy you already have, contact me and I’ll code it for you for a flat $20 donation. You can choose any trailing style you like–trail N-points, ATR/volatility-based, percentage-based, etc. I do have to ask for new donations even from past donors for this specific offering due to the additional time I have to put in for each request, rather than just giving access to the products of my brain, as it were. The $20 pricing is good if you already have the entry strategy file to send me. If you need the entry strategy developed too, then it becomes a custom development request, and I’ll have to give you a quote on the number of hours it will take in order to determine the pricing. Either way, if you need some work done, send me an email.
Tags: strategy, Thinkscript, trailing_stop, tutorial



May 14, 2009 at 8:17 pm
Cool-o Prospectus, will try to wrap my head around the false stopouts issue with aggregate bars. Be well
May 14, 2009 at 8:33 pm
I’ll try to make a picture or two explaining what I mean.
May 14, 2009 at 10:44 pm
Very nice!
May 14, 2009 at 10:50 pm
Nicely done. Have you published the code for this “EMA Cross” strategy?
Also, do you use entry/exit pairs or just long/short?
I’ve written some uncomplicated long/short pairs where the exit simply “rethinks” the exit, but I’m yet to convince the script to “rethink” the “StopLossLimit” as predictably as I’d like. It’s useful on 15m and greater samples, but in 133tk samples, it’s erratic.
Adam
May 14, 2009 at 10:55 pm
Fantastic work on the tutorial Prospectus.
You are a fine crafter of precision tools as well as a great conveyor of education.
It is all much appreciated.
Keep up the great work and the great spirit in what you do.
All your efforts will soon be greatly rewarded.
Peace-
May 15, 2009 at 12:41 am
Thanks for the nice feedback, everybody.
Adam, I have published the EMA cross strategies in my first strategy
tutorial, and I inlcuded the strategy code for the long entry in this
post as well in the example files download, so I’m not sure what else
you’re looking for? Maybe I need to make the download links more
visible.
Also, I don’t trade this EMA Cross method. I use it for tutorials and
examples because it is easy to understand and to visualize.
In some strategy methods that I have looked at seriously for intraday
trading, I have about 8 strategies active at once, such as:
Long entry
Long profit target exit
Long stop loss exit
Long exit at close of day
Short entry
Short profit target exit
Short stop loss exit
Short exit at close of day
And Think Desktop decides which ones happen in what order based on
when the rules for each are met. If you are long and trigger an exit
strategy, you go flat. If you are long and you hit the short entry
trigger, you go flat and reverse. Think Desktop handles each case
automatically as long as you provide the strategy files with the
triggering conditions.
June 6, 2009 at 12:24 pm
great work. very helpfull…
after starting to scripting my own studies I now try to learn about strategies…
is it possible instead of trailing stops just make a strategy that after an entry eighter exits on a fixed target like 5 ES point or SL 2 points?
thanx
June 6, 2009 at 9:19 pm
Thanks, glad you found it helpful!
Yes, a fixed exit is easy. You have to reproduce the entry code in your exit strategy, and then you do something like this for a long exit :
input limit=5;
rec entryprice = if **stick entry condition here** then **stick entry price here** else entryprice[1];
def target = if close>=entryprice+limit then 1 else 0;
addorder(target,entryprice+limit);
Hope that helps a bit!
June 7, 2009 at 3:09 am
Thanx a lot… I somehow managed to make a (not so easy
) script for fixed exits yesterday using your trailing example… Really cool having the abillity baktesting ideas… To bad intraday tickchats only have historic data for 5 days in TOS.
But I do belive I just found a new favorite blog to follow!
Have a great day!
August 12, 2009 at 5:43 pm
Very helpful indeed. Thank you Prospectus for the detailed explanations.
However I must say that I tried a great deal to get stops and limits to work in strategies well but not too satisfied at the end of the day. So I decided to make a study that works like a strategy so that entries and exits can better talk to each other and so that the order-price can be more easily captured. So here, instead of a report, we get to look at the cumulative profit/loss chart in the study itself. I think this allows for easier implementation of trailing stops too. Do check out the page-link above for some additional write up and a screenshot.
http://sites.google.com/site/badkrash/
August 12, 2009 at 7:35 pm
Nihil,
That is a very interesting idea! It looks like it works well for visualization purposes. My only gripe would be that I would want to see the entries and exits annotated on the base chart, but that’s just me.
Hopefully one day Think Desktop will get better strategy backtesting integration so all these workarounds aren’t needed. Thanks for sharing!
November 8, 2009 at 12:09 pm
I am stuck can anyone help me figure this out:
I am trying to simply find a way to reference the highest/lowest close since a crossover
the basic highest(close, xxx) or lowest(close, xxx) function in think script requires xxx to be a constant but I need it to be a variable
i.e.
a 50 day moving average
if a bar has been above the 50 day moving average for 10, 40, 100, 349 etc… days and then closes below the 50 day ma
then i need to be able to reference the highest close since it last crossed over from below to above the 50 day ma
likewise after it has crossed below it – i need to be able to reference the lowest close since it crossed below the 50 day ma
and going forward be able to do this (reference highest when closes above 50 day ma and reference lowest when closes below 50 day ma)
i need this in order to be able to calculate my formula
Step 1: start long
start 6 bars in
average of high-low for last 5 days x 1.5 = volmultiplier
since long – subtract volmultiplier from highest close since beginning of chart
plot this line on every close
Step 2 IF price closes below plotted line then add volmultiplier to lowest close since crossover
if price closes above plotted line then subtract volmultiplier to highest close since crossover
Step 3 repeat step 2 infinitely
I am running this on other platforms with no issues but am trying to get all my formulas over to TOS
i tried if/then statements but thinkscript only allows for a certain size script so if it has been 100 bars since a crossover or 200 bars since a crossover r more it will not work
i have everything but how to look a highest/lowest close since last crossover??
November 8, 2009 at 12:33 pm
You use a recursive statement. Assuming you have a definition of your crossover like this:
def crossover = if [crossover logic] then 1 else 0;
Then here is the logic you use:
rec highestclose = if crossover then close else if close>highestclose[1] then close else highestclose[1];
Similar for a crossunder. That logic is doing this, in english:
If we are crossing over, then set the value to this bar’s close. If not, then if thus close is higher than the highest close since crossing over, then update it. If not, then just keep the highest close value from the last bar.
April 9, 2010 at 4:42 pm
I am loving using some of your tools on strategies,,
Was wondering if you were ever able to use partial exits from positions, ..
the addorder( condition , price , trade size ) for some reason seems to ignore the trade size . I tried to long entry with say trade size of 100 ,, and then use say in the long exit a tradesize of 50 ,, but the tos seems to always exit with the same quabtity as the entry ..
What am I soing wrong ,,, any comments suggestions or smaple of something that works .
Thanks
April 9, 2010 at 4:43 pm
I am loving using some of your tools on strategies,,
Was wondering if you were ever able to use partial exits from positions, ..
Resubmitted with a bit more care for spelling
the addorder( condition , price , trade size ) for some reason seems to ignore the trade size . I tried to long entry with say trade size of 100 ,, and then use say in the long exit a tradesize of 50 ,, but the tos seems to always exit with the same quantity as the entry ..
What am I soing wrong ,,, any comments suggestions or sample of something that works .
Thanks
April 9, 2010 at 5:12 pm
If it’s not working, try entering two positions and only exiting one at a time. Also report the bug to TOS.
April 29, 2010 at 12:23 am
hello,
Id first like to say i appreciate resources like this that support learning. I am trying to write a short exit strategy that exits the short position once a +3 limit is hit. For some reason, I cannot get it to work. Here is what i have:
#
def trigger = if smasignal and isopen and adxsignal and macdsignal and rsisignal then 1 else 0;
def orderprice = close;
#
input limit=3;
rec entryprice = if trigger then orderprice-limit else orderprice[1];
def target = if close<=orderprice-limit then 1 else 0;
addorder(target,orderprice-limit);
What am I doing wrong?
April 29, 2010 at 12:30 am
Do you have smasignal and isopen and adxsignal and macdsignal and rsisignal all defined? What’s your error message? Do you also have the strategy defined as a short_exit?
April 29, 2010 at 8:56 am
i do. have them all defined. they are my conditions for the entry. I do not get an error message, instead it just does not show entries or exits. They go away when I put this piece into the source for the exit. here is all of it
# EMA Cross Short Entry
# By Prospectus @ http://readtheprospectus.wordpress.com
#
# Input Declarations:
#
declare SHORT_exit;
input opentime = 0930;
input closetime = 1600;
input SMA_F = 5;
input SMA_S = 20;
input dmilength = 14;
input adxcrossingType = {default above, below};
input adxthreshold = 20;
input fastLength = 12;
input slowLength = 26;
input MACDLength = 9;
input AverageType = {default EMA, SMA};
input crossingType = {default “Positive to Negative”, “Negative to Positive”};
input rsilength = 14;
input rsicrossingType = {default below, above};
input rsithreshold = 50;
# enter during market hours only
def AP = getAggregationPeriod();
def daily = if AP >= aggregationPeriod.DAY then 1 else 0;
def isopen = if daily then 1 else if secondsFromTime(opentime) >= 0 and secondsTillTime(closetime) >= 0 then 1 else 0;
# SMA crossunder
def smaunder = if simplemovingavg(close, SMA_S)> simplemovingavg(close, SMA_F) then 1 else 0;
def smacross = if simplemovingAvg(close, SMA_S)[1] = simplemovingavg(close, SMA_F) then 1 else 0;
def smasignal = if smaunder or smacross then 1 else 0;
# adx crossover 20 or adx above 20 and increasing
def adxincreasing = if DMI(dmilength).ADX[1] = adxthreshold then 1 else 0;
def adxsignal = if Crossover(adxcrossingType == adxCrossingType.above, DMI(dmilength).ADX > adxthreshold) or adxincreasing then 1 else 0;
# macd positive to negative cross or macd negative and decreasing
def Diff = MACD(fastLength, slowLength, MACDLength, AverageType).Diff;
def macddecreasing = if macd(fastlength, slowlength, macdlength, averagetype).diff macd(fastlength, slowlength, macdlength, averagetype).diff then 1 else 0;
def macdsignal = if Crossover(crossingType == CrossingType.”Negative to Positive”, Diff > 0) or macddecreasing then 1 else 0;
#rsi cross below 50 or rsi below 50 and decreasing
def rsidecreasing = if rsiwilder(length = rsilength).RSI[1] > rsiwilder(length = rsilength).rsi and rsiwilder(length = rsilength).RSI rsithreshold) or rsidecreasing;
#
def trigger = if smasignal and isopen and adxsignal and macdsignal and rsisignal then 1 else 0;
def orderprice = close;
#
# This code triggers the strategy on the chart.
# Arg. 1 adds order if true, nothing if false
# Arg. 2 is the entry price
input limit=3;
rec entryprice = if trigger then orderprice-limit else orderprice[1];
def target = if close<=orderprice-limit then 1 else 0;
addorder(target,orderprice-limit);
# Formatting:
#
SetColor(color.green);
May 5, 2010 at 7:58 am
Prospectus,
I’m fairly new to TOS and found your site via google. I have a strategy that I’ve worked on that suits me, but have little experience with TOS scripting. I’d like to forward you the laymans terminology to get your opinion on what you might be able to do to reflect it within a script to make conditions for entry/exit both long and short appear clearly on a chart. Happy to donate for your efforts. Please email me if interested.
Best,
Paul
March 30, 2011 at 8:57 am
Prospectus. I am trying to recreate TOS’s ATRTrailing Stop Indicator into C#. I have Visual Basic Files and Think Script Files for the indicator. But C# is the end goal. Any advice? Will donate for help.
Thanks
March 30, 2011 at 9:10 am
I can help you next week. Email me
May 16, 2011 at 12:59 pm
This may be a stupid request, but can you tell me the custom criteria for
thinkorswim for the following?
Simply, the “last 15 minutes of trading”
January 22, 2012 at 7:58 am
Hi, can you please offer additional details regarding your “N bar trailing stop” indicator? I am trying to understand what the criteria is for the lines breaking? Is it because the candlestick is unable to take out the previous “x” number of highs, but succeeds in taking out the previous “x” number of lows (in an uptrend)? …in other words, using your default value of “2″ what criteria determines the beginning/end of the trailing stop? I have created a screen cap to explain this question further: http://oi44.tinypic.com/xlwmeb.jpg
Regards.
January 22, 2012 at 11:01 am
The trailing stop shown is simply the high or the low of N bars ago. It is always updating on each bar. The lines on your chart are breaking because the current bar has broken the high or low of 2 bars in the past. That can happen even if the current bar doesn’t move very far if a wide range bar drops off the back end and is replaced by the next bar. In that sense, it’s not a true trailing stop.
January 22, 2012 at 11:41 am
Hey, thanks for the explanation. I think I get it now.
January 29, 2012 at 8:56 am
Robots…
[...]Tutorial: Trailing Stop Strategies for Think or Swim « Read the Prospectus[...]…