Ver en GitHub

Estrategia comercial de FT Bill Williams

Descripción general

La **estrategia comercial FT Bill Williams es una traducción de alto nivel StockSharp del MetaTrader asesor experto "FT_BillWillams_Trader". Combina los fractales de Bill Williams con el indicador Alligator para negociar rupturas de tendencias. La estrategia busca fractales nuevos, verifica que la estructura Alligator confirme la dirección de ruptura y, opcionalmente, aplica filtros de distancia, alineación y señal inversa antes de abrir una posición.

Lógica de trading

  1. Detección de fractales: la estrategia almacena los máximos y mínimos más recientes de FractalPeriod. Cuando la barra del medio es el punto más alto (o más bajo) de la ventana, se registra un nuevo nivel de ruptura. Se agrega un desplazamiento IndentPoints encima/debajo del fractal para evitar entradas prematuras.
  2. Confirmación de ruptura – dependiendo de EntryConfirmation:
    • PriceBreakout confirma cuando el rango de velas cruza el nivel de ruptura.
    • CloseBreakout espera a que el cierre de la vela anterior supere el nivel.
  3. Verificación de distancia: las entradas se rechazan cuando el nivel de ruptura está a más de MaxDistancePoints de los labios Alligator (valor de barra anterior). Establezca la distancia en cero para desactivar el filtro.
  4. Filtro de dientes: cuando UseTeethFilter está habilitado, el cierre anterior debe estar por encima (para largos) o por debajo (para cortos) de los dientes Alligator.
  5. Alineación de tendencia: con UseTrendAlignment = true, los labios, los dientes y la mandíbula deben estar separados por al menos TeethLipsDistancePoints y JawTeethDistancePoints puntos, respectivamente, lo que confirma que Alligator es tendencia.
  6. Salidas inversas: si ReverseExit = OppositeFractal, cualquier nuevo fractal opuesto cierra inmediatamente la posición abierta. Con OppositePosition, la estrategia primero cierra la operación actual antes de abrir una en la dirección opuesta.
  7. Salida de la mandíbula: JawExit define si la posición se cierra cuando el precio cruza la mandíbula Alligator (intrabar o al cierre de la vela).
  8. Trailing stop: cuando EnableTrailing es verdadero y la operación es rentable, el stop se mueve hacia los labios o los dientes dependiendo de la pendiente relativa de los labios y el SlopeSmaPeriod SMA. Las paradas de protección iniciales y los objetivos de ganancias están controlados por StopLossPoints y TakeProfitPoints.

Parámetros

Propiedad Descripción Predeterminado
OrderVolume Volumen comercial utilizado al enviar órdenes de mercado. 0.1
FractalPeriod Número de barras en el patrón fractal (se recomiendan valores impares). 5
IndentPoints Compensación agregada al nivel de ruptura (en puntos). 1
EntryConfirmation Modo de confirmación de ruptura (PriceBreakout, CloseBreakout). CloseBreakout
UseTeethFilter Requiere que el cierre anterior esté en el lado correcto de los dientes Alligator. true
MaxDistancePoints Distancia máxima entre el nivel de ruptura y Alligator labios (puntos). 1000
UseTrendAlignment Aplicar una separación mínima entre Alligator líneas. false
JawTeethDistancePoints Distancia mínima entre mandíbula y dientes utilizada en el filtro de alineación. 10
TeethLipsDistancePoints Distancia mínima entre dientes y labios utilizada en el filtro de alineación. 10
JawExit Modo de cierre de posiciones en cruce de mandíbulas (Disabled, PriceCross, CloseCross). CloseCross
ReverseExit Manejo de señales opuestas (Disabled, OppositeFractal, OppositePosition). OppositePosition
EnableTrailing Habilite la gestión de trailing stop basada en Alligator. true
SlopeSmaPeriod Período del SMA que se compara con la pendiente de los labios. 5
StopLossPoints Distancia de stop-loss en puntos (0 inhabilitaciones). 50
TakeProfitPoints Distancia de toma de ganancias en puntos (0 inhabilitaciones). 50
JawPeriod, TeethPeriod, LipsPeriod Períodos para las líneas Alligator. 13, 8, 5
JawShift, TeethShift, LipsShift Desplazamiento hacia adelante para cada línea Alligator. 8, 5, 3
MaMethod Tipo de media móvil para Alligator (Simple, Exponential, Smoothed, Weighted). Simple
AppliedPrice Precio de vela suministrado al Alligator. CandlePrice.Median
CandleType Tipo de vela suscrita a partir de los datos del mercado. 15-minute timeframe

Notas adicionales

  • La estrategia dibuja las líneas Alligator y ejecuta operaciones en el área del gráfico predeterminada.
  • FractalPeriod debe permanecer impar para que la barra central represente el vértice fractal; el valor predeterminado coincide con el asesor experto original.
  • Los parámetros basados en la distancia (IndentPoints, MaxDistancePoints, JawTeethDistancePoints, TeethLipsDistancePoints, StopLossPoints, TakeProfitPoints) se expresan en puntos de corredor (Security.PriceStep).
  • Las paradas dinámicas y las salidas de mandíbula dependen de velas completadas, lo que refleja la lógica MQL original que funciona con los valores de barra anteriores del Alligator.
using System;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bill Williams Fractal Breakout strategy filtered by Alligator alignment.
/// Buys on up-fractal breakout when price is above alligator teeth,
/// sells on down-fractal breakout when price is below alligator teeth.
/// Exits on opposite signal (reverse position).
/// </summary>
public class FTBillWillamsTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _jawPeriod;
	private readonly StrategyParam<int> _teethPeriod;
	private readonly StrategyParam<int> _lipsPeriod;
	private readonly StrategyParam<int> _fractalLen;

	private SMA _jaw = null!;
	private SMA _teeth = null!;
	private SMA _lips = null!;

	private decimal[] _highBuf = Array.Empty<decimal>();
	private decimal[] _lowBuf = Array.Empty<decimal>();
	private int _bufCount;

	private decimal? _pendingBuyLevel;
	private decimal? _pendingSellLevel;
	private decimal _prevJaw;
	private decimal _prevTeeth;
	private decimal _prevLips;
	private decimal _entryPrice;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int JawPeriod
	{
		get => _jawPeriod.Value;
		set => _jawPeriod.Value = value;
	}

	public int TeethPeriod
	{
		get => _teethPeriod.Value;
		set => _teethPeriod.Value = value;
	}

	public int LipsPeriod
	{
		get => _lipsPeriod.Value;
		set => _lipsPeriod.Value = value;
	}

	public int FractalLen
	{
		get => _fractalLen.Value;
		set => _fractalLen.Value = value;
	}

	public FTBillWillamsTraderStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for strategy", "General");

		_jawPeriod = Param(nameof(JawPeriod), 13)
			.SetDisplay("Jaw Period", "Alligator jaw SMA period", "Alligator");

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

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

		_fractalLen = Param(nameof(FractalLen), 5)
			.SetDisplay("Fractal Length", "Number of bars for fractal detection", "Signals");
	}

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

		_jaw = new SMA { Length = JawPeriod };
		_teeth = new SMA { Length = TeethPeriod };
		_lips = new SMA { Length = LipsPeriod };
		_highBuf = new decimal[FractalLen];
		_lowBuf = new decimal[FractalLen];
		_bufCount = 0;
		_pendingBuyLevel = null;
		_pendingSellLevel = null;
		_prevJaw = 0;
		_prevTeeth = 0;
		_prevLips = 0;
		_entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

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

		_highBuf = new decimal[FractalLen];
		_lowBuf = new decimal[FractalLen];
		_bufCount = 0;
		_pendingBuyLevel = null;
		_pendingSellLevel = null;
		_prevJaw = 0;
		_prevTeeth = 0;
		_prevLips = 0;
		_entryPrice = 0;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_jaw, _teeth, _lips, OnProcess)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _jaw);
			DrawIndicator(area, _teeth);
			DrawIndicator(area, _lips);
			DrawOwnTrades(area);
		}
	}

	private void OnProcess(ICandleMessage candle, decimal jawVal, decimal teethVal, decimal lipsVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		// Update fractal buffers
		UpdateFractals(candle);

		var close = candle.ClosePrice;
		var high = candle.HighPrice;
		var low = candle.LowPrice;

		// Manage existing positions - exit on opposite signal
		if (Position > 0)
		{
			// Close long if price breaks below pending sell level or close drops below teeth
			if (_pendingSellLevel is decimal sellLvl && low < sellLvl)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			// Close short if price breaks above pending buy level or close rises above teeth
			if (_pendingBuyLevel is decimal buyLvl && high > buyLvl)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		// Enter long: price breaks above up-fractal level, close above teeth (bullish)
		if (Position <= 0 && _pendingBuyLevel is decimal pendBuy)
		{
			if (high > pendBuy && close > teethVal)
			{
				if (Position < 0)
					BuyMarket(); // close short first

				BuyMarket();
				_entryPrice = close;
			}
		}

		// Enter short: price breaks below down-fractal level, close below teeth (bearish)
		if (Position >= 0 && _pendingSellLevel is decimal pendSell)
		{
			if (low < pendSell && close < teethVal)
			{
				if (Position > 0)
					SellMarket(); // close long first

				SellMarket();
				_entryPrice = close;
			}
		}

		_prevJaw = jawVal;
		_prevTeeth = teethVal;
		_prevLips = lipsVal;
	}

	private void UpdateFractals(ICandleMessage candle)
	{
		var len = _highBuf.Length;
		if (len < 3)
			return;

		// Shift buffers
		Array.Copy(_highBuf, 1, _highBuf, 0, len - 1);
		_highBuf[len - 1] = candle.HighPrice;
		Array.Copy(_lowBuf, 1, _lowBuf, 0, len - 1);
		_lowBuf[len - 1] = candle.LowPrice;

		_bufCount++;
		if (_bufCount < len)
			return;

		var wing = (len - 1) / 2;
		var center = len - 1 - wing;

		// Check up fractal
		var centerHigh = _highBuf[center];
		var isUp = true;
		for (var i = 0; i < len; i++)
		{
			if (i != center && _highBuf[i] >= centerHigh)
			{
				isUp = false;
				break;
			}
		}

		if (isUp)
			_pendingBuyLevel = centerHigh;

		// Check down fractal
		var centerLow = _lowBuf[center];
		var isDown = true;
		for (var i = 0; i < len; i++)
		{
			if (i != center && _lowBuf[i] <= centerLow)
			{
				isDown = false;
				break;
			}
		}

		if (isDown)
			_pendingSellLevel = centerLow;
	}
}