Turtle Breakout Trading Strategy Simulation


The “turtles” are a group of traders in the 1980s formed by Richard Dennis and William Eckhardt to study whether trading ability is determined by nature or nurture. The group’s story is covered in many books such as Market Wizards by Jack D. Schwager, Way of the Turtle by Curtis Faith (an original turtle), and The Complete Turtle Trader by Michael W. Covel. The turtle traders were taught a specific breakout trading system, based on technical analysis and trend following, that used the moving 10, 20 and 55 day high’s and low’s as trade signals combined with volatility adjusted position sizes.

The breakout strategy focuses on detecting when a given instrument is likely to make consistently large gains or declines by tracking the price versus a moving high-low range. For example, if Microsoft’s stock is at $25.05 and broke its last 20 day high of $25.00, then it would be a buy signal. The next time the stock crosses a 10 day low it would be a signal to close the position and sell. The strategy also has a set stop loss limit on all positions. The strategy performs well in a market where there is a steady rise or fall in the price, but does poorly when the prices are range bound and very volatilite.  Poor market conditions tend to trigger stop orders frequently leading to losing trades.

In the end, many of the turtle traders became very successful traders, which implies that nurture is a key factor in trading ability. The turtle breakout system has likely been improved and modified in various ways, but it is interesting to analyze the original system’s performance on various instruments and time periods. To demonstrate the flexibility of creating and back-testing strategies in Palantir Finance, we have simulated the main rules of the breakout trading strategy in the platform. The rules are based on “The Original Turtle Trading Rules”, written by Curtis Faith and can be found as a PDF hosted on various websites (Google results, the original website no longer hosts the paper.)


First, one of the basic metrics required by the strategy is determining the true range. The true range is defined by Faith as the maximum difference between either the high and the low, the high and the previous day’s close, or the previous day’s close and the low. True range is a conservative (wider) measure of the price range of an instrument and basically is one way of measuring price volatility. The strategy uses a 20 day exponential moving average of True Range to smooth out any extreme ranges. You can see the relevant charts in Figure 1.

Figure 1. Chart of the close/high/low price of Microsoft [MSFT], True Range metric [MSFT.TrueRange], and the 20 day exponential moving average [MSFT.TrueRange.ema(20)].

We create the custom metric in “hedgehog language,” a language specific to Palantir Finance and similar to java, to generate a time series of true range for any given instrument. The “max” function takes two time series arguments and generates a third time series, which consists of the max of the two inputs. The previous day’s close is calculated by lagging the close time series by one day. Once defined, the custom metric can be referenced anywhere in the platform and on any times series object.

Figure 2. Custom metric - Implementation of the True Range time series.

Strategy Details

The breakout strategy is set to trade on MSFT stock during the period between 10/9/2005-10/8/2010. The entry day range is set to 20 and the exit day range is set to 10. This means that a position will be entered if the 20 day high or low is crossed and profit will be taken when the 10 day low or high is crossed respectively.

Units of trading and price stops are determined by the N-value, which is the 20 day exponential moving average (EMA) of True Range (as defined above in the custom metric), and may be interpreted as an average volatility for the last 20 days (unrelated to the 20 entry day range value). Trading units (N-units) are set to 1% of NAV (Net Asset Value) divided by N-value. For example, if N was $0.50 and NAV was 1,000,000, then N-unit would be 1%$1,000,000/$0.50 or 20,000 shares. The N-unit formula helps calculate an appropriate trade size or exposure based on the risk of each instrument. For instruments without dollar prices, such as futures, one also needs to convert N-value to a dollar value per contract for calculating the N-unit. The stop loss logic is set to 2N-value price units for new positions and is stepped 0.5*N-value closer on each position increase. Each position is increased by a N-unit when the price moves in the positions favor by 0.5 N-value. This collection of rules creates a complete system for entering and exiting trades.

NOTE: Our implementation uses the default Palantir Finance’s built-in EMA formula, which differs slightly from the “The Original Turtle Trading Rules”. The turtle version used an equation similar to a modified moving average.  If one wants to use the turtle version of the EMA, it could easily be built as another custom metric.

Figure 3. Screen shot of the strategy component in Palantir Finance.

Strategy Code

Setup code:

Instrument inst = MSFT;

TimeSeries series = inst.close;
<span class="code-object">Number</span> currentN;
<span class="code-object">Number</span> unit;
<span class="code-object">Number</span> stopPrice;
<span class="code-object">Number</span> entryPrice;
<span class="code-object">Number</span> addPrice;
<span class="code-object">Number</span> pos;
<span class="code-object">Number</span> currentNAV;
<span class="code-object">Integer</span> entryDayRange = 20;
<span class="code-object">Integer</span> exitDayRange = 10;

Loop code:

//set our N (volatility) measurement.
</span>currentN = inst.TrueRange.ema(20).valueOn(now);

<span class="code-keyword">if</span> (currentN != <span class="code-keyword">null</span>)
currentNAV = portfolio().valueOn(now);

<span class="code-comment">//set unit size based on (1% of portfolio net asset value)/N
</span>unit = round(currentNAV*0.01/currentN,0);

<span class="code-comment">//get position
</span>pos = numContracts(inst);
<span class="code-keyword">if</span> (pos == <span class="code-keyword">null</span>)
  {pos = 0;}

<span class="code-comment">//<span class="code-object">long</span> position
</span><span class="code-keyword">if</span>(pos&gt;0)
  <span class="code-comment">//stop limit
</span>  <span class="code-keyword">if</span> ( series.movesBelow(stopprice) )
    {exit(inst);} <span class="code-keyword">else</span>
  <span class="code-comment">//exit condition, take profit
</span>  <span class="code-keyword">if</span> (series.movesAbove(inst.rollingHigh(exitDayRange,Enum.Days).lag(1)))
    {exit(inst);} <span class="code-keyword">else</span>
  <span class="code-comment">//add to <span class="code-object">long</span>
</span>  <span class="code-keyword">if</span> (series.movesAbove(addPrice)){
            <span class="code-comment">//add to position, adjust stop price and next add price
</span>            buy(inst,unit,Enum.NUM_CONTRACTS);
            stopPrice += currentN/2;
            addPrice += currentN/2;
<span class="code-comment">//<span class="code-object">short</span> position
</span><span class="code-keyword">else</span> <span class="code-keyword">if</span> (pos&lt;0)
  <span class="code-comment">//<span class="code-object">short</span> stop limit
</span>  <span class="code-keyword">if</span> ( series.movesAbove(stopprice) )
    {exit(inst);} <span class="code-keyword">else</span>
  <span class="code-comment">//exit condition, take profit
</span>  <span class="code-keyword">if</span> (series.movesBelow(inst.rollingLow(exitDayRange,Enum.Days).lag(1)))
    {exit(inst);} <span class="code-keyword">else</span>
  <span class="code-comment">//add to <span class="code-object">short</span>
</span>  <span class="code-keyword">if</span> (series.movesBelow(addPrice)){
            <span class="code-comment">//sell more, adjust stop, and adjust next add Price
</span>            sell(inst,unit,Enum.NUM_CONTRACTS);
            stopPrice -= currentN/2;
            addPrice -= currentN/2;
<span class="code-keyword">else</span>
  <span class="code-comment">//intiate <span class="code-object">long</span> position
</span>  <span class="code-keyword">if</span> (series.movesAbove(inst.rollingHigh(entryDayRange,Enum.Days).lag(1))){
            entryPrice = series.valueOn(now);
            addPrice = entryPrice + currentN/2;
            stopPrice = series.valueOn(now) - 2*currentN;
  <span class="code-comment">//initiate <span class="code-object">short</span> position
</span>  <span class="code-keyword">if</span> (series.movesBelow(inst.rollingLow(entryDayRange,Enum.Days).lag(1))){
            entryPrice = series.valueOn(now);
            addPrice = entryPrice - currentN/2;
            stopPrice = series.valueOn(now) + 2*currentN;

Performance statistics

Overall, the strategy performed very well with these settings and had a gain of +63.69% over the S&P 500 benchmark and had a sharpe ratio of 0.55.  The benchmark can be changed to any instrument or index for comparison.  The breakout strategy made 152 total trades and in Figure 4 you can see the breakdown of profitable and losing matched trades by long or short positions. In Figure 5, you can see on the NAV chart that the strategy was profitable in 2007 and in 2009-2010, and lost money during the volatile periods of 2008.  With detailed results such as these, you can fine tune the strategy to isolate conditions where the strategy is profitable to improve performance.  The next section on Twiddle will show you how to quickly run multiple scenarios based on a set of parameters.

Figure 4. Strategy statistics - The Palantir platform calculates many useful statistics on the performance of the strategy such as Profit and Loss, Sharpe Ratio, and performance versus a benchmark (S&P 500 [SPX]).

Figure 5. Result Charts - The chart tab also shows a graph of strategy NAV by date and also lines up winning trades (green) and losing trades (red) against the price of the stock or instrument.


Twiddle is another great feature that allows you to quickly run a series of simulations based on a range of parameters. In this example, the twiddle feature calculates the strategy results based on entryDayRange values between 10 to 30, in increments of 5, and exitDayRange values of 6 to 14, in increments of 2, to generate the matrix below.  Based on this analysis, the profit maximized setting for this specific period and strategy combination would be a 15 day entryDayRange value and a 12 or 14 exit day range; however, the additional gains do come with a higher sharpe ratio, meaning that the strategy is riskier.

Figure 6. Twiddle matrix - Each matrix cell represents a strategy simulation using the parameters on the horizontal and vertical axes.

Summary and JoyRide

As you can see, the Palantir Finance platform makes it very easy to implement, back-test, and twiddle custom strategies. You can test drive Palantir Finance at https://joyride.pfinance.com/welcome/. The custom metric “TrueRange” and strategy “Breakout” are saved and available to all JoyRide users. With a JoyRide account, you can create your own custom metrics and strategies or just explore any feature on the Palantir Finance platform.

NOTE: If you change the instrument MSFT to another stock like GLD (Gold ETF) in the strategy, you may need to disambiguate between different instruments of the same symbol by pressing CTRL-period in the code editor to select the correct instrument.