Ver en GitHub

Estrategia Bill Williams Trader

Esta estrategia implementa una versión simplificada del enfoque de trading de Bill Williams basado en el indicador Alligator y los Fractals.

Cómo funciona

  • Calcula las líneas del Alligator usando Medias Móviles Suavizadas (SMMA):
    • Longitud de Jaw (predeterminado 13)
    • Longitud de Teeth (predeterminado 8)
    • Longitud de Lips (predeterminado 5)
  • Detecta fractales alcistas y bajistas en velas completadas.
  • Comprar cuando el precio rompe por encima del último fractal superior que está por encima de la línea teeth del Alligator.
  • Vender cuando el precio rompe por debajo del último fractal inferior que está por debajo de la línea teeth del Alligator.
  • Salir de posiciones largas cuando el precio de cierre cae por debajo de la línea lips.
  • Salir de posiciones cortas cuando el precio de cierre sube por encima de la línea lips.

Parámetros

Nombre Descripción Predeterminado
JawLength Período de la SMMA de la mandíbula del Alligator 13
TeethLength Período de la SMMA de los dientes del Alligator 8
LipsLength Período de la SMMA de los labios del Alligator 5
CandleType Tipo de vela usado para los cálculos Velas de 15 minutos

Todos los parámetros pueden optimizarse mediante la interfaz de parámetros de la estrategia.

Uso

  1. Compilar la solución:
    dotnet build
    
  2. Lanzar la estrategia dentro del entorno StockSharp y seleccionar el instrumento y el marco temporal deseados.

Notas

Este ejemplo demuestra el uso de la API de alto nivel con vinculaciones de indicadores y no implementa dimensionamiento de posiciones ni gestión de riesgos más allá de salidas simples.

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>
/// Bill Williams Trader strategy based on Alligator and Fractals.
/// Buys when price breaks above an upper fractal above the Alligator teeth.
/// Sells when price breaks below a lower fractal below the Alligator teeth.
/// Exits when price crosses the Alligator lips in the opposite direction.
/// </summary>
public class BillWilliamsTraderStrategy : Strategy
{
	private readonly StrategyParam<int> _jawLength;
	private readonly StrategyParam<int> _teethLength;
	private readonly StrategyParam<int> _lipsLength;
	private readonly StrategyParam<DataType> _candleType;

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

	private readonly decimal[] _highBuffer = new decimal[5];
	private readonly decimal[] _lowBuffer = new decimal[5];

	private decimal? _upFractal;
	private decimal? _downFractal;

	/// <summary>
	/// Jaw SMMA period.
	/// </summary>
	public int JawLength
	{
		get => _jawLength.Value;
		set => _jawLength.Value = value;
	}

	/// <summary>
	/// Teeth SMMA period.
	/// </summary>
	public int TeethLength
	{
		get => _teethLength.Value;
		set => _teethLength.Value = value;
	}

	/// <summary>
	/// Lips SMMA period.
	/// </summary>
	public int LipsLength
	{
		get => _lipsLength.Value;
		set => _lipsLength.Value = value;
	}

	/// <summary>
	/// Candle type used by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initialize <see cref="BillWilliamsTraderStrategy"/>.
	/// </summary>
	public BillWilliamsTraderStrategy()
	{
		_jawLength = Param(nameof(JawLength), 13)
			.SetGreaterThanZero()
			.SetDisplay("Jaw Length", "Alligator jaw period", "Alligator")
			
			.SetOptimize(10, 20, 1);

		_teethLength = Param(nameof(TeethLength), 8)
			.SetGreaterThanZero()
			.SetDisplay("Teeth Length", "Alligator teeth period", "Alligator")
			
			.SetOptimize(5, 15, 1);

		_lipsLength = Param(nameof(LipsLength), 5)
			.SetGreaterThanZero()
			.SetDisplay("Lips Length", "Alligator lips period", "Alligator")
			
			.SetOptimize(3, 10, 1);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

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

		Array.Clear(_highBuffer);
		Array.Clear(_lowBuffer);
		_upFractal = null;
		_downFractal = null;
	}

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

		_jaw = new SmoothedMovingAverage { Length = JawLength };
		_teeth = new SmoothedMovingAverage { Length = TeethLength };
		_lips = new SmoothedMovingAverage { Length = LipsLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.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 });

		// shift buffers for fractal detection
		for (var i = 0; i < 4; i++)
		{
			_highBuffer[i] = _highBuffer[i + 1];
			_lowBuffer[i] = _lowBuffer[i + 1];
		}
		_highBuffer[4] = candle.HighPrice;
		_lowBuffer[4] = candle.LowPrice;

		if (candle.State != CandleStates.Finished || !_jaw.IsFormed || !_teeth.IsFormed || !_lips.IsFormed)
			return;

		// detect fractals using the middle bar
		var h2 = _highBuffer[2];
		if (h2 > _highBuffer[0] && h2 > _highBuffer[1] && h2 > _highBuffer[3] && h2 > _highBuffer[4])
			_upFractal = h2;

		var l2 = _lowBuffer[2];
		if (l2 < _lowBuffer[0] && l2 < _lowBuffer[1] && l2 < _lowBuffer[3] && l2 < _lowBuffer[4])
			_downFractal = l2;

		var jaw = jawVal.ToDecimal();
		var teeth = teethVal.ToDecimal();
		var lips = lipsVal.ToDecimal();

		// entry conditions: fractal breakout with Alligator trend filter
		if (_upFractal is decimal up && candle.ClosePrice > up && lips > teeth && teeth > jaw && Position <= 0)
		{
			BuyMarket(Volume + Math.Abs(Position));
			_upFractal = null;
		}
		else if (_downFractal is decimal down && candle.ClosePrice < down && lips < teeth && teeth < jaw && Position >= 0)
		{
			SellMarket(Volume + Math.Abs(Position));
			_downFractal = null;
		}

		// exit conditions based on lips cross
		if (Position > 0 && candle.ClosePrice < lips)
			SellMarket(Position);
		else if (Position < 0 && candle.ClosePrice > lips)
			BuyMarket(-Position);
	}
}