Estrategia Williams Alligator ATR
Esta estrategia utiliza el indicador Williams Alligator combinado con un stop-loss basado en ATR. Se abre una posición larga cuando la línea Lips cruza por encima de la línea Jaw. La posición se cierra cuando Lips cruza por debajo de Jaw o cuando el precio cae hasta un nivel de stop basado en ATR.
Detalles
- Criterios de entrada: Lips cruza por encima de Jaw.
- Criterios de salida: Lips cruza por debajo de Jaw o stop-loss por ATR.
- Indicadores: Smoothed Moving Averages, Average True Range.
- Tipo: Solo largos.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Williams Alligator strategy with ATR-based stop-loss.
/// Uses three smoothed moving averages (Jaw, Teeth, Lips) for trend detection.
/// </summary>
public class WilliamsAlligatorAtrStrategy : Strategy
{
private readonly StrategyParam<int> _jawLength;
private readonly StrategyParam<int> _teethLength;
private readonly StrategyParam<int> _lipsLength;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private bool _prevLipsAboveJaw;
private bool _prevLipsBelowJaw;
private bool _isInitialized;
private decimal _entryPrice;
private int _cooldownRemaining;
public int JawLength { get => _jawLength.Value; set => _jawLength.Value = value; }
public int TeethLength { get => _teethLength.Value; set => _teethLength.Value = value; }
public int LipsLength { get => _lipsLength.Value; set => _lipsLength.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public WilliamsAlligatorAtrStrategy()
{
_jawLength = Param(nameof(JawLength), 13)
.SetGreaterThanZero()
.SetDisplay("Jaw Length", "Alligator jaw period", "Alligator");
_teethLength = Param(nameof(TeethLength), 8)
.SetGreaterThanZero()
.SetDisplay("Teeth Length", "Alligator teeth period", "Alligator");
_lipsLength = Param(nameof(LipsLength), 5)
.SetGreaterThanZero()
.SetDisplay("Lips Length", "Alligator lips period", "Alligator");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for stop-loss", "ATR");
_atrMultiplier = Param(nameof(AtrMultiplier), 2m)
.SetGreaterThanZero()
.SetDisplay("ATR Multiplier", "ATR multiplier for stop-loss", "ATR");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevLipsAboveJaw = false;
_prevLipsBelowJaw = false;
_isInitialized = false;
_entryPrice = 0m;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var jaw = new SmoothedMovingAverage { Length = JawLength };
var lips = new SmoothedMovingAverage { Length = LipsLength };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(jaw, lips, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, jaw);
DrawIndicator(area, lips);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal jawVal, decimal lipsVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevLipsAboveJaw = lipsVal > jawVal;
_prevLipsBelowJaw = lipsVal < jawVal;
_isInitialized = true;
return;
}
if (!_isInitialized)
{
_prevLipsAboveJaw = lipsVal > jawVal;
_prevLipsBelowJaw = lipsVal < jawVal;
_isInitialized = true;
return;
}
var lipsAboveJaw = lipsVal > jawVal;
var lipsBelowJaw = lipsVal < jawVal;
// Check ATR stop for existing positions
if (Position > 0 && _entryPrice > 0 && atrVal > 0)
{
if (candle.ClosePrice <= _entryPrice - AtrMultiplier * atrVal)
{
SellMarket(Math.Abs(Position));
_entryPrice = 0m;
_cooldownRemaining = CooldownBars;
_prevLipsAboveJaw = lipsAboveJaw;
_prevLipsBelowJaw = lipsBelowJaw;
return;
}
}
else if (Position < 0 && _entryPrice > 0 && atrVal > 0)
{
if (candle.ClosePrice >= _entryPrice + AtrMultiplier * atrVal)
{
BuyMarket(Math.Abs(Position));
_entryPrice = 0m;
_cooldownRemaining = CooldownBars;
_prevLipsAboveJaw = lipsAboveJaw;
_prevLipsBelowJaw = lipsBelowJaw;
return;
}
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevLipsAboveJaw = lipsAboveJaw;
_prevLipsBelowJaw = lipsBelowJaw;
return;
}
// Long entry: lips crosses above jaw
if (!_prevLipsAboveJaw && lipsAboveJaw && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_entryPrice = candle.ClosePrice;
_cooldownRemaining = CooldownBars;
}
// Short entry: lips crosses below jaw
else if (!_prevLipsBelowJaw && lipsBelowJaw && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_entryPrice = candle.ClosePrice;
_cooldownRemaining = CooldownBars;
}
_prevLipsAboveJaw = lipsAboveJaw;
_prevLipsBelowJaw = lipsBelowJaw;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SmoothedMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class williams_alligator_atr_strategy(Strategy):
def __init__(self):
super(williams_alligator_atr_strategy, self).__init__()
self._jaw_length = self.Param("JawLength", 13) \
.SetGreaterThanZero() \
.SetDisplay("Jaw Length", "Alligator jaw period", "Alligator")
self._lips_length = self.Param("LipsLength", 5) \
.SetGreaterThanZero() \
.SetDisplay("Lips Length", "Alligator lips period", "Alligator")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("ATR Period", "ATR period for stop-loss", "ATR")
self._atr_multiplier = self.Param("AtrMultiplier", 2.0) \
.SetGreaterThanZero() \
.SetDisplay("ATR Multiplier", "ATR multiplier for stop-loss", "ATR")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._prev_lips_above_jaw = False
self._prev_lips_below_jaw = False
self._is_initialized = False
self._entry_price = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(williams_alligator_atr_strategy, self).OnReseted()
self._prev_lips_above_jaw = False
self._prev_lips_below_jaw = False
self._is_initialized = False
self._entry_price = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(williams_alligator_atr_strategy, self).OnStarted2(time)
jaw = SmoothedMovingAverage()
jaw.Length = int(self._jaw_length.Value)
lips = SmoothedMovingAverage()
lips.Length = int(self._lips_length.Value)
atr = AverageTrueRange()
atr.Length = int(self._atr_period.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(jaw, lips, atr, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, jaw)
self.DrawIndicator(area, lips)
self.DrawOwnTrades(area)
def _on_process(self, candle, jaw_val, lips_val, atr_val):
if candle.State != CandleStates.Finished:
return
jaw_v = float(jaw_val)
lips_v = float(lips_val)
atr_v = float(atr_val)
close = float(candle.ClosePrice)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_lips_above_jaw = lips_v > jaw_v
self._prev_lips_below_jaw = lips_v < jaw_v
self._is_initialized = True
return
if not self._is_initialized:
self._prev_lips_above_jaw = lips_v > jaw_v
self._prev_lips_below_jaw = lips_v < jaw_v
self._is_initialized = True
return
lips_above_jaw = lips_v > jaw_v
lips_below_jaw = lips_v < jaw_v
atr_mult = float(self._atr_multiplier.Value)
cooldown = int(self._cooldown_bars.Value)
# Check ATR stop for existing positions
if self.Position > 0 and self._entry_price > 0 and atr_v > 0:
if close <= self._entry_price - atr_mult * atr_v:
self.SellMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._cooldown_remaining = cooldown
self._prev_lips_above_jaw = lips_above_jaw
self._prev_lips_below_jaw = lips_below_jaw
return
elif self.Position < 0 and self._entry_price > 0 and atr_v > 0:
if close >= self._entry_price + atr_mult * atr_v:
self.BuyMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._cooldown_remaining = cooldown
self._prev_lips_above_jaw = lips_above_jaw
self._prev_lips_below_jaw = lips_below_jaw
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_lips_above_jaw = lips_above_jaw
self._prev_lips_below_jaw = lips_below_jaw
return
if not self._prev_lips_above_jaw and lips_above_jaw and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._entry_price = close
self._cooldown_remaining = cooldown
elif not self._prev_lips_below_jaw and lips_below_jaw and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._entry_price = close
self._cooldown_remaining = cooldown
self._prev_lips_above_jaw = lips_above_jaw
self._prev_lips_below_jaw = lips_below_jaw
def CreateClone(self):
return williams_alligator_atr_strategy()