0bps

Strategy vault / Breakout

Turtle Trading Decision System

The Turtle Trading Decision System is a trend-following trading strategy based on the breakout theory. It generates trading signals by moving averages of highest and lowest prices over specific periods to identify…

Author
ChaoZhang
Complexity
Intermediate · 170 lines
Parameters
13
Backtest bar
1d · swing
Tested on
BTC/USDT · futures

IMG

Overview

The Turtle Trading Decision System is a trend-following trading strategy based on the breakout theory. It generates trading signals by moving averages of highest and lowest prices over specific periods to identify potential trends. Trading signals are generated when prices break out above or below the highest or lowest prices over the specified periods. The strategy also incorporates trailing stops, pyramiding, and money management modules to form a relatively complete decision system.

Strategy Principle

The core strategy signals of the Turtle Trading Decision System are generated by comparing the price with the highest prices over N1 periods and the lowest prices over N2 periods. A long signal is generated when the price crosses above the highest price over N1 periods. A short signal is generated when the price crosses below the lowest price over N2 periods. The shutdown mode is used to control new signal generation.

After opening a position, the price will be compared with the stop loss price in real time to generate trailing stop signals. Also, compare the price with the add-on line to generate pyramiding signals. Both stop loss price and add-on line are related to ATR.

When opening a position each time, the position unit is calculated by taking a certain percentage of the initial capital to avoid the impact of a single loss on the total capital. Single losses are limited within a certain range.

Advantage Analysis

The Turtle Trading Decision System has the following advantages:

  1. Capture potential trends: By comparing prices with highest and lowest prices over periods to determine potential trend directions, potential price trends can be captured earlier.

  2. Risk management: Use money management and stop loss to control single and overall loss risks.

  3. Pyramiding management: Appropriate pyramiding can obtain additional profits from trends.

  4. Integrity: Combining money management, stop loss management and pyramiding management makes the decision system more complete.

  5. Simple and clear: The signal generation rules are simple and straightforward, easy to understand and verify.

Risk Analysis

The Turtle Trading Decision System also has some risks:

  1. False breakout risk: Prices may have false breakouts above or below the highest or lowest prices, causing wrong signals. Parameters can be adjusted appropriately to filter out some false breakouts.

  2. Trend reversal risk: There is a risk that the loss increases after pyramiding when prices reverse. The number of pyramiding should be limited appropriately and stops losses in time.

  3. Parameter optimization risk: Parameters settings can vary greatly for different markets, parameters should be optimized separately for each market to reduce risks.

Optimization Directions

The Turtle Trading Decision System can also be optimized in the following aspects:

  1. Add filters: Detect the momentum of price breakouts to filter out some false breakouts.

  2. Optimize stop loss strategies: How to reasonably track stop losses and strike a balance between protecting profits and reducing unnecessary stop losses.

  3. Parameter optimization by market: Optimize parameter combinations for the characteristics of different varieties.

  4. Add machine learning: Use machine learning algorithms to assist in judging trend directions.

Summary

The Turtle Trading Decision System judges the potential trend direction by comparing prices with the highest and lowest prices over specified periods, and constructs the entire decision system with risk management modules. It has strong trend tracking capability, and also has some risks of false breakouts and parameter optimization. This strategy can serve as a basic model for quantitative trading, and be expanded and optimized on this basis to develop appropriate decision systems for yourself.

Parameters

NameDefaultWhat it controls
v_input_1timestamp(2013-01-01T00:00:00+08:00)From Date/Start Date
v_input_2timestamp(2024-08-01T00:00:00+08:00)To Date/End Date
v_input_string_1Mode 1Enter Mode/Entry System
v_input_int_120Entry Length/System 1 entry length
v_input_int_210Exit Length/System 2 exit length
v_input_int_355Mode2 Entry Length/System 2 entry length
v_input_int_420Mode2 Exit Length/System 2 exit length
v_input_int_514ATR Period/Period for calculating ATR
v_input_float_10.02Risk Per Trade/The risk of each trade, 0.02 is2%
v_input_float_22Initial Stop ATR Multiple/ATR multiple used for stop loss
v_input_float_30.5Pyramid ATR Multiple/ATR multiple used for adding positions
v_input_int_64Max Units/Maximum number of position units
v_input_3trueHighlighter On/Off ?/Whether to highlight

Source Pine Script

/*backtest
start: 2024-01-29 00:00:00
end: 2024-02-28 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Li and Xie 
// All content in this script is for communication and learning purposes only and does not constitute investment advice. All consequences are borne by the user.
//@version=5
strategy(title='Turtle Trading Strategy@lihexie',
   shorttitle='OKX-Turtle Trading System @ Li Hexie',
   overlay=true,
   pyramiding=4,
   initial_capital = 1000,
   default_qty_type = strategy.percent_of_equity,
   default_qty_value=100,
   slippage = 0,
   commission_type = strategy.commission.percent,
   commission_value = 0.05)

// Input Parameters
from_date = input(timestamp("2013-01-01T00:00:00+08:00"), "From Date/Start Date")
end_date = input(timestamp("2024-08-01T00:00:00+08:00"), "To Date/End Date")
valid_date() => true
current_mode = input.string("Mode 1", "Enter Mode/Entry System",['Mode 1','Mode 2'])
// mode 1
entry_length = input.int(20, 'Entry Length/System 1 entry length', minval=1)  // Entry Length
exit_length = input.int(10, 'Exit Length/System 2 exit length', minval=1)  // Exit Length
// mode 2
entry_length_mode2 = input.int(55, 'Mode2 Entry Length/System 2 entry length', minval=1)  // Entry Length
exit_length_mode2 = input.int(20, 'Mode2 Exit Length/System 2 exit length', minval=1) 
atr_period = input.int(14, "ATR Period/Period for calculating ATR", minval=1)  // ATRtimeframe
risk_per_trade = input.float(0.02, "Risk Per Trade/The risk of each trade, 0.02 is2%", minval=0.001, maxval=1)  // Risk per trade
initial_stop_atr_multiple = input.float(2, "Initial Stop ATR Multiple/ATR multiple used for stop loss", minval=0.1, maxval=10)  // Initial Stop LossATRMultiples
pyramid_atr_multiple = input.float(0.5, "Pyramid ATR Multiple/ATR multiple used for adding positions", minval=0.1, maxval=10)  // add to positionATRMultiples
max_units = input.int(4, "Max Units/Maximum number of position units", minval=1, maxval=10)  // Maximum number of position units

highlighting = input(title='Highlighter On/Off ?/Highlight or not, defval=true) // Highlight or not


// Initialize variable
var int units = 0
var float trailing_stop_long = na
var float trailing_stop_short = na
var float real_entry_price_long = na
var float real_entry_price_short = na
var float add_unit_price_long = na
var float add_unit_price_short = na
var bool last_trade_win = false
// CalculationATR
atr = ta.atr(atr_period)

// Calculate unit size
unit_size = (strategy.equity * risk_per_trade) / (initial_stop_atr_multiple * atr)

// Switching Mode
mode_signal = current_mode == "Mode 1" ? (last_trade_win==false?true:false) : true

float entry_price_long = na
float entry_price_short = na
float exit_price_long = na
float exit_price_short = na
// Calculate entry and exit prices
if current_mode == "Mode 1"
    entry_price_long := ta.highest(entry_length)
    entry_price_short := ta.lowest(entry_length)
    exit_price_long := ta.lowest(exit_length)
    exit_price_short := ta.highest(exit_length)
else
    entry_price_long := ta.highest(entry_length_mode2)
    entry_price_short := ta.lowest(entry_length_mode2)
    exit_price_long := ta.lowest(exit_length_mode2)
    exit_price_short := ta.highest(exit_length_mode2)

// Calculate stop-loss price
stop_price_long = entry_price_long - (initial_stop_atr_multiple * atr)
stop_price_short = entry_price_short + (initial_stop_atr_multiple * atr)

// Transaction logic
// Generate buy and sell signals
long_signal = ta.crossover(close, entry_price_long[1]) and strategy.position_size==0 and valid_date()
short_signal = ta.crossunder(close, entry_price_short[1]) and strategy.position_size==0 and valid_date()
// Generate exit signal
exit_long_signal = ta.crossunder(close, exit_price_long[1]) and strategy.position_size > 0 and valid_date()
exit_short_signal = ta.crossover(close, exit_price_short[1]) and strategy.position_size < 0 and valid_date()

if long_signal 
    if mode_signal
        strategy.entry("Long", strategy.long, qty=unit_size, stop=stop_price_long)
        units := 1
        trailing_stop_long := stop_price_long
        real_entry_price_long := close
        add_unit_price_long := real_entry_price_long+pyramid_atr_multiple*atr
    else
        last_trade_win:=false
if short_signal 
    if mode_signal
        strategy.entry("Short", strategy.short, qty=unit_size, stop=stop_price_short)
        units := 1
        trailing_stop_short := stop_price_short
        real_entry_price_short := close
        add_unit_price_short := real_entry_price_short-pyramid_atr_multiple*atr
    else
        last_trade_win:=false
// Exit logic
if exit_long_signal
    last_trade_win := strategy.position_avg_price<close?true:false
    strategy.close_all("SL")
    units := 0
    real_entry_price_long := na
    add_unit_price_long := na
    trailing_stop_long := na
if exit_short_signal
    last_trade_win := strategy.position_avg_price>close?true:false
    strategy.close_all("SS")
    units := 0
    real_entry_price_short := na
    add_unit_price_short := na
    trailing_stop_short := na

// Generate add position signal
add_unit_signal = (close > add_unit_price_long or close < add_unit_price_short) and units[1] < max_units and valid_date()
// Adding position logic
if add_unit_signal
    if strategy.position_size > 0
        strategy.entry("AL", strategy.long, qty=unit_size)
        real_entry_price_long := close
        add_unit_price_long := real_entry_price_long+pyramid_atr_multiple*atr
        trailing_stop_long := real_entry_price_long - (initial_stop_atr_multiple * atr)
    if strategy.position_size < 0
        strategy.entry("AS", strategy.short, qty=unit_size)
        real_entry_price_short := close
        add_unit_price_short := real_entry_price_short-pyramid_atr_multiple*atr
        trailing_stop_short := real_entry_price_short + (initial_stop_atr_multiple * atr)
    units := units + 1

// Trailing stop logic
trailing_stop_long_signal = ta.crossunder(close, trailing_stop_long) and strategy.position_size > 0 and valid_date()
trailing_stop_short_signal = ta.crossover(close, trailing_stop_short) and strategy.position_size < 0 and valid_date()

if trailing_stop_long_signal
    last_trade_win := strategy.position_avg_price<close?true:false
    strategy.close_all("TSL")
    units := 0
    real_entry_price_long := na
    add_unit_price_long := na
    trailing_stop_long := na
if trailing_stop_short_signal
    last_trade_win := strategy.position_avg_price>close?true:false
    strategy.close_all("TSS")
    units := 0
    real_entry_price_short := na
    add_unit_price_short := na
    trailing_stop_short := na

// Beautify chart
plot_entry_lowest = plot(entry_price_short, 'Lower', color=color.new(#0094FF, 0))  // Draw entry minimum line
plot_entry_highest = plot(entry_price_long, 'Upper', color=color.new(#0094FF, 0))  // Draw entry maximum line
entry_line = ta.barssince(short_signal) <= ta.barssince(long_signal) ? entry_price_short : entry_price_long  // entry line
exit_line = ta.barssince(short_signal) <= ta.barssince(long_signal) ? exit_price_short : exit_price_long  // exit line
plot(entry_line, title='Trend Line', color=color.new(#ff52f1, 0), linewidth=2)  // Draw trend line
plot_exit = plot(exit_line, title='Exit Line', color=color.new(color.blue, 0), linewidth=1, style=plot.style_circles)  // Draw exit line

entry_long_color = highlighting and strategy.position_size>0 ? color.new(color.green, transp = 88) : na
entry_short_color = highlighting and strategy.position_size<0 ? color.new(color.red, transp = 88) : na
fill(plot_entry_highest, plot_exit, color=entry_long_color, title='Background') // Highlight bullish trend
fill(plot_entry_lowest, plot_exit, color=entry_short_color, title='Background') // Highlight bearish trend

Published by ChaoZhang on the FMZ strategy square · last modified 2024-02-29. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.

Build this with AgenKit

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/Turtle-Trading-Decision-System.md
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch

Understand it first

Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.

Related specs

esc

Try , , or .

↑↓ move↵ open