Ride Alligator Williams Strategy
This strategy implements Bill Williams' Alligator indicator. The lips, teeth and jaw lines are calculated from the median price using smoothed moving averages with lengths derived from a base period via the golden ratio. A long position is opened when the lips cross above the jaws while the teeth remain below. A short position is opened when the lips cross below the jaws while the teeth remain above. For an open position a trailing stop follows the jaw line.
Parameters
- Base Period – root period used to derive Alligator lengths.
- Candle Type – timeframe of input candles.
Indicators
- Smoothed Moving Average (lips, teeth, jaw)
Entry Rules
- Long when lips cross above jaws and teeth are below.
- Short when lips cross below jaws and teeth are above.
Exit Rules
- Opposite crossover closes the position.
- Trailing stop at the jaw line exits when price crosses it.
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>
/// Strategy based on Bill Williams Alligator.
/// Buys when the lips cross above the jaws while the teeth remain below.
/// Sells when the lips cross below the jaws while the teeth remain above.
/// A trailing stop is placed at the jaws line.
/// </summary>
public class RideAlligatorWilliamsStrategy : Strategy
{
private readonly StrategyParam<int> _basePeriod;
private readonly StrategyParam<DataType> _candleType;
private SmoothedMovingAverage _jaw;
private SmoothedMovingAverage _teeth;
private SmoothedMovingAverage _lips;
private bool _prevLipsAboveJaw;
private decimal? _stopPrice;
/// <summary>
/// Base period used to calculate Alligator lengths.
/// </summary>
public int BasePeriod
{
get => _basePeriod.Value;
set => _basePeriod.Value = value;
}
/// <summary>
/// Candle type for strategy calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="RideAlligatorWilliamsStrategy"/>.
/// </summary>
public RideAlligatorWilliamsStrategy()
{
_basePeriod = Param(nameof(BasePeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Base Period", "Root period for Alligator lines", "Alligator");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevLipsAboveJaw = false;
_stopPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var a1 = (int)Math.Round(BasePeriod * 1.61803398874989m);
var a2 = (int)Math.Round(a1 * 1.61803398874989m);
var a3 = (int)Math.Round(a2 * 1.61803398874989m);
_jaw = new SmoothedMovingAverage { Length = a3 };
_teeth = new SmoothedMovingAverage { Length = a2 };
_lips = new SmoothedMovingAverage { Length = a1 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle);
subscription.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _jaw);
DrawIndicator(area, _teeth);
DrawIndicator(area, _lips);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
var median = (candle.HighPrice + candle.LowPrice) / 2m;
var isFinal = candle.State == CandleStates.Finished;
var jawVal = _jaw.Process(new DecimalIndicatorValue(_jaw, median, candle.ServerTime) { IsFinal = isFinal });
var teethVal = _teeth.Process(new DecimalIndicatorValue(_teeth, median, candle.ServerTime) { IsFinal = isFinal });
var lipsVal = _lips.Process(new DecimalIndicatorValue(_lips, median, candle.ServerTime) { IsFinal = isFinal });
if (!isFinal)
return;
if (!_jaw.IsFormed || !_teeth.IsFormed || !_lips.IsFormed)
return;
var jaw = jawVal.GetValue<decimal>();
var teeth = teethVal.GetValue<decimal>();
var lips = lipsVal.GetValue<decimal>();
var lipsAboveJaw = lips > jaw;
var lipsBelowJaw = lips < jaw;
var teethAboveJaw = teeth > jaw;
var teethBelowJaw = teeth < jaw;
if (Position <= 0 && !_prevLipsAboveJaw && lipsAboveJaw && teethBelowJaw)
{
BuyMarket();
_stopPrice = null;
}
else if (Position >= 0 && _prevLipsAboveJaw && lipsBelowJaw && teethAboveJaw)
{
SellMarket();
_stopPrice = null;
}
if (Position > 0)
{
if (jaw < candle.ClosePrice)
{
var step = Security.PriceStep ?? 0m;
if (_stopPrice is null || jaw > _stopPrice + step)
_stopPrice = jaw;
}
if (_stopPrice != null && candle.ClosePrice <= _stopPrice)
{
SellMarket(Position);
_stopPrice = null;
}
}
else if (Position < 0)
{
if (jaw > candle.ClosePrice)
{
var step = Security.PriceStep ?? 0m;
if (_stopPrice is null || jaw < _stopPrice - step)
_stopPrice = jaw;
}
if (_stopPrice != null && candle.ClosePrice >= _stopPrice)
{
BuyMarket(Math.Abs(Position));
_stopPrice = null;
}
}
_prevLipsAboveJaw = lipsAboveJaw;
}
}
import clr
import math
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SmoothedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class ride_alligator_williams_strategy(Strategy):
def __init__(self):
super(ride_alligator_williams_strategy, self).__init__()
self._base_period = self.Param("BasePeriod", 8)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._jaw = None
self._teeth = None
self._lips = None
self._prev_lips_above_jaw = False
self._stop_price = None
@property
def BasePeriod(self):
return self._base_period.Value
@BasePeriod.setter
def BasePeriod(self, value):
self._base_period.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(ride_alligator_williams_strategy, self).OnStarted2(time)
self._prev_lips_above_jaw = False
self._stop_price = None
bp = int(self.BasePeriod)
phi = 1.61803398874989
a1 = int(round(bp * phi))
a2 = int(round(a1 * phi))
a3 = int(round(a2 * phi))
self._jaw = SmoothedMovingAverage()
self._jaw.Length = a3
self._teeth = SmoothedMovingAverage()
self._teeth.Length = a2
self._lips = SmoothedMovingAverage()
self._lips.Length = a1
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
h = float(candle.HighPrice)
l = float(candle.LowPrice)
median = (h + l) / 2.0
is_final = candle.State == CandleStates.Finished
jaw_result = process_float(self._jaw, median, candle.ServerTime, is_final)
teeth_result = process_float(self._teeth, median, candle.ServerTime, is_final)
lips_result = process_float(self._lips, median, candle.ServerTime, is_final)
if not is_final:
return
if not self._jaw.IsFormed or not self._teeth.IsFormed or not self._lips.IsFormed:
return
jaw_val = float(jaw_result)
teeth_val = float(teeth_result)
lips_val = float(lips_result)
close = float(candle.ClosePrice)
lips_above_jaw = lips_val > jaw_val
lips_below_jaw = lips_val < jaw_val
teeth_above_jaw = teeth_val > jaw_val
teeth_below_jaw = teeth_val < jaw_val
pos = float(self.Position)
if pos <= 0 and not self._prev_lips_above_jaw and lips_above_jaw and teeth_below_jaw:
self.BuyMarket()
self._stop_price = None
elif pos >= 0 and self._prev_lips_above_jaw and lips_below_jaw and teeth_above_jaw:
self.SellMarket()
self._stop_price = None
pos = float(self.Position)
if pos > 0:
if jaw_val < close:
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 0.0
if self._stop_price is None or jaw_val > self._stop_price + step:
self._stop_price = jaw_val
if self._stop_price is not None and close <= self._stop_price:
self.SellMarket(pos)
self._stop_price = None
elif pos < 0:
if jaw_val > close:
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 0.0
if self._stop_price is None or jaw_val < self._stop_price - step:
self._stop_price = jaw_val
if self._stop_price is not None and close >= self._stop_price:
self.BuyMarket(abs(pos))
self._stop_price = None
self._prev_lips_above_jaw = lips_above_jaw
def OnReseted(self):
super(ride_alligator_williams_strategy, self).OnReseted()
self._jaw = None
self._teeth = None
self._lips = None
self._prev_lips_above_jaw = False
self._stop_price = None
def CreateClone(self):
return ride_alligator_williams_strategy()