Ver en GitHub

Estrategia Cronex DeMarker

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

  1. Solicitar velas para el marco temporal seleccionado (4H por defecto).
  2. Calcular el oscilador DeMarker y suavizarlo con una SMA rápida (por defecto 14 barras).
  3. Aplicar una segunda SMA (por defecto 25 barras) sobre la línea rápida para obtener la línea de señal.
  4. 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.
  5. 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.
  6. 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;
	}
}