La estrategia FX-CHAOS Scalp MT4 es una adaptación directa del asesor experto MetaTrader 4 que combina un filtro Awesome Oscillator con niveles de ZigZag construidos sobre fractales. La versión StockSharp mantiene el diseño de múltiples marcos temporales del sistema original: las velas horarias generan señales comerciales mientras que las velas diarias proporcionan un sesgo de marco temporal más alto. Dos rastreadores integrados reconstruyen el indicador "ZigZag en Fractals" escaneando patrones de cinco velas y registrando máximos y mínimos alternos.
Flujo de trabajo comercial
Recopilación de datos
Las velas horarias alimentan la lógica de ejecución primaria y los controles de riesgo.
Las velas diarias actualizan la oscilación del ZigZag a largo plazo utilizada como filtro de tendencia.
El Awesome Oscillator (5, 34) se evalúa en la serie horaria a través del indicador de alto nivel API.
Reconstrucción en zigzag
Cada vela terminada se guarda en una ventana corrediza de cinco elementos.
Cuando la vela del medio forma un fractal ascendente, el rastreador guarda la vela alta como la última oscilación y cambia la dirección a "arriba"; un fractal descendente hace lo mismo con los mínimos.
Las oscilaciones consecutivas en la misma dirección sólo se reemplazan si el nuevo extremo es más pronunciado, imitando la lógica de amortiguación del indicador MT4.
Detección de señal
El búfer de ruptura agrega dos compensaciones de pasos de precio al máximo/mínimo de la hora anterior, reflejando el relleno 2*Point que se encuentra en el código original.
Para entradas largas, la vela debe abrirse por debajo del máximo amortiguado, cerrar por encima de él, permanecer por debajo de la oscilación horaria más reciente del ZigZag, cerrar por encima de la última oscilación diaria y mantener el Oscilador Impresionante negativo.
Las entradas cortas reflejan las condiciones que utilizan los valores del oscilador positivo, el nivel inferior de ZigZag superior y el buffer.
Ejecución de órdenes y resolución de conflictos
Las posiciones opuestas se cierran antes de enviar una nueva orden, por lo que la estrategia nunca mantiene operaciones largas y cortas simultáneas.
El precio de cierre ejecutado se almacena para derivar distancias de stop-loss y take-profit en velas posteriores.
Gestión del riesgo
Los umbrales de limitación de pérdidas y obtención de beneficios son opcionales; un valor de 0 deshabilita la regla correspondiente.
Al final de cada vela terminada, la estrategia comprueba si el rango de la vela ha tocado el stop o el objetivo configurado y cierra la posición si se ha superado el nivel.
Cuando aparece una ruptura opuesta, la posición se liquida primero y luego la nueva operación se envía en la misma vela para preservar la regla de posición única.
Parámetros
Nombre
Descripción
Volume
Volumen comercial en lotes aplicado a cada orden de mercado.
Stop Loss (pts)
Distancia en puntos para el tope de protección. Multiplicado por el paso del precio del valor. Establezca en 0 para desactivar.
Take Profit (pts)
Distancia en puntos para el objetivo de beneficio. Multiplicado por el paso de precio. Establezca en 0 para desactivar.
Breakout Buffer
Se agregaron puntos adicionales al extremo de la vela anterior antes de probar las rupturas. El valor predeterminado reproduce el colchón 2*Point utilizado en MT4.
Spread (pts)
Spread promedio en puntos que se agrega al umbral de ruptura en las señales de compra para que la entrada refleje 2*Point + spread de MT4.
Trading Candle
Plazo principal utilizado para las entradas (el valor predeterminado es una hora).
Daily Candle
Se utiliza un período de tiempo más alto para el filtro ZigZag (el valor predeterminado es un día).
Notas de implementación
La estrategia se basa en los SubscribeCandles API y BindEx de alto nivel para evitar trabajar con buffers de indicadores directamente, respetando las pautas del repositorio.
El paso de precio recuperado de Security.PriceStep se utiliza para convertir valores de parámetros expresados en puntos en distancias de precios absolutas. Si al instrumento le falta un paso, el código vuelve a 1.
Ambos rastreadores de ZigZag se reinician en OnReseted y pausan las operaciones hasta que acumulan suficientes velas para determinar el primer movimiento. Esto evita entradas prematuras cuando falta el contexto histórico.
La representación del gráfico dibuja las velas horarias, el Awesome Oscillator y las operaciones de estrategia para ayudar a comparar la implementación de StockSharp con la plantilla MT4.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class FxChaosScalpMt4Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _momentumPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevMom;
private bool _hasPrev;
private int _cooldownRemaining;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FxChaosScalpMt4Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA filter", "Indicators");
_momentumPeriod = Param(nameof(MomentumPeriod), 10).SetDisplay("Momentum", "Momentum period", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 200).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMom = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var mom = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, mom, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal mom)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevMom = mom; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevMom = mom;
return;
}
if (close > ema && _prevMom <= 0 && mom > 0 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (close < ema && _prevMom >= 0 && mom < 0 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevMom = mom;
}
}
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, Momentum
from StockSharp.Algo.Strategies import Strategy
class fx_chaos_scalp_mt4_strategy(Strategy):
def __init__(self):
super(fx_chaos_scalp_mt4_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 14).SetDisplay("EMA Period", "EMA filter", "Indicators")
self._momentum_period = self.Param("MomentumPeriod", 10).SetDisplay("Momentum", "Momentum period", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 200).SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_mom = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def ema_period(self): return self._ema_period.Value
@property
def momentum_period(self): return self._momentum_period.Value
@property
def cooldown_candles(self): return self._cooldown_candles.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(fx_chaos_scalp_mt4_strategy, self).OnReseted()
self._prev_mom = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(fx_chaos_scalp_mt4_strategy, self).OnStarted2(time)
self._prev_mom = 0.0
self._has_prev = False
self._cooldown_remaining = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
mom = Momentum()
mom.Length = self.momentum_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, mom, self.process_candle).Start()
def process_candle(self, candle, ema, mom):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema)
mom_val = float(mom)
if not self._has_prev:
self._prev_mom = mom_val
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_mom = mom_val
return
if close > ema_val and self._prev_mom <= 0 and mom_val > 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif close < ema_val and self._prev_mom >= 0 and mom_val < 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_mom = mom_val
def CreateClone(self):
return fx_chaos_scalp_mt4_strategy()