Many of you asked for a method to backtest this study. It is a relatively simple matter to construct a thinkScript strategy from a study. Most of the code from any study can be copied straight across into your strategy. You will need to declare the strategy mode with a declare statement with one of the following arguments:
LONG_ENTRY; LONG_EXIT; SHORT_ENTRY; SHORT_EXIT
Since you can’t plot anything from a strategy, all plot statements for variables that will be part of the strategy logic should be converted to def statements and their formatting commands removed. Other non-essential plot statements and associated formatting can be removed entirely. Your entire goal when creating a strategy is to define a binary condition that will trigger a trade. In this particular case we are looking for a moving average cross. I had already coded that into the study for use with the signal dots:
def buySignal = if TypicalPriceZeroLagTEMA > HeikinAshiZeroLagTEMA and TypicalPriceZeroLagTEMA[1] <= HeikinAshiZeroLagTEMA[1] then 1 else 0;
With this condition we can now add the other essential piece of code for strategies – the addOrder(condition,price) command:
addOrder(buySignal,open[-1]);
Here you see the binary condition buySignal entered as the trigger argument and the price is the next bar’s open, hence the [-1] indexing.
Strategies only work in pairs. You can have a Long Entry and Long Exit pair or a Long Entry and Short Entry pair etc. In this case I used a daily chart with six months of data to run the backtest. With proper money and stop management to minimize drawdowns this looks to be a viable strategy. Profit was $7400 on a single ES contract over the preceding six month period. Full results here.
The Long Entry Code:
declare LONG_ENTRY;
input period = 55;
def price = (high+low+close)/3;
def TMA1 = 3 * ExpAverage(price, period)
- 3 * ExpAverage(ExpAverage(price, period), period)
+ ExpAverage(ExpAverage(ExpAverage(price, period), period), period);
def TMA2 = 3 * ExpAverage(TMA1, period)
- 3 * ExpAverage(ExpAverage(TMA1, period), period)
+ ExpAverage(ExpAverage(ExpAverage(TMA1, period), period), period);
def difference = TMA1 - TMA2;
def TypicalPriceZeroLagTEMA = TMA1 + difference;
rec haopen = compoundValue(1, ((open[1] + high[1] + low[1] + close[1]) / 4
+ haopen[1]) / 2, hl2);
def haclose = ((open + high + low + close) / 4 + haopen + Max(high, haopen)
+ Min(low, haopen)) / 4;
def HATMA1 = 3 * ExpAverage(haclose, period)
- 3 * ExpAverage(ExpAverage(haclose, period), period)
+ ExpAverage(ExpAverage(ExpAverage(haclose, period), period), period);
def HATMA2 = 3 * ExpAverage(HATMA1, period)
- 3 * ExpAverage(ExpAverage(HATMA1, period), period)
+ ExpAverage(ExpAverage(ExpAverage(HATMA1, period), period), period);
def HAdifference = HATMA1 - HATMA2;
def HeikinAshiZeroLagTEMA = HATMA1 + HAdifference;
def buySignal = if TypicalPriceZeroLagTEMA > HeikinAshiZeroLagTEMA
and TypicalPriceZeroLagTEMA[1] <= HeikinAshiZeroLagTEMA[1] then 1 else 0;
addOrder(buySignal,open[-1]);
setColor(color.green);
The Short Entry Code:
declare SHORT_ENTRY;
input period = 55;
def price = (high+low+close)/3;
def TMA1 = 3 * ExpAverage(price, period)
- 3 * ExpAverage(ExpAverage(price, period), period)
+ ExpAverage(ExpAverage(ExpAverage(price, period), period), period);
def TMA2 = 3 * ExpAverage(TMA1, period)
- 3 * ExpAverage(ExpAverage(TMA1, period), period)
+ ExpAverage(ExpAverage(ExpAverage(TMA1, period), period), period);
def difference = TMA1 - TMA2;
def TypicalPriceZeroLagTEMA = TMA1 + difference;
rec haopen = compoundValue(1, ((open[1] + high[1] + low[1] + close[1]) / 4
+ haopen[1]) / 2, hl2);
def haclose = ((open + high + low + close) / 4 + haopen + Max(high, haopen)
+ Min(low, haopen)) / 4;
def HATMA1 = 3 * ExpAverage(haclose, period)
- 3 * ExpAverage(ExpAverage(haclose, period), period)
+ ExpAverage(ExpAverage(ExpAverage(haclose, period), period), period);
def HATMA2 = 3 * ExpAverage(HATMA1, period)
- 3 * ExpAverage(ExpAverage(HATMA1, period), period)
+ ExpAverage(ExpAverage(ExpAverage(HATMA1, period), period), period);
def HAdifference = HATMA1 - HATMA2;
def HeikinAshiZeroLagTEMA = HATMA1 + HAdifference;
def sellSignal = if TypicalPriceZeroLagTEMA < HeikinAshiZeroLagTEMA
and TypicalPriceZeroLagTEMA[1] >= HeikinAshiZeroLagTEMA[1] then 1 else 0;
addOrder(sellSignal, open[-1]);
setColor(color.red);





Thanks Eric. No wonder I couldn’t figure it out. I thought there was a way to call a study from within the strategy, so I was trying to do that.
This is very helpful.
bill
That would be nice….but alas, not yet.
Dude, you rock – your explantion has opened my eyes greatly – keep it going. Thanks Much
Outstanding….wish I would have scrolled down enough the see the code snip
That said your explanation was good enough to port the study over to a strategy and learned allot along the way…now if I only knew how to tweak my draws.
This is great stuff!!
Thanks for this, I’ve been working with strategies a lot to cross check results from metatrader, finding plenty of variance, trust TOS results more. Wish it could handle stops, haven’t found any way for exit rules to reference entry price :\
Eric,
Check this out. I pulled out some old strategy code and I thought I remembered that you could indeed reference a study from inside a strategy. I remember writing to TOS help and getting the answer. I’ve pasted the whole code here (forgive my simplicity… I’m a trader, not a programmer), and the key word is “reference”. I was able to pull values from the ADX_DMI studies without having to bring the actual code it. This is what I was trying to do with your studies and could’t make work, but I think I just wasn’t passing the required parameters properly.
Bill
declare LONG_ENTRY;
input DMI = 13;
input ADX_length = 8;
input ADX_signal = 25;
input Price_Breakout_Length = 30;
input DMI_Breakout_Length = 20;
def dmiPlus = reference diplus(length = DMI);
def dmiMinus = reference diminus(length = DMI);
def adxLine = reference adx(length = ADX_length);
def condition = adxLine > ADX_signal AND
High > Highest( High[1], Price_Breakout_Length ) AND
dmiPlus > Highest(dmiPlus[1],DMI_Breakout_Length);
addOrder(condition);
@Bill Smith: You can’t call a user-defined study inside of a strategy. But you can replicate the study in the code and use it in your strategy.
@manatrader: When I make strategies with trailing stops, I replicate the entire entry logic inside of the trailing stop strategy. This way, the trailing stop logic knows where to begin trailing and has the entry price available.
[...] two recent posts, ThinkScripter (a great new blog that features studies and strategies coded for the thinkScript language used on [...]
Excellent work. I’m very keen on seeing the performance when a more realistic approach to trading is taken.
-Eric
Can anyone tell me what I’m doing wrong?
When I cut the code from above and paste it into the source box for a new study, I get three sections highlighted in red:
line 1: “LONG_ENTRY” is highlighted in red
line 34: “addOrder” is highlighted in red
line35: “setColor” is highlighted in red
Beneath that in the next box (under the link for thinkScript Manual) are the notations:
No such function: addOrder at 34:1
No such function: setColor at 35:1
Unexpected declare: Long_Entry at 1:9
At least one plot should be defined
________________________________________________
Thanks in advance for any assistance
neutral,
These are not studies but strategies. You need to cut and paste each one into a new TOS strategy. One will be the long side of the strategy and the other will be the short side. Together they work to create an always in trading approach going from long to short and back again.
Eric
Hi Eric – Just ran in to your website, you have done some amazing things with the TOS scripting. Can you tell me if there is a way to exit EOD in the script while backtesting? Also, can there be alerts generated based on an EMA crossover strategy?
Thanks much,
JB
JB,
You can create exit strategies using the TOS time functions such as getSecondsTill(time). You will need both a long and short exit strategy with the time function to create a binary exit signal. Yes, EMA crossovers are easy to create into strategies almost identical to the Vervoot crossover.
Hello Think Scripter,
I wanted to know if it is possible to add off set orders with a limit and/or stop amount? Also is it possible to turn the Fisher Transform Signal to a Strategie? I’ve tried bt with no luck!
Thanks for your great work on scripting for the TOS charts. I appreciate it.
Have you noticed that on some charts the entries and exits don’t always correspond to the dots painted by the VerVoortCrossover study? I’m still trying to figure out why but haven’t discovered why. I thought it’s may be only happening on a tick chart but I’ve also seen it happen on time charts too.
Mark,
I have always noted strange behavior from strategies. Perhaps it is my lack of skill in coding them but I have seen inconsistent results on occasion as well as strategies that act different in real-time as opposed to historically. Often times merely resetting a chart period will cause different results from a strategy. For this reason, I only use TOS strategies as a crude backtest of a study/trading method. I never use them real-time to trade with.
Eric
Eric,
Please post a brief step-by-step on how to backtest a strategy like this one in TOS. Thanks again for your excellent work.
Craig
Gold Member
Eric,
Also, have you also created and posted Long_Exit and Short_Exit strategies on your site for the pairs required for testing the above Vervoot entry strategies?
Thanks again,
Craig
Gold Member
The strategies are in the current zip file.
Eric
I would say that the main advantage of the strategy in the fact that one strategy may combine more completely different studies. Of course, provided that you do not exaggerate in order to get signals. It is in fact a combination of study and determining the number of adjustable parameters with the greatest skill of creating good strategy as opposed to studies that are sufficient for themselves.