Estrategia de energía de las olas EA
La Estrategia Wave Power EA es una adaptación de C# del asesor experto MQL4 "Wave Power EA1". El robot original construye una posición en
dirección de una señal estocástica o MACD y luego agrega órdenes de mercado adicionales cada número fijo de pips mientras ajusta la
nivel de toma de ganancias compartido. La versión StockSharp reproduce este comportamiento utilizando la estrategia de alto nivel API, enlace de indicador
y ayudantes de pedidos integrados. Todos los comentarios permanecen en inglés según sea necesario.
Cómo funciona la estrategia
Selección de señal – la primera operación se abre solo cuando uno de los filtros del indicador genera una dirección:
Stochastic – %K cruza %D dentro de regiones de sobreventa/sobrecompra.
MacdSlope – MACD línea que sube por encima o cae por debajo de su valor anterior.
CciLevels – CCI cae por debajo de –120 o sube por encima de +120.
AwesomeBreakout – Oscilador impresionante que rompe el mínimo/máximo histórico adaptativo que se capturó durante la inicialización.
RsiMa – el rápido SMA cruza el lento SMA mientras que RSI confirma el impulso (por encima/por debajo de 50).
SmaTrend – un ventilador 15/20/25/50 SMA apuntando en la misma dirección con una diferencia de pendiente mínima.
Expansión de la red: después de que se completa la primera orden de mercado, la estrategia recuerda el precio de ejecución. Cada vez que el mercado se mueve
por GridStepPips contra la posición actual y no se excede el recuento máximo de órdenes, la estrategia envía un nuevo mercado
ordene en la misma dirección. Cada nueva capa multiplica el volumen por el parámetro Multiplier.
Objetivos compartidos: cada nueva orden recalcula un precio común de obtención de ganancias y (opcionalmente) de límite de pérdidas. Cuando el número de
las órdenes activas se acercan al umbral OrdersToProtect, la distancia de obtención de beneficios se reemplaza por ReboundProfitPrimary.
Una vez superado el umbral, la distancia cambia a ReboundProfitSecondary para fomentar una recuperación más rápida.
Monitoreo de cesta: en cada cierre de vela, la estrategia convierte las pérdidas y ganancias abiertas en pips por lote. Si el beneficio de rebote o
Cuando se alcanzan los umbrales de protección contra pérdidas, toda la cesta se liquida mediante órdenes de mercado. Lo mismo ocurre cuando el mayor
la operación es anterior a OrdersTimeAliveSeconds o cuando la operación el viernes está deshabilitada.
Ciclo de vida: una vez que la canasta está plana, todos los contadores internos se reinician, lo que permite que la siguiente señal comience un nuevo promedio
ciclo.
En comparación con el EA original, este puerto evita intencionalmente abrir posiciones opuestas (de cobertura) después de un cierto número de cuadrículas.
capas. Todas las entradas adicionales siguen la dirección inicial. El resto de las normas de gestión del dinero, la lógica de protección y
Los filtros de indicador siguen siendo compatibles con la implementación de referencia MQL4.
Parámetros
| Parámetro |
Descripción |
EntryLogic |
Modo indicador utilizado para el primer pedido. |
CandleType |
Plazo que alimenta todos los indicadores (predeterminado: 1 hora). |
InitialVolume |
Volumen del primer pedido en lotes/contratos. |
GridStepPips |
Distancia mínima en pips entre capas de la cuadrícula. |
MaxOrders |
Número máximo de pedidos simultáneos en la cesta. |
TakeProfitPips |
Distancia de toma de ganancias compartida en pips (0 desactiva el objetivo). |
StopLossPips |
Distancia de stop-loss compartida en pips (0 desactiva el stop). |
Multiplier |
Multiplicador de volumen aplicado a cada pedido adicional. |
SecureProfitProtection |
Habilita la lógica del beneficio de rebote. |
OrdersToProtect |
Número de órdenes necesarias antes de que comience la protección contra rebotes. |
ReboundProfitPrimary |
Beneficio por lote (en pips) para la primera etapa de protección. |
ReboundProfitSecondary |
Beneficio por lote (en pips) una vez que se excede el recuento de órdenes protegidas. |
LossProtection |
Habilita la guardia de pérdida flotante. |
LossThreshold |
Pérdida por lote (en pips) que activa la guardia cuando la canasta está llena. |
ReverseCondition |
Invierte señales de compra/venta. |
TradeOnFriday |
Permite abrir nuevos pedidos los viernes. |
OrdersTimeAliveSeconds |
Vida útil máxima del pedido más reciente en segundos (0 desactiva el temporizador). |
TrendSlopeThreshold |
Diferencia de pendiente mínima SMA utilizada por la lógica SmaTrend. |
Consejos de uso
- Adjunte la estrategia a un valor con un paso de precio configurado para que la conversión de pips funcione correctamente.
- Ajuste
GridStepPips, Multiplier y MaxOrders según la volatilidad del instrumento y la política de margen del corredor.
- Habilite los bloques de protección cuando ejecute una cuenta real para evitar pérdidas descontroladas durante tendencias prolongadas.
- La estrategia se basa en velas cerradas; elija un período de tiempo que refleje el ritmo comercial deseado (el EA original usa M30
y combinaciones H1, pero las velas H1 predeterminadas funcionan bien).
- Debido a que no se implementa la cobertura después de la quinta capa, considere reducir
MaxOrders si necesita el original exacto
comportamiento.
Archivos
CS/WavePowerEAStrategy.cs – StockSharp implementación de la lógica de red Wave Power EA.
README.md / README_ru.md / README_zh.md – documentación en inglés, ruso y chino.
La versión de Python se omite intencionalmente según los requisitos de la tarea.
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex
class wave_power_ea_strategy(Strategy):
def __init__(self):
super(wave_power_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 12) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._grid_step_percent = self.Param("GridStepPercent", 0.5) \
.SetDisplay("Grid Step %", "Price move % to add to position", "Grid")
self._max_grid_orders = self.Param("MaxGridOrders", 5) \
.SetDisplay("Max Grid Orders", "Maximum averaging orders", "Grid")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._grid_count = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def GridStepPercent(self):
return self._grid_step_percent.Value
@property
def MaxGridOrders(self):
return self._max_grid_orders.Value
def OnStarted2(self, time):
super(wave_power_ea_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._grid_count = 0
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self.FastPeriod
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self.SlowPeriod
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._fast_ema, self._slow_ema, self._rsi, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_val, slow_val, rsi_val):
if candle.State != CandleStates.Finished:
return
fv = float(fast_val)
sv = float(slow_val)
rv = float(rsi_val)
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fv
self._prev_slow = sv
return
close = float(candle.ClosePrice)
bullish_cross = self._prev_fast <= self._prev_slow and fv > sv
bearish_cross = self._prev_fast >= self._prev_slow and fv < sv
# Exit on opposite cross
if self.Position > 0 and bearish_cross:
self.SellMarket()
self._grid_count = 0
self._entry_price = 0.0
elif self.Position < 0 and bullish_cross:
self.BuyMarket()
self._grid_count = 0
self._entry_price = 0.0
# Grid averaging: add to position if price moved against us
grid_step = float(self.GridStepPercent)
max_grid = self.MaxGridOrders
if self.Position > 0 and self._entry_price > 0 and self._grid_count < max_grid:
drop_percent = (self._entry_price - close) / self._entry_price * 100.0
if drop_percent >= grid_step * (self._grid_count + 1):
self.BuyMarket()
self._grid_count += 1
elif self.Position < 0 and self._entry_price > 0 and self._grid_count < max_grid:
rise_percent = (close - self._entry_price) / self._entry_price * 100.0
if rise_percent >= grid_step * (self._grid_count + 1):
self.SellMarket()
self._grid_count += 1
# New entry
if self.Position == 0:
if bullish_cross and rv > 50:
self._entry_price = close
self._grid_count = 0
self.BuyMarket()
elif bearish_cross and rv < 50:
self._entry_price = close
self._grid_count = 0
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def OnReseted(self):
super(wave_power_ea_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._grid_count = 0
def CreateClone(self):
return wave_power_ea_strategy()