Ver no GitHub

Estratégia do comerciante FT Bill Williams

Visão geral

A Estratégia de Trader FT Bill Williams é uma tradução StockSharp de alto nível do consultor especialista MetaTrader "FT_BillWillams_Trader". Ele combina fractais Bill Williams com o indicador Alligator para romper tendências comerciais. A estratégia observa novos fractais, verifica se a estrutura Alligator confirma a direção do rompimento e, opcionalmente, aplica filtros de distância, alinhamento e sinal reverso antes de abrir uma posição.

Lógica de negociação

  1. Detecção fractal – a estratégia armazena em buffer os máximos e mínimos FractalPeriod mais recentes. Quando a barra do meio é o ponto mais alto (ou mais baixo) da janela, um novo nível de rompimento é registrado. Um deslocamento IndentPoints é adicionado acima/abaixo do fractal para evitar entradas prematuras.
  2. Confirmação do intervalo – dependendo de EntryConfirmation:
    • PriceBreakout confirma quando o intervalo da vela cruza o nível de rompimento.
    • CloseBreakout espera que o fechamento da vela anterior ultrapasse o nível.
  3. Verificação de distância – as entradas são rejeitadas quando o nível de rompimento está mais distante que MaxDistancePoints dos lábios Alligator (valor da barra anterior). Defina a distância como zero para desativar o filtro.
  4. Filtro de dentes – quando UseTeethFilter está ativado, o fechamento anterior deve estar acima (para longos) ou abaixo (para curtos) dos dentes Alligator.
  5. Alinhamento de tendência – com UseTrendAlignment = true, os lábios, dentes e mandíbula devem estar separados por pelo menos TeethLipsDistancePoints e JawTeethDistancePoints pontos, respectivamente, confirmando que Alligator está em tendência.
  6. Saídas reversas – se ReverseExit = OppositeFractal, qualquer novo fractal oposto fecha imediatamente a posição aberta. Com OppositePosition, a estratégia primeiro fecha a negociação atual antes de abrir uma na direção oposta.
  7. Saída da mandíbulaJawExit define se a posição é fechada quando o preço cruza a mandíbula Alligator (intrabarra ou no fechamento da vela).
  8. Trailing stop – quando EnableTrailing é verdadeiro e a negociação é lucrativa, o stop se move para os lábios ou dentes dependendo da inclinação relativa dos lábios e do SlopeSmaPeriod SMA. As paradas de proteção iniciais e as metas de lucro são controladas por StopLossPoints e TakeProfitPoints.

Parâmetros

Propriedade Descrição Padrão
OrderVolume Volume de negociação utilizado no envio de ordens de mercado. 0.1
FractalPeriod Número de barras no padrão fractal (valores ímpares recomendados). 5
IndentPoints Offset adicionado ao nível de rompimento (em pontos). 1
EntryConfirmation Modo de confirmação de interrupção (PriceBreakout, CloseBreakout). CloseBreakout
UseTeethFilter Exija que o fechamento anterior esteja no lado correto dos dentes Alligator. true
MaxDistancePoints Distância máxima entre o nível de rompimento e Alligator lábios (pontos). 1000
UseTrendAlignment Aplique separação mínima entre Alligator linhas. false
JawTeethDistancePoints Distância mínima mandíbula-dentes usada no filtro de alinhamento. 10
TeethLipsDistancePoints Distância mínima entre dentes e lábios utilizada no filtro de alinhamento. 10
JawExit Modo de fechamento de posições no crossover da mandíbula (Disabled, PriceCross, CloseCross). CloseCross
ReverseExit Tratamento de sinal oposto (Disabled, OppositeFractal, OppositePosition). OppositePosition
EnableTrailing Ative o gerenciamento de trailing stop baseado em Alligator. true
SlopeSmaPeriod Período do SMA que é comparado com a inclinação dos lábios. 5
StopLossPoints Distância de stop-loss em pontos (0 desabilita). 50
TakeProfitPoints Distância de lucro em pontos (0 desabilita). 50
JawPeriod, TeethPeriod, LipsPeriod Pontos finais para as linhas Alligator. 13, 8, 5
JawShift, TeethShift, LipsShift Deslocamento para frente para cada linha Alligator. 8, 5, 3
MaMethod Tipo de média móvel para Alligator (Simple, Exponential, Smoothed, Weighted). Simple
AppliedPrice Preço da vela fornecida ao Alligator. CandlePrice.Median
CandleType Tipo de vela subscrito a partir dos dados de mercado. 15-minute timeframe

Notas adicionais

  • A estratégia desenha as Alligator linhas e executa as negociações na área padrão do gráfico.
  • FractalPeriod deve permanecer ímpar para que a barra do meio represente o ápice do fractal; o valor padrão corresponde ao consultor especialista original.
  • Parâmetros baseados em distância (IndentPoints, MaxDistancePoints, JawTeethDistancePoints, TeethLipsDistancePoints, StopLossPoints, TakeProfitPoints) são expressos em pontos de corretagem (Security.PriceStep).
  • As paradas finais e as saídas de mandíbula dependem de velas concluídas, espelhando a lógica MQL original que funciona com os valores de barra anteriores do 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;
	}
}