Esta estrategia porta el asesor experto de MetaTrader 5 "Bill Williams.mq5" de Vladimir Karputov a la API de alto nivel de StockSharp. Se suscribe a una única serie de velas, reconstruye los puntos fractales de Bill Williams y evalúa las rupturas en relación con las líneas Alligator desplazadas. Cuando la vela actual cierra más allá del fractal alcista o bajista más cercano y ese fractal se sitúa fuera de las tres curvas del Alligator (Mandíbula, Dientes, Labios), el sistema abre una posición. Las funciones opcionales de gestión monetaria reproducen los inputs originales como stop-loss, take-profit, trailing stop, reversión de señales y cierre automático de posiciones opuestas.
Lógica de operación
Detección de fractales – cada vela finalizada actualiza los buffers rodantes de máximos y mínimos. El algoritmo escanea hasta FractalsLookback barras completadas y encuentra los fractales alcistas y bajistas de Bill Williams más recientes confirmados (patrón de cinco barras).
Reconstrucción del Alligator – el Precio Mediano (High + Low) / 2 alimenta tres instancias de SmoothedMovingAverage que representan la mandíbula, los dientes y los labios. Sus valores se desplazan hacia adelante el número configurado de barras para coincidir con las reglas de representación de MetaTrader.
Validación de ruptura – una configuración larga requiere que el último fractal alcista esté por encima de la mandíbula, los dientes y los labios desplazados, mientras que la vela más reciente cierra por encima del precio del fractal. Una configuración corta refleja la lógica por debajo del Alligator.
Ejecución de órdenes – por defecto, la estrategia abre una única orden de mercado con OrderVolume cuando se detecta la ruptura y no se mantiene posición. Si CloseOppositePositions está habilitado, se aplana una posición opuesta antes de abrir una nueva. Establecer ReverseSignals = true intercambia los lados de ruptura para reproducir el modo inverso del EA.
Gestión de riesgos – los niveles de stop-loss y take-profit configurables se almacenan internamente y se evalúan en cada vela. El trailing stop se activa una vez que el mercado se mueve TrailingStopPips + TrailingStepPips en la dirección del trade y sigue avanzando conforme el precio avanza. Los stops se expresan en "pips" derivados del PriceStep del instrumento, incluyendo el ajuste de 3 o 5 dígitos de MetaTrader.
Parámetros
Nombre
Descripción
Predeterminado
OrderVolume
Tamaño del trade en lotes o contratos para entradas de mercado.
0.1
StopLossPips
Distancia de stop-loss inicial en pips. Establecer en 0 para deshabilitar.
50
TakeProfitPips
Distancia de take-profit en pips. Establecer en 0 para deshabilitar.
50
TrailingStopPips
Distancia de trailing stop en pips. 0 deshabilita la lógica de trailing.
10
TrailingStepPips
Ganancia pip adicional requerida antes de que el trailing stop se mueva nuevamente. Debe ser positivo cuando el trailing está habilitado.
5
JawPeriod
Longitud de la media móvil suavizada para la mandíbula del Alligator (azul).
13
JawShift
Desplazamiento hacia adelante para los valores de la mandíbula, medido en barras.
8
TeethPeriod
Longitud de la media móvil suavizada de los dientes (rojo).
8
TeethShift
Desplazamiento hacia adelante para los valores de los dientes.
5
LipsPeriod
Longitud de la media móvil suavizada de los labios (verde).
5
LipsShift
Desplazamiento hacia adelante para los valores de los labios.
3
FractalsLookback
Número de velas completadas escaneadas al buscar los fractales confirmados más recientes.
100
ReverseSignals
Cuando es true, las señales de compra provienen de rupturas de fractal bajista y las señales de venta provienen de rupturas de fractal alcista.
false
CloseOppositePositions
Cuando es true, la estrategia cierra una posición opuesta existente antes de entrar en un nuevo trade.
false
CandleType
Serie de velas utilizada para cálculos y señales.
TimeFrame(1h)
Notas
La estrategia opera estrictamente en velas finalizadas e ignora los ticks intrabarra, coincidiendo con el flujo de trabajo barra a barra del Expert Advisor original.
Para emular el cálculo de pip de MetaTrader 5, la estrategia multiplica el PriceStep del exchange por 10 cuando el instrumento tiene 3 o 5 lugares decimales.
Las órdenes protectoras y el trailing stop se gestionan internamente. Cuando se cumple una condición de stop o objetivo en la siguiente vela, la posición se cierra a mercado para imitar la gestión de órdenes del EA.
Los indicadores Alligator se dibujan automáticamente si hay un área de gráfico disponible, permitiendo la comparación visual entre el port de StockSharp y la plantilla de MetaTrader.
Los proyectos de Python y pruebas se omiten intencionalmente según las directrices del repositorio para nuevas conversiones.
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;
public class BillWilliamsAlligatorStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public BillWilliamsAlligatorStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bill_williams_alligator_strategy(Strategy):
def __init__(self):
super(bill_williams_alligator_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(bill_williams_alligator_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(bill_williams_alligator_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return bill_williams_alligator_strategy()