Ver en GitHub

Estrategia Ride Alligator Williams

Esta estrategia implementa el indicador Alligator de Bill Williams. Las líneas de labios, dientes y mandíbula se calculan desde el precio medio usando medias móviles suavizadas con longitudes derivadas de un período base a través de la razón áurea. Se abre una posición larga cuando los labios cruzan por encima de la mandíbula mientras los dientes permanecen por debajo. Se abre una posición corta cuando los labios cruzan por debajo de la mandíbula mientras los dientes permanecen por encima. Para una posición abierta, un trailing stop sigue la línea de la mandíbula.

Parámetros

  • Base Period – período raíz usado para derivar las longitudes del Alligator.
  • Candle Type – marco temporal de las velas de entrada.

Indicadores

  • Media Móvil Suavizada (labios, dientes, mandíbula)

Reglas de entrada

  • Largo cuando los labios cruzan por encima de la mandíbula y los dientes están por debajo.
  • Corto cuando los labios cruzan por debajo de la mandíbula y los dientes están por encima.

Reglas de salida

  • Un cruce opuesto cierra la posición.
  • El trailing stop en la línea de la mandíbula sale cuando el precio la cruza.
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;
	}
}