La Estrategia Cronex DeMarker reproduce el clásico asesor experto Cronex que combina el oscilador DeMarker con una pila de doble suavizado. Primero, los valores del DeMarker son suavizados por una media móvil simple rápida, luego el resultado es suavizado una vez más por una media más lenta. La distancia y el orden relativo de estas dos líneas proporcionan señales de entrada estilo reversión.
La implementación MQL5 original permite alternancias de dirección de trade y funciona en marcos temporales superiores. Este puerto StockSharp mantiene la misma filosofía: reacciona cuando la línea rápida cruza a través de la lenta y cierra inmediatamente cualquier posición opuesta. Debido a que el sistema es contrario, un cruce por debajo de la línea lenta abre una posición larga, mientras que un cruce por encima abre una corta. Ambas direcciones pueden desactivarse de forma independiente a través de parámetros, lo que hace que la estrategia sea flexible para diferentes asignaciones de cartera.
Cómo funciona
Solicitar velas para el marco temporal seleccionado (4H por defecto).
Calcular el oscilador DeMarker y suavizarlo con una SMA rápida (por defecto 14 barras).
Aplicar una segunda SMA (por defecto 25 barras) sobre la línea rápida para obtener la línea de señal.
Cuando la línea rápida estaba por encima de la línea lenta en la vela anterior y ahora cae por debajo, la estrategia compra (reversión contraria). Cualquier posición corta existente se aplana.
Cuando la línea rápida estaba por debajo de la línea lenta en la vela anterior y ahora sube por encima, la estrategia vende y cierra cualquier posición larga abierta.
El tamaño de la posición se define por la propiedad Volume; las reversiones usan la posición absoluta para invertir inmediatamente.
Esta lógica permite al experto capturar movimientos de agotamiento a corto plazo después de fuertes empujes de momentum, convirtiéndolo en una herramienta de reversión a la media que prefiere mercados en rango o choppy.
Parámetros predeterminados
Parámetro
Valor predeterminado
Descripción
DeMarkerPeriod
25
Número de barras utilizadas por el oscilador DeMarker.
FastPeriod
14
Longitud de la primera SMA de suavizado aplicada a los valores del DeMarker.
SlowPeriod
25
Longitud de la SMA de señal aplicada a la línea rápida.
CandleType
4 horas
Serie de velas utilizada para los cálculos del indicador.
EnableLongEntry
true
Permitir entradas largas contrarias cuando la línea rápida cruza por debajo de la línea lenta.
EnableShortEntry
true
Permitir entradas cortas cuando la línea rápida cruza por encima de la línea lenta.
EnableLongExit
true
Cerrar posiciones largas existentes cuando aparecen condiciones bajistas.
EnableShortExit
true
Cerrar posiciones cortas existentes cuando aparecen condiciones alcistas.
Filtros y etiquetas
Categoría: Reversión a la media, basado en Oscilador
Dirección: Largo y Corto (configurable)
Indicadores: DeMarker, Media Móvil Simple (doble suavizado)
Stops: Ninguno (totalmente impulsado por señal)
Marco temporal: Trading Swing (H4 por defecto, ajustable)
Complejidad: Intermedio debido a la cadena de indicadores secuenciales
Perfil de riesgo: Medio — las entradas contrarias pueden enfrentar tendencias extendidas
Automatización: Totalmente automatizado a través de la API de alto nivel de StockSharp
Notas de uso
La estrategia solo procesa velas terminadas para evitar problemas de repintado.
Las órdenes de reversión reutilizan el tamaño de posición absoluto, garantizando aplanamiento inmediato antes de entrar en la nueva dirección.
La salida del gráfico dibuja las dos líneas suavizadas y los marcadores de trade, ayudando con la validación discrecional.
Para carteras que solo permiten una dirección, deshabilitar las entradas y salidas no deseadas a través de los parámetros proporcionados.
Considerar agregar controles de riesgo externos (stop-loss, salida trailing) al implementar en activos volátiles.
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 CronexDeMarkerStrategy : 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 CronexDeMarkerStrategy()
{
_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 cronex_de_marker_strategy(Strategy):
def __init__(self):
super(cronex_de_marker_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(cronex_de_marker_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(cronex_de_marker_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 cronex_de_marker_strategy()