3Commas Turtle Strategy
Упрощённая стратегия Turtle на основе каналов Дончиана. Покупает при пробое верхней границы быстрого канала с подтверждением от медленного, продаёт при пробое нижней границы. Выход происходит при пересечении цены с противоположным выходным каналом.
Детали
- Условия входа: Пробой быстрого канала с подтверждением медленного.
- Длинные/короткие: Обе стороны.
- Условия выхода: Пересечение выходного канала.
- Стопы: По каналам.
- Значения по умолчанию:
PeriodFast= 20PeriodSlow= 20PeriodExit= 10CandleType= TimeSpan.FromMinutes(1)
- Фильтры:
- Категория: Тренд
- Направление: Обе
- Индикаторы: Каналы Дончиана
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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()