Ver no GitHub

Estratégia Cronex AC

A estratégia Cronex AC recria o clássico consultor especialista Cronex Acceleration/Deceleration (AC) usando a API de alto nível do StockSharp. Ela suaviza o Oscilador Acelerador com duas médias móveis consecutivas e reage quando a linha rápida cruza a linha lenta. Cruzamentos altistas abrem posições compradas e fecham vendidas, enquanto cruzamentos baixistas abrem vendidas e fecham compradas.

Lógica de trading

  1. Construir valores do Oscilador Acelerador (AO-AC) a partir da série de velas selecionada.
  2. Suavizar o AC com o tipo de média móvel escolhido duas vezes: a primeira suavização produz a linha "rápida" e a segunda suavização produz a linha "sinal".
  3. Avaliar as duas linhas na barra definida pelo parâmetro SignalBar. A estratégia também olha uma barra mais atrás para confirmar um cruzamento.
  4. Quando a linha rápida cruza acima da linha de sinal, a estratégia fecha posições vendidas existentes (se habilitado) e abre uma nova posição comprada (se habilitado).
  5. Quando a linha rápida cruza abaixo da linha de sinal, a estratégia fecha posições compradas existentes (se habilitado) e abre uma nova posição vendida (se habilitado).
  6. O tamanho da posição é igual ao Volume configurado mais o valor absoluto da posição atual, permitindo reversões em uma única ordem a mercado.

A lógica espelha o especialista MQL5 agindo apenas em velas completamente finalizadas e separando as permissões para entradas e saídas em ambas as direções.

Parâmetros

Nome Tipo Padrão Descrição
SmoothingType CronexMovingAverageType Simple Algoritmo de média móvel aplicado ao Oscilador Acelerador. Opções: Simple, Exponential, Smoothed, Weighted.
FastPeriod int 14 Retrocesso da primeira suavização (linha rápida).
SlowPeriod int 25 Retrocesso da segunda suavização (linha de sinal).
SignalBar int 1 Número de barras finalizadas a olhar para trás ao ler o sinal. Um valor de 1 replica o comportamento padrão do Cronex.
CandleType DataType TimeFrame(8h) Série de velas usada para cálculos.
EnableLongEntry bool true Permitir abrir posições compradas após um cruzamento altista.
EnableShortEntry bool true Permitir abrir posições vendidas após um cruzamento baixista.
EnableLongExit bool true Permitir fechar posições compradas quando a linha rápida cai abaixo da linha lenta.
EnableShortExit bool true Permitir fechar posições vendidas quando a linha rápida sobe acima da linha lenta.
Volume decimal padrão da estratégia Tamanho de ordem usado para entradas. A estratégia adiciona automaticamente o valor absoluto da posição aberta para reverter em uma única operação.

Gráficos

Quando uma área de gráfico está disponível, a estratégia plota:

  • velas fonte para o período selecionado,
  • valores do Oscilador Acelerador,
  • médias móveis rápida e de sinal,
  • as próprias operações da estratégia para validação visual.

Notas

  • Todos os cálculos dependem de velas concluídas (CandleStates.Finished) para evitar repintagem.
  • Os buffers de suavização mantêm exatamente valores históricos suficientes para avaliar o deslocamento SignalBar solicitado, correspondendo ao especialista MQL original.
  • Recursos de gestão monetária da versão MQL (stop-loss, take-profit, desvio) são intencionalmente omitidos para que a gestão de posições possa ser tratada externamente através dos controles de risco do 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;
	}
}