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
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.
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.
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.
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.
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
Anexe a estratégia a um título com uma etapa de preço configurada para que a conversão do pip funcione corretamente.
Ajuste GridStepPips, Multiplier e MaxOrders de acordo com a volatilidade do instrumento e a política de margem da corretora.
Ative os bloqueios de proteção ao executar em uma conta real para evitar perdas descontroladas durante tendências prolongadas.
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).
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;
}
}