Turtle System

I have seen a plethora of posts on turtle system where the rules and code are provided. The codes range from a mere Donchian break to a fairly close representation. Without dynamic portfolio feedback it is quite impossible to program portfolio constraints as Curtis Faith explains in his welcome. Way of the Turtle. But the other components can be programmed pretty close to Curtis’s descriptions. I wanted to provide this code in a concise way to illustrate some of EasyLanguage’s esoteric constructs and some neat shortcuts. First let’s take a look at how the system has worked in crude oil for the last 15 years.

## Turtle System Key: The Trends

If there are trends in the market, the Turtle will catch you. See how the market rallied in 2007 and immediately rallied in 2008, and see how the Tortoise caught the moves – impressive. But see how the system stops working in congestion. It took a small slice of the 2014 move down and has done a great job of catching the pandemic crash and rebound. In my last post, I programmed the LTL (Last Trader Loser) function to determine the success/failure of the Turtle System 1 Entry. I modified it slightly for this post and used it in conjunction with the Turtle System 2 Entry and the 1 AddOn pyramid trade. /2N to get as close as possible to the core of turtle I/O logic.

I’m going to provide the ELD for you to review at your leisure, but here are the important pieces of code that you may not be able to derive without a lot of programming experience.

If mp[1] <> mp and mp <> 0 then

begin

if mp = 1 then

begin

origEntry = entryPrice;

origEntryName = “Sys1Long”;

If ltl = False and h >= lep1[1] then origEntryName = “Sys2Long”;

end;

if mp =-1 then

begin

origEntry = entryPrice;

origEntryName = “Sys1Short”;

If ltl = False and l <= sep1[1] then origEntryName = “Sys2Short”;

end;

end;

This code determines if the current market position is not flat and is different from the market position of the previous bar. If this is the case, then a new operation has been executed. This information is needed to know which exit to apply without forcibly binding them using the EasyLanguage From Entry keywords. I just need to know the name of the input. The entryPrice is the entryPrice. Here I know if the LTL is false, and the entryPrice is equal to or greater/less than (based on the current market position) the entry levels of system 2, then I know that system 2 got us into the market with a trade.

If mp = 1 and origEntryName = “Sys1Long” then Sell currentShares shares next bar at lxp stop;

If mp =-1 and origEntryName = “Sys1Short” then buyToCover currentShares shares next bar at sxp stop;

//55 bar component – no contingency here

If mp = 0 and ltl = False then buy(“55BBO”) next bar at lep1 stop;

If mp = 1 and origEntryName = “Sys2Long” then sell(“55BBO-Lx”) currentShares shares next bar at lxp1 stop;

If mp = 0 and ltl = False then sellShort(“55SBO”) next bar at sep1 stop;

If mp =-1 and origEntryName = “Sys2Short” then buyToCover(“55SBO-Sx”) currentShares shares next bar at sxp1 stop;

The key to this logic is the currentShares shares keywords. This code tells TradeStation to liquidate all current stocks or contracts at stop levels. You could use currentContracts if you’re more comfortable with vernacular futures.

## Activation of the pyramiding option in TradeStation

Before you can pyramid, you must activate it in Strategy Properties.

If mp = 1 and currentShares < 4 then buy(“AddonBuy”) next bar at entryPrice + (currentShares * .5*NValue) stop;

If mp =-1 and currentShares < 4 then sellShort(“AddonShort”) next bar at entryPrice – (currentShares * .5*NValue) stop;

This logic adds positions from the original input Price in 1/2N increments. The description of this logic is a bit fuzzy. Is the N value the ATR reading when the first contract was placed or is it recalculated dynamically? I erred on the side of caution and used the N when the first contract was put up. So, to calculate the long AddOn entries, just take the original entryPrice and add currentShares * 0.5N. So if currentShares is 1, then the next level of the pyramid would be entryPrice + 1* 0.5N. If currentShares is 2 , then entryPrice + 2* 0.5N and so on. The stop 2N trails the last entryPrice. So if you put in 4 contracts (specified in Curtis’s book), then the final output would be 2N from where you added the 4th contract. Here is the code for that.

### Settle all contracts in the last entry – 2N

vars: lastEntryPrice(0);

If cs <= 1 then lastEntryPrice = entryPrice;

If cs > 1 and cs > cs[1] and mp = 1 then lastEntryPrice = entryPrice + ((currentShares-1) * .5*NValue);

If cs > 1 and cs > cs[1] and mp =-1 then lastEntryPrice = entryPrice – ((currentShares-1) * .5*NValue);

//If mp = -1 then print(d,” “,lastEntryPrice,” “,NValue);

If mp = 1 then sell(“2NLongLoss”) currentShares shares next bar at lastEntryPrice-2*NValue stop;

If mp =-1 then buyToCover(“2NShrtLoss”) currentShares shares next bar at lastEntryPrice+2*NValue Stop;

I introduce a new variable here: cs. CS stands for currentShares and I keep track of her from bar to bar. If currentShares or cs is less than or equal to 1 I know that the lastPrice entry was the originalPrice entry. Things get a bit more complicated when you start adding positions – initially I couldn’t remember if the EasyLanguage entryPrice contained the latest entryPrice or the original – turns out it’s the original – good to know. So if currentShares is greater than one and the currentShares of the current bar is greater than the currentShares of the previous bar, then I know I added another contract and so I need to update lastEntryPrice. LastEntryPrice is calculated by taking the original entryPrice and adding (currentShares-1) * 0.5N. Now this is the theoreticalPrice input, because I don’t account for slippage in the input. You could do this setting. Therefore, once I know the lastEntryPrice I can determine 2N from that price.

### Exit at 2N Trailing Stop

If mp = 1 then sell(“2NLongLoss”) currentShares shares next bar at lastEntryPrice-2*NValue stop;

If mp =-1 then buyToCover(“2NShrtLoss”) currentShares shares next bar at lastEntryPrice+2*NValue Stop;

That’s all the nifty code. Below is the function and ELD for my implementation of the Turtle System dual input system. You will see some pretty fancy code when it comes to system input 1 and this is due to these scenarios:

What if you are theoretically short and they are theoretically stopped for a real loser and you can enter the same bar on a long trade?

What if you are theoretically short and the reversal point would result in a losing trade? It would not book the loser in time to enter the long position at the reversal point.

What if you are really short and the reversal point would result in a real loser, then you would want to allow the reversal at that point?

There are probably other scenarios, but I think I covered all the bases. Just let me know if that’s not the case. What I did to validate the entries was I scheduled a 20/10 day breakout/failure with a 2N stop and then went through the list and removed the trades that followed a non 2N loss (10 bar exit for a loss or win .) I then made sure those operations were not in the full system output. There was a bit of trial and error. If you see an error, like I said, let me know.

Remember that I posted the results of different permutations of this strategy incorporating dynamic portfolio feedback on my other website https://www.trendfollowingsystems.com/. These results reflect the fairly close portfolio that Curtis suggests in his book.

Article courtesy of George Pruitt

## Quantified Models Youtube Channel

On our YouTube channel we have several videos available that you may find very useful for developing trading systems. To access, click this link: Quantified Models YouTube Channel

We hope this information has been useful to you.