Ver no GitHub

Extreme EA (Conversão para StockSharp)

A estratégia Extreme EA é um Consultor Especialista seguidor de tendência originalmente escrito para MetaTrader. Combina duas médias móveis com um filtro de Índice de Canal de Commodity (CCI) e um módulo de gerenciamento adaptativo de dinheiro. Este porte mantém a lógica de negociação intacta enquanto expõe todos os controles importantes através da API de alto nível do StockSharp. A estratégia opera apenas em velas fechadas e é compatível com múltiplos períodos executando as médias móveis e o CCI em assinaturas de velas independentes.

Visão Geral da Estratégia

  1. Filtro de tendência: Duas médias móveis são calculadas no MaCandleType configurável. A média rápida rastreia o momentum de curto prazo enquanto a média lenta define a inclinação da tendência dominante. A estratégia verifica a inclinação da média lenta usando os dois valores anteriores para imitar os deslocamentos do array CopyBuffer do código MQL.
  2. Filtro de momentum: O CCI é avaliado em seu próprio período (CciCandleType) e fonte de preço. O último valor completado é armazenado em cache e reutilizado até que uma nova vela CCI apareça, o que corresponde ao comportamento dos buffers do MetaTrader.
  3. Regras de entrada:
    • Entrar comprado quando a MA lenta sobe, a MA rápida sobe e o CCI cai abaixo do nível inferior.
    • Entrar vendido quando a MA lenta cai, a MA rápida cai e o CCI sobe acima do nível superior.
  4. Regras de saída:
    • Fechar todos os comprados se a MA lenta parar de subir.
    • Fechar todos os vendidos se a MA lenta parar de cair.

Gerenciamento de Risco

  • MaximumRisk controla o tamanho de posição alvo baseado no patrimônio atual do portfólio e no último preço. Se o volume calculado for zero ou os valores do portfólio não estiverem disponíveis, a estratégia recorre ao Volume configurado ou ao mínimo da bolsa.
  • DecreaseFactor reduz o volume calculado após duas ou mais negociações perdedoras consecutivas. A redução espelha a fórmula original lot = lot - lot * losses / DecreaseFactor.
  • HistoryDays limita por quanto tempo uma sequência de perdas é lembrada. Se uma negociação de fechamento ocorrer após o número especificado de dias, a sequência é reiniciada antes de aplicar a redução.
  • MaxPositions limita a pirâmide restringindo a exposição líquida por direção. Quando o limite é atingido, novas entradas são suprimidas até que a exposição diminua.

Parâmetros

Nome Tipo Padrão Descrição
MaximumRisk decimal 0.05 Fração do patrimônio usada para dimensionar cada nova negociação.
DecreaseFactor decimal 6 Fator de redução por sequência de perdas. Definir como 0 para desativar.
HistoryDays int 60 Número de dias preservados ao contar perdas consecutivas.
MaxPositions int 3 Máximo de entradas simultâneas por direção.
FastMaPeriod int 15 Período para a média móvel rápida.
SlowMaPeriod int 75 Período para a média móvel lenta.
CciPeriod int 12 Comprimento de lookback para o CCI.
CciUpperLevel decimal 50 Limiar CCI superior usado para vendidos.
CciLowerLevel decimal -50 Limiar CCI inferior usado para comprados.
MaCandleType DataType 15m Período para ambas as médias móveis e execução.
CciCandleType DataType 30m Período para o filtro CCI.
MaMethod MaMethod Exponential Método de suavização (Simple, Exponential, Smoothed, LinearWeighted).
MaPriceMode AppliedPriceMode Median Entrada de preço para as médias móveis.
CciPriceMode AppliedPriceMode Typical Entrada de preço para o CCI.

Notas de Implementação

  • A estratégia assina o período das médias móveis uma vez e opcionalmente uma segunda assinatura para o CCI. Quando ambos os períodos coincidem, uma única assinatura alimenta ambos os componentes, reproduzindo o fluxo de trabalho original de gráfico único.
  • Os valores anteriores dos indicadores são armazenados em campos privados para emular as comparações ma_slow_array[1], ma_slow_array[2] e ma_fast_array[0] sem recorrer a buffers de indicadores manuais.
  • O dimensionamento de posição é normalizado contra o passo de volume do instrumento, mínimo e máximo para evitar ordens rejeitadas.
  • O módulo de risco registra os preços de entrada e saída para estimar o PnL realizado por posição completada, o que substitui o loop HistoryDealGet usado no MetaTrader.

Diferenças em relação à Versão MQL

  • Funções específicas do MetaTrader como FreeMarginCheck, MarginCheck e HistorySelect são aproximadas com as métricas de portfólio do StockSharp e o rastreador interno de sequências de perdas.
  • O porte do StockSharp opera em posições líquidas. As ordens de fechamento achatam toda a exposição na direção relevante, alinhando-se com o modelo de posição consolidada.
  • As rotinas de registro do EA original foram omitidas em favor dos diagnósticos integrados 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;

/// <summary>
/// Extreme EA strategy using fast/slow EMA crossover with CCI filter.
/// Buys when both EMAs rising and CCI below lower level (oversold bounce).
/// Sells when both EMAs falling and CCI above upper level (overbought reversal).
/// </summary>
public class ExtremeEaStrategy : Strategy
{
	private readonly StrategyParam<int> _fastMaPeriod;
	private readonly StrategyParam<int> _slowMaPeriod;
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<decimal> _cciUpperLevel;
	private readonly StrategyParam<decimal> _cciLowerLevel;

	private ExponentialMovingAverage _fastMa;
	private ExponentialMovingAverage _slowMa;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _prevFast2;
	private decimal _prevSlow2;
	private bool _hasPrev;

	/// <summary>
	/// Fast EMA period.
	/// </summary>
	public int FastMaPeriod
	{
		get => _fastMaPeriod.Value;
		set => _fastMaPeriod.Value = value;
	}

	/// <summary>
	/// Slow EMA period.
	/// </summary>
	public int SlowMaPeriod
	{
		get => _slowMaPeriod.Value;
		set => _slowMaPeriod.Value = value;
	}

	/// <summary>
	/// CCI indicator length.
	/// </summary>
	public int CciPeriod
	{
		get => _cciPeriod.Value;
		set => _cciPeriod.Value = value;
	}

	/// <summary>
	/// Upper CCI threshold for sell entries.
	/// </summary>
	public decimal CciUpperLevel
	{
		get => _cciUpperLevel.Value;
		set => _cciUpperLevel.Value = value;
	}

	/// <summary>
	/// Lower CCI threshold for buy entries.
	/// </summary>
	public decimal CciLowerLevel
	{
		get => _cciLowerLevel.Value;
		set => _cciLowerLevel.Value = value;
	}

	/// <summary>
	/// Initialize strategy parameters.
	/// </summary>
	public ExtremeEaStrategy()
	{
		_fastMaPeriod = Param(nameof(FastMaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA", "Fast EMA period", "Indicator");

		_slowMaPeriod = Param(nameof(SlowMaPeriod), 200)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA", "Slow EMA period", "Indicator");

		_cciPeriod = Param(nameof(CciPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("CCI Period", "CCI lookback period", "Indicator");

		_cciUpperLevel = Param(nameof(CciUpperLevel), 50m)
			.SetDisplay("CCI Upper", "Upper CCI threshold for sell", "Levels");

		_cciLowerLevel = Param(nameof(CciLowerLevel), -50m)
			.SetDisplay("CCI Lower", "Lower CCI threshold for buy", "Levels");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_fastMa = null;
		_slowMa = null;
		_prevFast = 0;
		_prevSlow = 0;
		_prevFast2 = 0;
		_prevSlow2 = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
		_slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fastMa, _slowMa, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_fastMa.IsFormed || !_slowMa.IsFormed)
		{
			_prevFast2 = _prevFast;
			_prevSlow2 = _prevSlow;
			_prevFast = fastValue;
			_prevSlow = slowValue;
			_hasPrev = true;
			return;
		}

		if (!_hasPrev)
		{
			_prevFast2 = _prevFast;
			_prevSlow2 = _prevSlow;
			_prevFast = fastValue;
			_prevSlow = slowValue;
			_hasPrev = true;
			return;
		}

		var slowIsRising = _prevSlow > _prevSlow2;
		var slowIsFalling = _prevSlow < _prevSlow2;
		var fastIsRising = fastValue > _prevFast;
		var fastIsFalling = fastValue < _prevFast;

		// Buy: fast crosses above slow
		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
		}
		// Sell: fast crosses below slow
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
		}

		_prevFast2 = _prevFast;
		_prevSlow2 = _prevSlow;
		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}