Tested by BacktestingMax
Turtle Trading System 1 (20/10) backtest
Does Turtle Trading System 1 still work?
Yes, but only a little, and less than before. Turtle Trading System 1 buys when price breaks above the 20-day high and sells short (sells first, to make money if price falls) when it breaks below the 20-day low. We backtested it on daily charts of 8 currency pairs, gold and silver, from 2007 to 2025, after trading costs, with each market as a separate backtest at 1% risk per trade (the Turtles risked 2%). It made money on 7 of the 10 markets; the best was silver, +29.1% in 19 years. On the 10 markets together, the trades that opened from 2007 to 2018 made +83.2R, but those that opened from 2019 to 2025 made only +12.4R (R is the money one trade risks: 1% of the account). In 2019–2025, only 6 of the 10 markets made money. The filter, which skips the next breakout after a winning one, gave a better result on 9 of the 10 markets, though less so in 2019–2025. The 55-day failsafe (entering at a 55-day breakout when the filter skips one) did better than the basic rules on 7 of the 10 markets in 2019–2025. System 1 also beat Donchian's simpler four-week rule on 4 of the 5 markets that both tests share. Overnight (swap) fees are not included.
10 backtests 2007–2025 Trading costs included Tested 19 October 2026
Where it worked 10 backtests- Made money
- 7 of 10 tests, using the basic rules
- Made money in both periods
- 4 2007–2018 and again 2019–2025
- Best backtest
- +29% Silver, daily chart: account growth 2007–2025
- With the 55-day failsafe breakout
- 4 tests made money in both periods, compared with 4 using the basic rules
Made money in both periods
- USD/JPY, daily
- GBP/JPY, daily
- Gold, daily
- Silver, daily
The results
Results on every market
Each box shows one backtest of the Turtle Trading System 1 using the basic rules, from 2007 to 2025, after trading costs: the % result, and a small chart of the account balance. The solid line is the account balance and the dashed line is the starting balance. Green results made money; red results lost money. Under each result: whether it made money in both 2007–2018 and 2019–2025, or passed all four of our checks (see "How a test passes" further down).
| Market | daily |
|---|---|
| EUR/USD | +11% Made money overall, lost in one period |
| GBP/USD | +0.7% Made money overall, lost in one period |
| USD/JPY | +15% Passed all four checks |
| AUD/USD | −7% Lost money |
| USD/CAD | −4% Lost money |
| USD/CHF | −2% Lost money |
| EUR/JPY | +18% Made money overall, lost in one period |
| GBP/JPY | +12% Made money in both periods |
| Gold | +22% Passed all four checks |
| Silver | +29% Passed all four checks |
All the numbers, test by test
| Market | Chart | Trades | Win rate | Profit factor | Result | Max drawdown | 2007–2018 | 2019–2025 | Monte Carlo drawdown | Trading costs |
|---|---|---|---|---|---|---|---|---|---|---|
| EUR/USD | daily | 136 | 41.2% | 1.17 | +10.6% | −16.8% | +15.9% | −4.5% | −15.7% | $34 |
| GBP/USD | daily | 147 | 36.7% | 1.01 | +0.7% | −12.1% | +4.8% | −3.9% | −17.0% | $37 |
| USD/JPY | daily | 121 | 41.3% | 1.32 | +15.1% | −9.7% | +0.1% | +15.0% | −14.8% | $33 |
| AUD/USD | daily | 143 | 37.8% | 0.90 | −7.0% | −19.4% | +11.5% | −16.5% | −22.5% | $49 |
| USD/CAD | daily | 158 | 31.6% | 0.94 | −4.3% | −14.4% | −6.8% | +2.7% | −22.2% | $55 |
| USD/CHF | daily | 134 | 42.5% | 0.96 | −2.2% | −16.6% | −3.3% | +1.2% | −17.3% | $60 |
| EUR/JPY | daily | 142 | 39.4% | 1.28 | +17.9% | −10.2% | +19.2% | −1.1% | −16.4% | $46 |
| GBP/JPY | daily | 131 | 42% | 1.24 | +12.4% | −9.5% | +12.1% | +0.2% | −13.4% | $52 |
| Gold | daily | 129 | 38.8% | 1.47 | +22.2% | −6.5% | +0.3% | +21.8% | −12.5% | $44 |
| Silver | daily | 131 | 42% | 1.61 | +29.1% | −6.6% | +19.2% | +8.2% | −10.3% | $122 |
Profit factor is the money won divided by the money lost. Above 1 means the test made money. Max drawdown is the biggest fall from the highest balance. 2007–2018 and 2019–2025 show the result in each period on its own. Monte Carlo drawdown: we shuffled the trades into a random order 1,000 times; in 95% of those runs, the worst drawdown was this number or less. Result is the change in the account, with the risk of each trade set to 1% of the account at that time.
The account balance
The best test and the middle test
What we found
What the 10 backtests show
System 1 did better than Donchian's simpler four-week rule on 4 of the 5 markets that our two tests share. The four-week rule, from our Donchian channel breakout test, buys at a daily close above the 20-day high, sells short at a close below the 20-day low, and is almost always in a trade: it has no 10-day exit and no filter. For the trades that opened from 2007 to 2025, the results were: GBP/USD +1.4R for System 1 against −8.8R for the four-week rule, USD/JPY +15.3R against +0.9R, GBP/JPY +12.5R against 0.0R, and gold +21.2R against +17.3R. On EUR/USD, the two made about the same: +11.2R and +11.8R. R is the money one trade risks: 1% of the account.
The buys made most of the profit on gold (+26.7R), silver (+24.8R) and USD/JPY (+24.2R). The sells made the money on EUR/USD (+10.1R), USD/CHF (+7.2R) and AUD/USD (+4.4R), where the buys lost money or made little. On all 10 markets together, the 674 buys made +90.8R and the 698 sells made +4.9R.
The 1,185 trades that lasted more than a week made +263.4R in total, and the 187 trades that ended within a week lost 167.7R.
The filter (the rule that skips the next breakout after a winning one) helped, more in 2007–2018 than in 2019–2025. From 2007 to 2025, 7 of the 10 markets made money with the filter, and 6 when we took every breakout. The filter gave the better result on 9 of the 10 markets. USD/JPY was the exception: +25.3% when we took every breakout, and +15.1% with the filter. In 2019–2025 alone, taking every breakout did better on 6 of the 10 markets, but the skipped breakouts that opened in those years still lost 10.2R in total (see 'The filter' below).
Making a winning trade bigger, as the Turtles did, made both the gains and the losses bigger. We added one more unit, the size of the first trade, each time price moved 0.5N further in the trade's direction, up to 4 units. Gold then made +121.2% instead of +22.2%, and silver +180.9% instead of +29.1%. But GBP/USD lost 34.6%, USD/CAD 22.7% and USD/CHF 16.9%. On the 8 currency pairs, the max drawdown (the biggest fall from the highest balance) was 22.8% to 49.1%, compared with 9.5% to 19.4% with one unit. In 2019–2025, this version made money on only 4 of the 10 markets, compared with 6 with one unit.
Year by year
The result of each year, all 10 markets together
Each bar adds up the results of the trades that opened in that year, on all 10 markets, with the basic rules. R is the money one trade risks: 1% of the account. For example, +10R means that the trades of that year together made 10 times the amount one trade risks.
- 200758 trades +14.4R
- 200865 trades +20.1R
- 200972 trades −8.5R
- 201078 trades +11.0R
- 201179 trades −2.8R
- 201260 trades +24.7R
- 201377 trades +16.8R
- 201475 trades +20.8R
- 201566 trades +5.6R
- 201691 trades −15.9R
- 201776 trades −3.3R
- 201873 trades +0.3R
- 201985 trades −8.4R
- 202067 trades −9.6R
- 202165 trades +1.3R
- 202280 trades +3.9R
- 202366 trades +12.6R
- 202464 trades +10.4R
- 202575 trades +2.2R
The trades that opened from 2007 to 2018 made +83.2R in total, and those that opened from 2019 to 2025 made +12.4R. System 1 lost money in 6 of the 19 years: 2009, 2011, 2016, 2017, 2019 and 2020. From 2016 to 2020, the trades lost 36.9R in total. From 2021 to 2025, every year made money: +30.4R in total.
The filter
The breakouts that System 1 skips lost money
To see what the filter does, we took every 20-day breakout on the 10 markets from 2007 to 2025, with no filter. Then we split these trades into two groups, by how the breakout before them ended. The first group is almost the same breakouts that the basic rules take, and the second group is the breakouts they skip. R is the money one trade risks: 1% of the account.
- After a losing breakout
- +96.7R 1,369 trades, 38.6% of them made money. System 1 takes these breakouts.
- After a winning breakout
- −29.4R 784 trades, 33.2% of them made money. System 1 skips these breakouts.
For the trades that opened from 2007 to 2018, the breakouts after a winning breakout lost 19.2R, and they lost money on 8 of the 10 markets. The breakouts after a losing breakout made +81.4R. For the trades that opened from 2019 to 2025, the breakouts after a winning breakout lost 10.2R, but they lost money on only 5 of the 10 markets. The breakouts after a losing breakout made +15.3R. Over the whole test, the breakouts after a winning breakout lost money on 7 of the 10 markets. These groups come from the backtest that took every breakout. Its account balance, and so its trade sizes, were not the same as with the filter, so its numbers differ a little from the results of the basic rules. The first breakout on each market has no breakout before it, so it is in neither group.
Stock indices
System 1 on stock indices, from 2019 to 2025
Our stock index price data before 2019 has known problems: extra short candles after the Friday close, and, on short charts, overnight prices that often don't move. So, to be safe, we tested 5 stock indices from January 2019 to December 2025 only. These are separate backtests from the 10 markets above, with the same rules and the same 3 changes we test further down. Each result is the change in the account, after trading costs. The last column is how much the index itself rose.
| Index | Trades (basic rules) | Basic rules | With no filter | With added units | With the 55-day failsafe | The index itself |
|---|---|---|---|---|---|---|
| S&P 500 | 39 | +12.8% | +13.3% | +14.0% | +16.6% | +173.2% |
| Nasdaq 100 | 42 | +0.9% | +9.9% | −10.2% | +11.1% | +298.3% |
| Dow Jones | 48 | +2.6% | −2.9% | −2.6% | −5.5% | +106.3% |
| DAX | 61 | +0.9% | −1.6% | −10.8% | −0.6% | +131.5% |
| FTSE 100 | 59 | −3.7% | −12.6% | −3.6% | −12.2% | +48.0% |
Every index rose a lot in these 7 years, but System 1 made little on them. The best result was +16.6%, on the S&P 500 with the failsafe. With the basic rules, each index made only 39 to 61 trades, fewer than the 100 we need to judge one test. On the 5 indices together, the buys made +17.6R and the sells lost 3.5R. R is the money one trade risks: 1% of the account.
The strategy
What the Turtle Trading System 1 is
Turtle Trading System 1 is a trend-following breakout system: it trades in the direction price is already moving. A breakout is when price moves above the highest price, or below the lowest price, of a recent period. In 1983 and 1984, the traders Richard Dennis and William Eckhardt taught two breakout systems to a group of new traders they called the Turtles. System 1 is the shorter-term one. It buys when price rises above the highest price of the last 20 days, and it sells short when price falls below the lowest price of the last 20 days. It closes a buy when price falls to the lowest price of the last 10 days, and it closes a sell when price rises to the highest price of the last 10 days. That is why traders call it '20/10'. System 1 also has a filter: if the last breakout made money, skip the next one. The stop-loss and the trade size use N, the Turtles' name for the average true range (ATR) of the last 20 days. ATR measures how far price moves in an average day, including the gaps between days. We took the entry, exit, stop-loss and filter rules from 'The Original Turtle Trading Rules', published by Curtis Faith, one of the Turtles. Our basic version trades one position at a time (one unit), at half the Turtles' risk, without adding units and without the 55-day failsafe breakout (when the filter skips a 20-day breakout, enter at a 55-day breakout instead). We test both of these further down. System 2, the Turtles' other system, enters at a 55-day breakout and exits at the 20-day low or high.
- Entry
- A stop order at the 20-day high (buy) and at the 20-day low (sell short), renewed at every daily close
- Exits
- The 10-day low for a buy and the 10-day high for a sell, or the 2N stop-loss, whichever comes first
- N
- The 20-day average true range, smoothed like the Turtles: (19 × the day before's N + that day's true range) ÷ 20
- Filter
- Skip the breakout after a breakout that made money
- Units
- One unit per trade. Adding units to a winning trade, as the Turtles did, is a change we tested further down.
- Risk per trade
- 1% of the account at 2N, as in our other backtests. The Turtles' unit lost 1% of the account for each N that price moved, so 2% at 2N.
- Closing at the next open
- The Turtles closed a trade during the day, at the 10-day level. Our backtest closes it at the next day's open. To see what this changes, we ran a separate, simpler check of every breakout, with no filter and no trading costs, measuring each trade by how far price moved, with 1R being a move of 2N: once closing at the 10-day level during the day, and once at the next day's open. Closing at the next open gave between 7.9R less and 12.7R more on each market, and 16.8R more on the 10 markets together. This check measures R in a simpler way than the backtests on this page, so only the difference between the two exits counts, not its totals.
- Trading costs
- The only trading cost is one fixed spread per market: the gap between the buy price and the sell price. On the currency pairs, the spread is in pips. A pip is a price move of 0.0001, or 0.01 on the pairs with the Japanese yen (JPY). The spread is 0.8 pips on EUR/USD, 1.2 on GBP/USD, 0.9 on USD/JPY, 1.0 on AUD/USD, 1.3 on USD/CAD, 1.5 on USD/CHF, 1.4 on EUR/JPY and 2.5 on GBP/JPY. On gold it is $0.30 an ounce, and on silver $0.02. It is 0.4 points on the S&P 500, 1.5 on the Nasdaq 100, 2 on the Dow Jones, and 1 on the DAX and the FTSE 100. We added no commission (a fee per trade) and no slippage (a worse price than the order's). In the backtest, a stop order opens the trade at its level, or at the day's open if price opens beyond it, without paying the spread. Closing the trade pays half of the spread. So each trade pays half of the spread in total.
- Smallest trade size
- When one unit was smaller than the smallest trade size the market allows (1,000 of the first currency of a pair, such as 1,000 euros on EUR/USD; 1 ounce of gold; 50 ounces of silver; 0.1 of an index contract), the test used the smallest size, if it lost no more than 2% at 2N. On the 10 markets, this happened on 7 of the 1,372 trades: 1 on gold and 6 on silver, which risked 1.1% to 1.5% of the account. No breakout was skipped because of the trade size. On the stock indices, 15 of the 48 Dow Jones trades and 1 Nasdaq 100 trade used the smallest size, risking up to 2.0%.
- Days that count
- Only trading days count for the highs, the lows and N: days when price moved. Some of our price data has a short extra candle after the Friday close, and it does not count as a day.
- Overnight (swap) fees
- Not included. Brokers charge (or sometimes pay) a fee for each night a trade stays open. Half of the trades lasted 18 days or more, and a trade was open 42% to 51% of the time on each market. The gains here are small, about 1% a year or less, so these fees could change the results a lot.
- What we did not test
- The Turtles traded many markets at once in one account, with limits on how many units to hold across related markets, and they traded smaller after the account fell. We did not test this: each backtest here trades one market on its own, with its own $10,000 account.
The rules we tested
- N is the average true range of the last 20 days. The true range of a day is the biggest of three distances: from the high to the low, from the day before's close to the high, and from the day before's close to the low. Like the Turtles, we smooth N every day: N = (19 × the day before's N + that day's true range) ÷ 20.
- At every daily close, place an order to buy at the highest price of the last 20 days, and an order to sell short at the lowest price of the last 20 days. Selling short means you sell first and buy back later, so the trade makes money if the price falls. These are stop orders: each one opens the trade during the day, as soon as price reaches its level. If price opens beyond the level, the trade opens at the open.
- The filter: skip the breakout if the last breakout made money, whether it was a buy or a sell. A skipped breakout still counts as the last breakout. We follow it with the same stop-loss and exit, to see whether it would have made money. A breakout made money if its trade would have closed at a profit. A trade that hits its stop-loss is a loser, even if price turns around later.
- The stop-loss is 2N from the breakout level: 2N below it for a buy, and 2N above it for a sell. If the lowest price of the last 10 days (for a buy) or the highest price of the last 10 days (for a sell) is closer, the stop-loss goes there instead. It stays where it was placed.
- The 10-day exit: when price touches the lowest price of the last 10 days (for a buy) or the highest price of the last 10 days (for a sell), the trade closes at the next day's open. The Turtles closed it at that price, during the day.
- Size each trade so that it loses 1% of the account if price moves 2N against it from the breakout level. This size is one unit. If one unit is smaller than the smallest trade size the market allows, use the smallest size, but only if it loses no more than 2% of the account at 2N. Otherwise, skip the trade.
The method
How we tested it
The test
- Markets
- EUR/USD, GBP/USD, USD/JPY, AUD/USD, USD/CAD, USD/CHF, EUR/JPY, GBP/JPY, Gold and Silver
- Charts
- daily candles
- Dates
- January 2007 to December 2025
- Account
- $10,000, risking 1% of the account on each trade
- Trading costs
- Included. Every trade pays that market's normal trading cost: the spread, which is the gap between the buy price and the sell price.
How a test passes
We call a test passed only if it meets all four checks. A strategy can make money in one backtest and still fail one of these checks.
- At least 100 trades. With fewer trades, a good result could be luck.
- It made money from 2007 to 2018 and again from 2019 to 2025. This shows whether the strategy kept working in the newer years, not only in the older ones.
- A profit factor (the money won divided by the money lost) of at least 1.2 from 2019 to 2025, after trading costs.
- In 95% of 1,000 random shuffles of the trades, the account must not fall more than 30% from its highest point.
Improvements
Can the Turtle Trading System 1 be improved?
Traders argue about three of the Turtles' rules: the filter, adding units, and the 55-day failsafe breakout. So we tested 3 changes to the basic rules, one at a time, on the same 10 markets from 2007 to 2025: taking every breakout, adding units, and the failsafe. If you pick the best version and judge it on the same years, it will almost always look good. So we picked the best one using 2007–2018 only, by the number of tests that made money, and by the middle test when two versions tie. Then we checked it on 2019–2025, the years we did not use to pick it.
| Version | Made money 2007–2018years used to pick the best version | Made money 2019–2025years not used to pick it | Made money in both periods | Passed all four checks |
|---|---|---|---|---|
| Basic System 1: with the filter, one unit The rules under 'The rules we tested': skip the breakout after a winning breakout, trade one unit, and no 55-day failsafe. | 8 of 10middle test +8.2% | 6 of 10middle test +0.7% | 4 | 3 |
| With no filter: every breakout taken Take every 20-day breakout, also right after a breakout that made money. Everything else stays the same. | 8 of 10middle test +4.0% | 6 of 10middle test +1.1% | 4 | 3 |
| With added units: up to 4 As the Turtles did, make a winning trade bigger: add one more unit, the same size as the first trade, each time price moves 0.5N further in the trade's direction, up to 4 units. Each unit has its own stop-loss, 2N from its entry. When price reaches the stop-loss of the newest unit, all the units close: the newest at its stop-loss, the others at the next day's open. In the Turtles' rules, the older units' stop-losses move up to that level; in this backtest, a stop-loss stays where it was placed. Each unit counts as one trade. | 6 of 10middle test +19.5% | 4 of 10middle test −5.9% | 2 | 2 |
| With the 55-day failsafe breakoutBest on 2007–2018 When the filter skips a breakout, enter at the 55-day breakout in the same direction instead: buy at the 55-day high after a skipped buy, or sell short at the 55-day low after a skipped sell. The Turtles' original rules have this 'failsafe', so that a big trend is not missed. Its trades have the same stop-loss and 10-day exit. | 8 of 10middle test +9.4% | 6 of 10middle test +3.7% | 4 | 3 |
The 55-day failsafe breakout did a little better than the basic rules. It did best on 2007–2018, the years we used to pick: 8 of 10 tests made money, the same as with the basic rules, but the middle test (half of the 10 did better, half did worse) made +9.4%, compared with +8.2%. In 2019–2025, the years we kept for the check, the failsafe version made money on 6 of 10 markets, like the basic rules, but its middle test made +3.7% instead of +0.7%, and 7 of the 10 markets did better with it than with the basic rules. With either version, the same 4 markets made money in both periods: USD/JPY, GBP/JPY, gold and silver. Taking every breakout did worse than the basic rules on 9 of the 10 markets from 2007 to 2025, but better on 6 of the 10 in 2019–2025 alone. Adding units made the biggest gains, on gold and silver, but it made money on only 4 of 10 markets in 2019–2025, and it had the biggest drawdowns.
Passed all four checks with the 55-day failsafe breakout
- USD/JPY, daily
- Gold, daily
- Silver, daily
Questions
Questions traders ask
Does Turtle trading still work?
Yes, but only a little, and less than before, in our backtest. Turtle Trading System 1 buys at a 20-day high, sells short at a 20-day low, closes a buy at the 10-day low and a sell at the 10-day high, and skips the next breakout after a winning one. On daily charts of 8 currency pairs, gold and silver, after trading costs, the trades that opened from 2007 to 2018 made +83.2R on the 10 markets together, and those that opened from 2019 to 2025 made +12.4R (R is the money one trade risks: 1% of the account). It made money on 7 of the 10 markets from 2007 to 2025, and on 6 of the 10 in 2019–2025 alone. On 5 stock indices from 2019 to 2025, System 1 made between −3.7% and +12.8%, while every index rose 48% or more.
Should you skip a breakout after a winning trade?
In our backtest, skipping helped, mostly in 2007–2018. That is System 1's filter: if the last 20-day breakout made money, skip the next one. When we took every breakout on the 10 markets from 2007 to 2025, the 784 breakouts right after a winning breakout lost 29.4R in total, and the 1,369 breakouts right after a losing breakout made +96.7R (R is the money one trade risks: 1% of the account). With the filter, the result from 2007 to 2025 was better on 9 of the 10 markets; USD/JPY was the exception. In 2019–2025 alone, taking every breakout did better on 6 of the 10 markets, but the skipped breakouts that opened in those years still lost 10.2R in total.
Does adding units (pyramiding) improve the Turtle system?
Not overall, in our backtest. Adding units means making a winning trade bigger: the Turtles added one more unit, the size of the first trade, each time price moved 0.5N further in the trade's direction, up to 4 units. N is the average true range of the last 20 days: how far price moves in an average day. From 2007 to 2025, adding units turned gold's +22.2% into +121.2% and silver's +29.1% into +180.9%. But it made money on 6 of the 10 markets instead of 7, and on the 8 currency pairs the max drawdown (the biggest fall from the highest balance) grew to 22.8% to 49.1%. In 2019–2025, it made money on only 4 of the 10 markets, compared with 6 with one unit.
Which markets does the Turtle trading system work best on?
In our test: silver, gold and the yen pairs. From 2007 to 2025, System 1 made +29.1% on silver, +22.2% on gold, +17.9% on EUR/JPY, +15.1% on USD/JPY and +12.4% on GBP/JPY, risking 1% of the account on each trade. On gold, silver and USD/JPY, most of the profit came from buys. It lost money on AUD/USD (−7.0%), USD/CAD (−4.3%) and USD/CHF (−2.2%). USD/JPY, GBP/JPY, gold and silver made money in both 2007–2018 and 2019–2025, but 3 of them barely: USD/JPY (+0.1%) and gold (+0.3%) in 2007–2018, and GBP/JPY (+0.2%) in 2019–2025. On stock indices, we could only test 2019 to 2025, with 39 to 61 trades per index, too few to judge one market: System 1 made +12.8% on the S&P 500, and between −3.7% and +2.6% on the Nasdaq 100, the Dow Jones, the DAX and the FTSE 100.
Keep exploring
Related strategies we tested
Donchian Channels Donchian channel breakout strategy backtest Made money in 9 of 30 tests, 5 of them in both periods. Best: USD/JPY, 1-hour, +102%The strategy code we ran
This is the exact code from the BacktestingMax strategy engine. Paste it into the strategy editor in the app to run it on any market.
class TurtleSystemOne(Strategy):
"""Turtle Trading System 1 (20/10), from "The Original Turtle Trading Rules" (Curtis Faith),
on a daily chart.
A day counts only if price moved during it and it is not the short candle some price data
has after the Friday close. N is the Turtles' average true range: the first N is the average
true range of 20 days, then each day N = (19 x the day before's N + today's true range) / 20.
Standard (all switches off), one unit at a time:
Entry a stop order to buy at the highest high of the last 20 days and one to sell
short at the lowest low of the last 20 days, renewed at every daily close. The
trade opens during the day, when price reaches that level (or at the open, when
price opens beyond it).
Filter skip the breakout if the last System 1 breakout, buy or sell, made money.
Skipped breakouts count too: each one is followed with the same exits, to know
whether it made money.
Exits the trade closes when price touches the lowest low of the last 10 days (for a
buy) or the highest high of the last 10 days (for a sell), or at a stop-loss
2N from the breakout level, whichever comes first.
The stop order that opens with the trade sits 2N from the breakout level, or
at the 10-day low or high if that is closer. It does not move. When price
later touches a newer 10-day low or high, the trade closes at the next day's
open: an order can't be moved every day here.
Size one unit: the trade loses 1% of the account at 2N. When that is less than the
smallest trade size the market allows, use the smallest size if it loses no
more than 2%; otherwise skip the trade.
The changes, one at a time:
no_filter = 1 take every breakout
add_units = 1 add one more unit each time price moves 0.5N further in the trade's
direction, up to 4 units. Each unit has its own stop order, 2N from its
entry (or at the 10-day low or high, if closer). When price reaches the
stop of the newest unit, every unit closes: the newest at its stop, the
others at the next day's open.
failsafe = 1 when the filter skips a breakout, buy at the 55-day high or sell short at
the 55-day low instead
"""
params = {"entry_days": Param(type=int, default=20, min=5, max=55),
"exit_days": Param(type=int, default=10, min=2, max=55),
"stop_n": Param(type=float, default=2.0, min=0.5, max=5.0),
"no_filter": Param(type=int, default=0, min=0, max=1),
"add_units": Param(type=int, default=0, min=0, max=1),
"failsafe": Param(type=int, default=0, min=0, max=1)}
max_open_positions = 4 # room for 4 units with add_units = 1; otherwise one unit at a time
lookback = 5
def init(self, ctx):
self.ny = ctx.clock("America/New_York")
self.stop_n = ctx.params.stop_n
self.highs = [] # the highs and lows of the last 55 trading days, oldest first
self.lows = []
self.ranges = [] # the first 20 true ranges, until N starts
self.n = None # N: the Turtles' 20-day average true range
self.prev_close = None
self.lv = None # the levels set at the last trading day's close
self.last_won = None # did the last System 1 breakout make money? None before the first
self.s1 = None # System 1's breakout trade, taken or skipped: [side, entry, stop, exit_due]
self.armed = False # True when a breakout on the next candle is System 1's next breakout
self.group = None # our open trade: side, kind, N, unit size, unit ids, stop-loss, last entry
self.pending = None # what the resting entry orders are: kind, N, and unit size per side
self.resting = [] # ids of the entry orders waiting to fill
def on_bar(self, ctx):
o, h, l, c = ctx.open[0], ctx.high[0], ctx.low[0], ctx.close[0]
if self.lv is not None:
self.follow_s1(o, h, l, c)
self.manage_trade(ctx, h, l)
self.update_levels(ctx, h, l, c)
self.place_orders(ctx)
# ---- System 1's breakouts, taken or skipped (the filter reads their results) --------------
def follow_s1(self, o, h, l, c):
"""Follow System 1's breakout trade with the plain rules (one unit, the same stop order and
10-day exit as a real trade), whether we took it or skipped it."""
lv, s = self.lv, self.s1
if s is None:
if not self.armed:
return
up, down = h >= lv["hi"], l <= lv["lo"]
if up and down: # one candle crossed the whole channel: count the side nearer the open
up = lv["hi"] - o <= o - lv["lo"]
down = not up
if not (up or down):
return
side = 1 if up else -1
level = lv["hi"] if up else lv["lo"]
entry = max(o, level) if up else min(o, level)
stop = self.first_stop(side, level, lv["n"])
self.start_s1(side, entry, stop)
if (c - stop) * side <= 0: # closed beyond the stop-loss, so it was hit after the entry
self.end_s1(stop)
return
side, entry, stop, due = s
worst = l if side == 1 else h # the price furthest against the trade
exit_level = lv["x_lo"] if side == 1 else lv["x_hi"]
if due:
self.end_s1(o) # the 10-day exit, at this candle's open
elif (worst - stop) * side <= 0:
self.end_s1(min(o, stop) if side == 1 else max(o, stop)) # an open beyond it fills there
elif (worst - exit_level) * side <= 0:
s[3] = True # touched the 10-day exit: closes at the next open
def start_s1(self, side, entry, stop):
self.s1 = [side, entry, stop, False]
def end_s1(self, exit_price):
side, entry = self.s1[0], self.s1[1]
self.last_won = (exit_price - entry) * side > 0
self.s1 = None
# ---- Our trade -----------------------------------------------------------------------------
def manage_trade(self, ctx, h, l):
"""Note new units, and close every unit at the next open once price touches the 10-day
exit or the stop of the newest unit."""
pos = ctx.positions
if not pos:
self.group = None
return
side = 1 if pos[0].is_long else -1
g = self.group
if g is None:
p = self.pending
g = self.group = {"side": side, "kind": p["kind"] if p else "", "n": p["n"] if p else 0.0,
"size": p["size"][side] if p else 0.0, "ids": [], "stop": None,
"last": None, "exit": p is None}
if any(q.is_long != pos[0].is_long for q in pos):
g["exit"] = True # a buy and a sell both filled: one candle crossed the whole channel
if g["exit"]:
ctx.close_all()
return
ids = [q.position_id for q in pos]
lost = [i for i in g["ids"] if i not in ids]
new = [i for i in ids if i not in g["ids"]]
g["ids"] = ids
if lost: # a unit's stop order was hit: close the other units too
ctx.close_all()
g["exit"] = True
return
if new: # units opened during this candle: their own stop orders are enough for today
stops = [q.sl_price for q in pos]
entries = [q.entry_price for q in pos]
g["stop"] = max(stops) if side == 1 else min(stops)
g["last"] = max(entries) if side == 1 else min(entries)
return
worst = l if side == 1 else h
exit_level = self.lv["x_lo"] if side == 1 else self.lv["x_hi"]
if (worst - exit_level) * side <= 0 or (worst - g["stop"]) * side <= 0:
ctx.close_all()
g["exit"] = True
# ---- Levels and orders ---------------------------------------------------------------------
def update_levels(self, ctx, h, l, c):
"""N and the 10-, 20- and 55-day highs and lows at this close, from trading days only."""
if h <= l or self.ny.weekday in (4, 5):
return # no price movement, or the short candle after the Friday close: not a trading day
if self.prev_close is not None:
tr = max(h - l, abs(h - self.prev_close), abs(l - self.prev_close))
if self.n is None:
self.ranges.append(tr)
if len(self.ranges) == 20:
self.n = sum(self.ranges) / 20
else:
self.n = (19 * self.n + tr) / 20
self.prev_close = c
self.highs.append(h)
self.lows.append(l)
if len(self.highs) > 55:
self.highs.pop(0)
self.lows.pop(0)
e, x = ctx.params.entry_days, ctx.params.exit_days
if self.n is None or len(self.highs) < max(e, x):
return
full = len(self.highs) == 55
self.lv = {"hi": max(self.highs[-e:]), "lo": min(self.lows[-e:]),
"x_hi": max(self.highs[-x:]), "x_lo": min(self.lows[-x:]),
"f_hi": max(self.highs) if full else None, "f_lo": min(self.lows) if full else None,
"n": self.n}
def place_orders(self, ctx):
"""Renew the resting entry orders for the next candle."""
for oid in self.resting:
ctx.cancel_order(oid)
self.resting = []
self.armed = False
self.pending = None
lv, g = self.lv, self.group
if lv is None:
return
if g is not None:
units = len(g["ids"])
if ctx.params.add_units == 1 and not g["exit"] and 0 < units < 4:
for k in range(1, 5 - units):
at = g["last"] + g["side"] * k * 0.5 * g["n"]
self.order(ctx, g["side"], at, g["n"], g["size"], g["kind"] + "_add")
return
if ctx.positions:
return
blocked = ctx.params.no_filter == 0 and self.last_won is True
if self.s1 is None:
self.armed = True # a breakout on the next candle is System 1's next breakout
if ctx.gate("last_breakout_lost", not blocked):
self.place_entries(ctx, "s1", lv["hi"], lv["lo"], 4 if ctx.params.add_units == 1 else 1)
return
if blocked and ctx.params.failsafe == 1 and lv["f_hi"] is not None:
self.place_entries(ctx, "failsafe", lv["f_hi"], lv["f_lo"], 1)
def place_entries(self, ctx, kind, hi, lo, units):
"""Stop orders to buy at hi and to sell short at lo (more units 0.5N beyond, if any)."""
n = self.lv["n"]
sizes = {}
for side, level in ((1, hi), (-1, lo)):
size, smallest = self.unit_size(ctx, level, level - side * self.stop_n * n)
sizes[side] = size
if not ctx.gate("size_fits", size > 0):
continue # even the smallest trade size would lose more than 2%: skip this side
tag = kind + ("_min" if smallest else "")
for k in range(units):
self.order(ctx, side, level + side * k * 0.5 * n, n, size, tag if k == 0 else tag + "_add")
self.pending = {"kind": kind, "n": n, "size": sizes}
def unit_size(self, ctx, entry, stop):
"""One unit loses 1% of the account at 2N. Below the smallest trade size, use the
smallest size if it loses no more than 2%. Returns (size, smallest size used)."""
size = ctx.size_by_risk_pct(0.01, stop=stop, entry=entry)
if size > 0:
return size, False
return ctx.size_by_risk_pct(0.02, stop=stop, entry=entry), True
def first_stop(self, side, at, n):
"""The stop order for a unit that opens at 'at': 2N away, or at the 10-day low (a buy)
or high (a sell) when that is closer, since the 10-day exit then comes first."""
stop = at - side * self.stop_n * n
exit_level = self.lv["x_lo"] if side == 1 else self.lv["x_hi"]
if 0 < (at - exit_level) * side < self.stop_n * n:
stop = exit_level
return stop
def order(self, ctx, side, at, n, size, tag):
"""A stop order to open one unit at the price 'at', with its stop order (first_stop)."""
stop = self.first_stop(side, at, n)
if side == 1:
o = ctx.buy(size=size, stop=at, sl=stop, tag=tag + "_long")
else:
o = ctx.sell(size=size, stop=at, sl=stop, tag=tag + "_short")
if o is not None:
self.resting.append(o.order_id)
Your turn
Test the Turtle Trading System 1 yourself
Change the settings, the market or the stop-loss and see the result in seconds. Ask the BacktestingMax AI: Backtest Turtle Trading System 1 on gold, daily chart, from 2007 to 2025: buy at the 20-day high and sell short at the 20-day low with stop orders, close at the 10-day low or high, stop-loss 2 times the 20-day ATR, skip the next breakout after a winning breakout, 1% risk per trade
.
Free account. No credit card needed.
See every strategy we tested Browse strategies shared by tradersBacktest on historical data with trading costs, run by BacktestingMax. Past results do not guarantee future results, and nothing here is financial advice. Updated 19 October 2026.