Ver en GitHub

Estrategia Simple de Alligator

Descripción general

La estrategia Simple de Alligator recrea el expert advisor de MetaTrader "Alligator Simple v1.0" usando la API de alto nivel de StockSharp. Lee el indicador Alligator de Bill Williams en velas terminadas y abre una posición cuando las líneas Lips, Teeth y Jaw se expanden en la misma dirección en la barra completada anterior. Cada operación puede incluir opcionalmente gestión de stop-loss, take-profit y trailing stop basados en pips que refleja la implementación MQL original.

Indicadores y datos

  • Líneas Alligator: tres Medias Móviles Suavizadas (SMMA) calculadas sobre el precio mediano de la vela (high + low) / 2 con longitudes configurables y desplazamientos hacia adelante para el Jaw, Teeth y Lips.
  • Velas: la estrategia se suscribe a un único CandleType configurable (velas de una hora por defecto) y solo procesa velas terminadas para evitar el sesgo de mirar hacia adelante.

Lógica de trading

  1. Evaluación de señales
    • Recuperar los valores desplazados del Alligator para la vela completada anterior.
    • Señal larga: Lips[t-1] > Teeth[t-1] > Jaw[t-1].
    • Señal corta: Lips[t-1] < Teeth[t-1] < Jaw[t-1].
  2. Ejecución
    • Entrar al mercado con OrderVolume cuando no hay posición abierta.
    • Solo se mantiene una posición a la vez; las señales opuestas se ignoran hasta que la posición actual se cierra.

Salida y gestión del riesgo

  • Stop-loss inicial: si StopLossPips > 0, la estrategia desplaza el precio de ejecución por la distancia en pips convertida con el paso de precio del instrumento (incluyendo el multiplicador de pips de 3/5 dígitos usado por los símbolos de MetaTrader).
  • Take-profit: cuando TakeProfitPips > 0, se coloca un objetivo de beneficio simétricamente alrededor del precio de entrada. Un valor de cero desactiva el objetivo.
  • Trailing stop: cuando tanto TrailingStopPips como TrailingStepPips son positivos, el stop avanza a close − TrailingStop (largos) o close + TrailingStop (cortos) una vez que el precio se ha movido al menos TrailingStop + TrailingStep a favor de la operación. Las actualizaciones del trailing se basan en el máximo/mínimo de la vela para simular toques intra-barra.
  • Gestión de salida: las condiciones de stop-loss, take-profit y trailing emiten órdenes de mercado para aplanar la posición y se evalúan en cada vela terminada.

Parámetros

  • OrderVolume (predeterminado 1): tamaño de la operación en lotes o contratos.
  • StopLossPips (predeterminado 100): distancia del stop-loss inicial en pips. Establecer en cero para deshabilitar.
  • TakeProfitPips (predeterminado 100): distancia del take-profit en pips. Establecer en cero para deshabilitar.
  • TrailingStopPips (predeterminado 5): distancia del trailing stop en pips. Cero desactiva el trailing.
  • TrailingStepPips (predeterminado 5): distancia extra en pips que el precio debe recorrer antes de que avance el trailing stop. Debe ser positivo cuando el trailing está habilitado.
  • JawPeriod, TeethPeriod, LipsPeriod: longitudes SMMA para el jaw, teeth y lips (predeterminados 13/8/5).
  • JawShift, TeethShift, LipsShift: desplazamientos hacia adelante aplicados al leer los valores del Alligator (predeterminados 8/5/3).
  • CandleType: tipo/marco temporal de datos de velas para los cálculos (predeterminado velas de una hora).

Notas de implementación

  • Las distancias en pips se adaptan automáticamente al tamaño del tick del valor. Los instrumentos con tres o cinco decimales multiplican el paso de precio por diez para replicar la definición de pip de MetaTrader.
  • Los buffers de historial del indicador almacenan suficientes valores para respetar los desplazamientos hacia adelante configurados, eliminando la manipulación manual de arrays.
  • La estrategia usa los helpers BuyMarket y SellMarket para enviar órdenes, manteniendo el código enfocado en la generación de señales y el manejo del riesgo.
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>
/// Simplified Bill Williams Alligator breakout strategy.
/// Buys when Lips > Teeth > Jaw (upward expansion).
/// Sells when Lips less than Teeth less than Jaw (downward expansion).
/// Uses stop-loss and take-profit for risk management.
/// </summary>
public class AlligatorSimpleStrategy : Strategy
{
	private readonly StrategyParam<int> _jawPeriod;
	private readonly StrategyParam<int> _teethPeriod;
	private readonly StrategyParam<int> _lipsPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private SmoothedMovingAverage _jaw;
	private SmoothedMovingAverage _teeth;
	private SmoothedMovingAverage _lips;

	private decimal _entryPrice;
	private int _cooldown;

	/// <summary>
	/// Period for the Alligator jaw (blue) smoothed moving average.
	/// </summary>
	public int JawPeriod
	{
		get => _jawPeriod.Value;
		set => _jawPeriod.Value = value;
	}

	/// <summary>
	/// Period for the Alligator teeth (red) smoothed moving average.
	/// </summary>
	public int TeethPeriod
	{
		get => _teethPeriod.Value;
		set => _teethPeriod.Value = value;
	}

	/// <summary>
	/// Period for the Alligator lips (green) smoothed moving average.
	/// </summary>
	public int LipsPeriod
	{
		get => _lipsPeriod.Value;
		set => _lipsPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initialize <see cref="AlligatorSimpleStrategy"/>.
	/// </summary>
	public AlligatorSimpleStrategy()
	{
		_jawPeriod = Param(nameof(JawPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("Jaw Period", "Alligator jaw period", "Alligator");

		_teethPeriod = Param(nameof(TeethPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Teeth Period", "Alligator teeth period", "Alligator");

		_lipsPeriod = Param(nameof(LipsPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Lips Period", "Alligator lips period", "Alligator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_jaw = null;
		_teeth = null;
		_lips = null;
		_entryPrice = 0;
		_cooldown = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_jaw = new SmoothedMovingAverage { Length = JawPeriod };
		_teeth = new SmoothedMovingAverage { Length = TeethPeriod };
		_lips = new SmoothedMovingAverage { Length = LipsPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_jaw, _teeth, _lips, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal jawValue, decimal teethValue, decimal lipsValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_jaw.IsFormed || !_teeth.IsFormed || !_lips.IsFormed)
			return;

		if (_cooldown > 0)
		{
			_cooldown--;
			return;
		}

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		// Check SL/TP for existing positions
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}

			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}
		}

		// Buy when lips > teeth > jaw (Alligator opening upward)
		if (lipsValue > teethValue && teethValue > jawValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 110;
		}
		// Sell when lips < teeth < jaw (Alligator opening downward)
		else if (lipsValue < teethValue && teethValue < jawValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 110;
		}
	}
}