Turtle Trader SAR convierte el sistema Turtle original de MQL5 con un trailing Parabolic SAR opcional a StockSharp C#.
La estrategia opera rupturas de canales Donchian, dimensiona posiciones por riesgo basado en ATR y puede piramidear operaciones ganadoras.
Cómo Funciona
Cálculo de Indicadores
ATR de 20 períodos para volatilidad.
Canales Donchian para ShortPeriod y ExitPeriod.
Parabolic SAR opcional para stops de seguimiento.
Dimensionamiento de Posición
Cada entrada arriesga RiskFraction del capital actual.
El tamaño de la unidad está limitado por MaxUnits.
Criterios de Entrada
Cierre por encima del máximo de ShortPeriod -> comprar.
Cierre por debajo del mínimo de ShortPeriod -> vender.
Piramidación
Agrega nueva unidad cada movimiento de AddInterval ATR a favor hasta MaxUnits.
Criterios de Salida
Ruptura opuesta de ExitPeriod.
Stop ATR usando StopAtr y take profit opcional TakeAtr.
Si UseSar es true, también se aplica el stop Parabolic SAR.
Parámetros
ExitPeriod = 10
ShortPeriod = 20
LongPeriod = 55
RiskFraction = 0.01
MaxUnits = 4
AddInterval = 1
StopAtr = 1
TakeAtr = 1
UseSar = false
SarStep = 0.02
SarMax = 0.2
CandleType = 1 day
Etiquetas
Categoría: Seguimiento de tendencia
Dirección: Ambos
Indicadores: ATR, Highest, Lowest, Parabolic SAR
Stops: ATR / SAR
Complejidad: Intermedio
Marco temporal: Diario
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
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>
/// Turtle Trader strategy with Donchian breakout entries and ATR-based stops.
/// </summary>
public class TurtleTraderSarStrategy : Strategy
{
private readonly StrategyParam<int> _shortPeriod;
private readonly StrategyParam<decimal> _stopMultiplier;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _highs = new();
private readonly List<decimal> _lows = new();
private readonly List<decimal> _closes = new();
private decimal _stopPrice;
public int ShortPeriod { get => _shortPeriod.Value; set => _shortPeriod.Value = value; }
public decimal StopMultiplier { get => _stopMultiplier.Value; set => _stopMultiplier.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TurtleTraderSarStrategy()
{
_shortPeriod = Param(nameof(ShortPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Short Period", "Donchian breakout period", "General");
_stopMultiplier = Param(nameof(StopMultiplier), 2m)
.SetDisplay("Stop Multiplier", "ATR multiplier for stop", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highs.Clear();
_lows.Clear();
_closes.Clear();
_stopPrice = 0m;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highs.Clear();
_lows.Clear();
_closes.Clear();
_stopPrice = 0m;
var sub = SubscribeCandles(CandleType);
sub.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, sub);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_highs.Add(candle.HighPrice);
_lows.Add(candle.LowPrice);
_closes.Add(candle.ClosePrice);
if (_highs.Count < ShortPeriod + 1)
return;
// Trim to keep memory bounded
while (_highs.Count > ShortPeriod + 10)
{
_highs.RemoveAt(0);
_lows.RemoveAt(0);
_closes.RemoveAt(0);
}
// Compute Donchian channel (excluding current candle)
var len = _highs.Count;
decimal highest = 0, lowest = decimal.MaxValue;
for (int i = len - 1 - ShortPeriod; i < len - 1; i++)
{
if (_highs[i] > highest) highest = _highs[i];
if (_lows[i] < lowest) lowest = _lows[i];
}
// Simple ATR approximation: average of (high-low) over last 20 candles
var atrPeriod = Math.Min(20, len);
decimal sumRange = 0;
for (int i = len - atrPeriod; i < len; i++)
sumRange += _highs[i] - _lows[i];
var atr = sumRange / atrPeriod;
var price = candle.ClosePrice;
// Manage existing position
if (Position > 0 && _stopPrice > 0 && price <= _stopPrice)
{
SellMarket();
return;
}
else if (Position < 0 && _stopPrice > 0 && price >= _stopPrice)
{
BuyMarket();
return;
}
if (Position != 0)
return;
// Breakout entry
if (price > highest && atr > 0)
{
_stopPrice = price - StopMultiplier * atr;
BuyMarket();
}
else if (price < lowest && atr > 0)
{
_stopPrice = price + StopMultiplier * atr;
SellMarket();
}
}
}
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.Strategies import Strategy
class turtle_trader_sar_strategy(Strategy):
def __init__(self):
super(turtle_trader_sar_strategy, self).__init__()
self._short_period = self.Param("ShortPeriod", 20)
self._stop_multiplier = self.Param("StopMultiplier", 2.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._highs = []
self._lows = []
self._closes = []
self._stop_price = 0.0
@property
def ShortPeriod(self):
return self._short_period.Value
@ShortPeriod.setter
def ShortPeriod(self, value):
self._short_period.Value = value
@property
def StopMultiplier(self):
return self._stop_multiplier.Value
@StopMultiplier.setter
def StopMultiplier(self, value):
self._stop_multiplier.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(turtle_trader_sar_strategy, self).OnStarted2(time)
self._highs = []
self._lows = []
self._closes = []
self._stop_price = 0.0
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
h = float(candle.HighPrice)
l = float(candle.LowPrice)
c = float(candle.ClosePrice)
self._highs.append(h)
self._lows.append(l)
self._closes.append(c)
period = int(self.ShortPeriod)
if len(self._highs) < period + 1:
return
while len(self._highs) > period + 10:
self._highs.pop(0)
self._lows.pop(0)
self._closes.pop(0)
length = len(self._highs)
highest = 0.0
lowest = float('inf')
for i in range(length - 1 - period, length - 1):
if self._highs[i] > highest:
highest = self._highs[i]
if self._lows[i] < lowest:
lowest = self._lows[i]
atr_period = min(20, length)
sum_range = 0.0
for i in range(length - atr_period, length):
sum_range += self._highs[i] - self._lows[i]
atr = sum_range / atr_period if atr_period > 0 else 0.0
price = c
if self.Position > 0 and self._stop_price > 0.0 and price <= self._stop_price:
self.SellMarket()
return
elif self.Position < 0 and self._stop_price > 0.0 and price >= self._stop_price:
self.BuyMarket()
return
if self.Position != 0:
return
if price > highest and atr > 0.0:
self._stop_price = price - float(self.StopMultiplier) * atr
self.BuyMarket()
elif price < lowest and atr > 0.0:
self._stop_price = price + float(self.StopMultiplier) * atr
self.SellMarket()
def OnReseted(self):
super(turtle_trader_sar_strategy, self).OnReseted()
self._highs = []
self._lows = []
self._closes = []
self._stop_price = 0.0
def CreateClone(self):
return turtle_trader_sar_strategy()