Ver en GitHub

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

  1. 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.
  2. 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.

  3. 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.

  4. 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.

  5. 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

  1. Adjunte la estrategia a un valor con un paso de precio configurado para que la conversión de pips funcione correctamente.
  2. Ajuste GridStepPips, Multiplier y MaxOrders según la volatilidad del instrumento y la política de margen del corredor.
  3. Habilite los bloques de protección cuando ejecute una cuenta real para evitar pérdidas descontroladas durante tendencias prolongadas.
  4. 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).
  5. 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;
	}
}