Ver no GitHub

Estratégia de energia das ondas EA

A Estratégia Wave Power EA é uma versão C# do consultor especialista MQL4 "Wave Power EA1". O robô original constrói uma posição em direção de um sinal estocástico ou MACD e, em seguida, adiciona ordens de mercado adicionais a cada número fixo de pips enquanto ajusta o nível de lucro compartilhado. A versão StockSharp reproduz esse comportamento usando a estratégia de alto nível API, vinculação de indicador e ajudantes de pedidos integrados. Todos os comentários permanecem em inglês, conforme necessário.

Como funciona a estratégia

  1. Seleção de sinal – a primeira negociação é aberta somente quando um dos filtros do indicador gera uma direção:

    • Stochastic – %K cruzando %D dentro de regiões de sobrevenda/sobrecompra.
    • MacdSlope – MACD linha subindo acima ou caindo abaixo de seu valor anterior.
    • CciLevels – CCI caindo abaixo de –120 ou subindo acima de +120.
    • AwesomeBreakout – Oscilador impressionante quebrando o histórico adaptativo baixo/alto que foi capturado durante a inicialização.
    • RsiMa – rápido SMA cruza lento SMA enquanto RSI confirma impulso (acima/abaixo de 50).
    • SmaTrend – um leque 15/20/25/50 SMA apontando na mesma direção com uma diferença mínima de inclinação.
  2. Expansão da grade – após o preenchimento da primeira ordem de mercado, a estratégia lembra o preço de preenchimento. Sempre que o mercado se move por GridStepPips em relação à posição atual e a contagem máxima de pedidos não for excedida, a estratégia envia um novo mercado faça o pedido na mesma direção. Cada nova camada multiplica o volume pelo parâmetro Multiplier.

  3. Metas compartilhadas – cada novo pedido recalcula um preço comum de take-profit e (opcionalmente) de stop-loss. Quando o número de pedidos ativos se aproximam do limite OrdersToProtect, a distância de realização do lucro é substituída por ReboundProfitPrimary. Depois que o limite é excedido, a distância muda para ReboundProfitSecondary para estimular uma recuperação mais rápida.

  4. Monitoramento de cesta – a cada fechamento de vela, a estratégia converte o P&L aberto em pips por lote. Se o lucro de recuperação ou os limites de proteção contra perdas são atingidos, toda a cesta é liquidada usando ordens de mercado. O mesmo acontece quando o mais velho a negociação for anterior a OrdersTimeAliveSeconds ou quando a negociação na sexta-feira estiver desativada.

  5. Ciclo de vida – quando a cesta estiver plana, todos os contadores internos serão zerados, permitindo que o próximo sinal inicie uma nova média ciclo.

Em comparação com o EA original, esta porta evita intencionalmente a abertura de posições opostas (hedge) após um certo número de grades camadas. Todas as entradas adicionais seguem a direção inicial. O resto das regras de gestão de dinheiro, lógica de proteção e os filtros do indicador permanecem compatíveis com a implementação de referência MQL4.

Parâmetros

Parâmetro Descrição
EntryLogic Modo indicador usado para o primeiro pedido.
CandleType Prazo que alimenta todos os indicadores (padrão: 1 hora).
InitialVolume Volume da primeira ordem em lotes/contratos.
GridStepPips Distância mínima em pips entre as camadas da grade.
MaxOrders Número máximo de pedidos simultâneos na cesta.
TakeProfitPips Distância de lucro compartilhada em pips (0 desativa a meta).
StopLossPips Distância de stop-loss compartilhada em pips (0 desativa o stop).
Multiplier Multiplicador de volume aplicado a cada pedido adicional.
SecureProfitProtection Ativa a lógica de lucro de recuperação.
OrdersToProtect Número de pedidos necessários antes do início da proteção contra recuperação.
ReboundProfitPrimary Lucro por lote (em pips) para a primeira etapa de proteção.
ReboundProfitSecondary Lucro por lote (em pips) quando a contagem de pedidos protegidos for excedida.
LossProtection Ativa a proteção contra perda flutuante.
LossThreshold Perda por lote (em pips) que aciona a guarda quando o cesto está cheio.
ReverseCondition Inverte sinais de compra/venda.
TradeOnFriday Permite abertura de novos pedidos às sextas-feiras.
OrdersTimeAliveSeconds Vida útil máxima do pedido mais recente em segundos (0 desativa o cronômetro).
TrendSlopeThreshold Diferença mínima de inclinação SMA usada pela lógica SmaTrend.

Dicas de uso

  1. Anexe a estratégia a um título com uma etapa de preço configurada para que a conversão do pip funcione corretamente.
  2. Ajuste GridStepPips, Multiplier e MaxOrders de acordo com a volatilidade do instrumento e a política de margem da corretora.
  3. Ative os bloqueios de proteção ao executar em uma conta real para evitar perdas descontroladas durante tendências prolongadas.
  4. A estratégia depende de velas fechadas; escolha um período de tempo que reflita o ritmo de negociação desejado (o EA original usa M30 e H1, mas as velas H1 padrão funcionam bem).
  5. Como a cobertura após a quinta camada não é implementada, considere reduzir MaxOrders se você precisar do original exato comportamento.

Arquivos

  • CS/WavePowerEAStrategy.cs – StockSharp implementação da lógica de grade Wave Power EA.
  • README.md / README_ru.md / README_zh.md – documentação em inglês, russo e chinês.

A versão Python é omitida intencionalmente de acordo com os requisitos da tarefa.

using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Wave Power strategy using RSI + EMA crossover for entry
/// with grid-like averaging on drawdown.
/// </summary>
public class WavePowerEAStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _gridStepPercent;
	private readonly StrategyParam<int> _maxGridOrders;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _gridCount;

	public WavePowerEAStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 12)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI period.", "Indicators");

		_gridStepPercent = Param(nameof(GridStepPercent), 0.5m)
			.SetDisplay("Grid Step %", "Price move % to add to position.", "Grid");

		_maxGridOrders = Param(nameof(MaxGridOrders), 5)
			.SetDisplay("Max Grid Orders", "Maximum averaging orders.", "Grid");
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal GridStepPercent
	{
		get => _gridStepPercent.Value;
		set => _gridStepPercent.Value = value;
	}

	public int MaxGridOrders
	{
		get => _maxGridOrders.Value;
		set => _maxGridOrders.Value = value;
	}

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

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_gridCount = 0;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, rsi, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevSlow == 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;
		var bullishCross = _prevFast <= _prevSlow && fastVal > slowVal;
		var bearishCross = _prevFast >= _prevSlow && fastVal < slowVal;

		// Exit on opposite cross
		if (Position > 0 && bearishCross)
		{
			SellMarket();
			_gridCount = 0;
			_entryPrice = 0;
		}
		else if (Position < 0 && bullishCross)
		{
			BuyMarket();
			_gridCount = 0;
			_entryPrice = 0;
		}

		// Grid averaging: add to position if price moved against us
		if (Position > 0 && _entryPrice > 0 && _gridCount < MaxGridOrders)
		{
			var dropPercent = (_entryPrice - close) / _entryPrice * 100;
			if (dropPercent >= GridStepPercent * (_gridCount + 1))
			{
				BuyMarket();
				_gridCount++;
			}
		}
		else if (Position < 0 && _entryPrice > 0 && _gridCount < MaxGridOrders)
		{
			var risePercent = (close - _entryPrice) / _entryPrice * 100;
			if (risePercent >= GridStepPercent * (_gridCount + 1))
			{
				SellMarket();
				_gridCount++;
			}
		}

		// New entry
		if (Position == 0)
		{
			if (bullishCross && rsiVal > 50)
			{
				_entryPrice = close;
				_gridCount = 0;
				BuyMarket();
			}
			else if (bearishCross && rsiVal < 50)
			{
				_entryPrice = close;
				_gridCount = 0;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}