3Commas Turtle Strategy
Simplified Turtle-style breakout system using Donchian channels. Buys on breakouts above the fast channel when price is also above the slow channel, and sells on breakdowns below the fast channel with confirmation from the slow channel. Exits occur when price crosses the exit channel in the opposite direction.
Details
- Entry Criteria: Breakout of fast channel with slow channel confirmation.
- Long/Short: Both directions.
- Exit Criteria: Price crosses exit channel.
- Stops: Channel-based.
- Default Values:
PeriodFast= 20PeriodSlow= 20PeriodExit= 10CandleType= TimeSpan.FromMinutes(1)
- Filters:
- Category: Trend
- Direction: Both
- Indicators: Donchian channels
- Stops: Yes
- Complexity: Intermediate
- Timeframe: Intraday
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified turtle breakout strategy.
/// </summary>
public class ThreeCommasTurtleStrategy : Strategy
{
private readonly StrategyParam<int> _periodFast;
private readonly StrategyParam<int> _periodSlow;
private readonly StrategyParam<int> _periodExit;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevUpperFast;
private decimal _prevLowerFast;
private decimal _prevClose;
public int PeriodFast
{
get => _periodFast.Value;
set => _periodFast.Value = value;
}
public int PeriodSlow
{
get => _periodSlow.Value;
set => _periodSlow.Value = value;
}
public int PeriodExit
{
get => _periodExit.Value;
set => _periodExit.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ThreeCommasTurtleStrategy()
{
_periodFast = Param(nameof(PeriodFast), 10)
.SetDisplay("Period Fast", "Fast channel period", "Channels");
_periodSlow = Param(nameof(PeriodSlow), 15)
.SetDisplay("Period Slow", "Slow channel period", "Channels");
_periodExit = Param(nameof(PeriodExit), 5)
.SetDisplay("Period Exit", "Exit channel period", "Channels");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevUpperFast = 0m;
_prevLowerFast = 0m;
_prevClose = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevUpperFast = 0m;
_prevLowerFast = 0m;
_prevClose = 0m;
var upperFast = new Highest { Length = PeriodFast };
var lowerFast = new Lowest { Length = PeriodFast };
var upperSlow = new Highest { Length = PeriodSlow };
var lowerSlow = new Lowest { Length = PeriodSlow };
var upperExit = new Highest { Length = PeriodExit };
var lowerExit = new Lowest { Length = PeriodExit };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(upperFast, lowerFast, upperSlow, lowerSlow, upperExit, lowerExit, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal upFast, decimal lowFast, decimal upSlow, decimal lowSlow, decimal upExit, decimal lowExit)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevClose == 0)
{
_prevUpperFast = upFast;
_prevLowerFast = lowFast;
_prevClose = candle.ClosePrice;
return;
}
if (candle.ClosePrice > _prevUpperFast && Position <= 0)
{
BuyMarket();
}
else if (candle.ClosePrice < _prevLowerFast && Position >= 0)
{
SellMarket();
}
else if (Position > 0 && candle.ClosePrice < lowExit)
SellMarket();
else if (Position < 0 && candle.ClosePrice > upExit)
BuyMarket();
_prevUpperFast = upFast;
_prevLowerFast = lowFast;
_prevClose = candle.ClosePrice;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class three_commas_turtle_strategy(Strategy):
def __init__(self):
super(three_commas_turtle_strategy, self).__init__()
self._period_fast = self.Param("PeriodFast", 10) \
.SetDisplay("Period Fast", "Fast channel period", "Channels")
self._period_slow = self.Param("PeriodSlow", 15) \
.SetDisplay("Period Slow", "Slow channel period", "Channels")
self._period_exit = self.Param("PeriodExit", 5) \
.SetDisplay("Period Exit", "Exit channel period", "Channels")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_upper_fast = 0.0
self._prev_lower_fast = 0.0
self._prev_close = 0.0
@property
def period_fast(self):
return self._period_fast.Value
@property
def period_slow(self):
return self._period_slow.Value
@property
def period_exit(self):
return self._period_exit.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(three_commas_turtle_strategy, self).OnReseted()
self._prev_upper_fast = 0.0
self._prev_lower_fast = 0.0
self._prev_close = 0.0
def OnStarted2(self, time):
super(three_commas_turtle_strategy, self).OnStarted2(time)
upper_fast = Highest()
upper_fast.Length = self.period_fast
lower_fast = Lowest()
lower_fast.Length = self.period_fast
upper_slow = Highest()
upper_slow.Length = self.period_slow
lower_slow = Lowest()
lower_slow.Length = self.period_slow
upper_exit = Highest()
upper_exit.Length = self.period_exit
lower_exit = Lowest()
lower_exit.Length = self.period_exit
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(upper_fast, lower_fast, upper_slow, lower_slow, upper_exit, lower_exit, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, up_fast, low_fast, up_slow, low_slow, up_exit, low_exit):
if candle.State != CandleStates.Finished:
return
if self._prev_close == 0:
self._prev_upper_fast = up_fast
self._prev_lower_fast = low_fast
self._prev_close = candle.ClosePrice
return
if candle.ClosePrice > self._prev_upper_fast and self.Position <= 0:
self.BuyMarket()
elif candle.ClosePrice < self._prev_lower_fast and self.Position >= 0:
self.SellMarket()
elif self.Position > 0 and candle.ClosePrice < low_exit:
self.SellMarket()
elif self.Position < 0 and candle.ClosePrice > up_exit:
self.BuyMarket()
self._prev_upper_fast = up_fast
self._prev_lower_fast = low_fast
self._prev_close = candle.ClosePrice
def CreateClone(self):
return three_commas_turtle_strategy()