Ver en GitHub

Estrategia Cronex AC

La estrategia Cronex AC recrea el clásico asesor experto Cronex Acceleration/Deceleration (AC) utilizando la API de alto nivel de StockSharp. Suaviza el Oscilador Acelerador con dos medias móviles consecutivas y reacciona cuando la línea rápida cruza la línea lenta. Los cruces alcistas abren posiciones largas y cierran cortas, mientras que los cruces bajistas abren cortas y cierran largas.

Lógica de trading

  1. Construir valores del Oscilador Acelerador (AO-AC) desde la serie de velas seleccionada.
  2. Suavizar el AC con el tipo de media móvil elegido dos veces: el primer suavizado produce la línea "rápida" y el segundo suavizado produce la línea "señal".
  3. Evaluar las dos líneas en la barra definida por el parámetro SignalBar. La estrategia también mira una barra más atrás para confirmar un cruce.
  4. Cuando la línea rápida cruza por encima de la línea de señal, la estrategia cierra las posiciones cortas existentes (si está habilitado) y abre una nueva posición larga (si está habilitado).
  5. Cuando la línea rápida cruza por debajo de la línea de señal, la estrategia cierra las posiciones largas existentes (si está habilitado) y abre una nueva posición corta (si está habilitado).
  6. El tamaño de la posición es igual al Volume configurado más el valor absoluto de la posición actual, permitiendo reversiones en una sola orden a mercado.

La lógica refleja al experto MQL5 actuando únicamente en velas completamente terminadas y separando los permisos para entradas y salidas en ambas direcciones.

Parámetros

Nombre Tipo Valor predeterminado Descripción
SmoothingType CronexMovingAverageType Simple Algoritmo de media móvil aplicado al Oscilador Acelerador. Opciones: Simple, Exponential, Smoothed, Weighted.
FastPeriod int 14 Retroceso del primer suavizado (línea rápida).
SlowPeriod int 25 Retroceso del segundo suavizado (línea de señal).
SignalBar int 1 Número de barras terminadas a mirar atrás al leer la señal. Un valor de 1 replica el comportamiento Cronex predeterminado.
CandleType DataType TimeFrame(8h) Serie de velas utilizada para los cálculos.
EnableLongEntry bool true Permitir abrir posiciones largas después de un cruce alcista.
EnableShortEntry bool true Permitir abrir posiciones cortas después de un cruce bajista.
EnableLongExit bool true Permitir cerrar posiciones largas cuando la línea rápida cae por debajo de la línea lenta.
EnableShortExit bool true Permitir cerrar posiciones cortas cuando la línea rápida sube por encima de la línea lenta.
Volume decimal predeterminado de la estrategia Tamaño de orden utilizado para entradas. La estrategia añade automáticamente el valor absoluto de la posición abierta para revertir en una sola operación.

Gráficos

Cuando hay un área de gráfico disponible, la estrategia representa:

  • velas fuente para el marco temporal seleccionado,
  • valores del Oscilador Acelerador,
  • medias móviles rápida y de señal,
  • las propias operaciones de la estrategia para validación visual.

Notas

  • Todos los cálculos se basan en velas completadas (CandleStates.Finished) para evitar repintado.
  • Los buffers de suavizado mantienen exactamente los valores históricos suficientes para evaluar el desplazamiento SignalBar solicitado, coincidiendo con el experto MQL original.
  • Las características de gestión monetaria de la versión MQL (stop-loss, take-profit, desviación) se omiten intencionalmente para que la gestión de posiciones pueda manejarse externamente a través de los controles de riesgo de StockSharp.
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 CronexAcStrategy : 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 CronexAcStrategy()
	{
		_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;
	}
}