Ver en GitHub

Estrategia del Oscilador de Olas de Elliott

Esta estrategia aplica el Oscilador de Olas de Elliott (EWO) sobre los cierres de velas. El EWO se calcula como la diferencia entre una Media Móvil Simple rápida y una lenta (5 y 35 períodos por defecto). La lógica de trading busca puntos de giro en el oscilador para capturar posibles reversiones de tendencia.

Se abre una posición larga cuando el oscilador forma un mínimo local y comienza a subir. Se abre una posición corta cuando el oscilador forma un máximo local y comienza a caer. Las posiciones existentes se invierten en consecuencia. Se admiten take‑profit y stop‑loss basados en porcentaje opcionales a través de StartProtection.

Detalles

  • Indicador: Oscilador de Olas de Elliott = SMA(rápida) − SMA(lenta).
  • Criterios de entrada:
    • Largo: el valor del oscilador estaba bajando y luego gira hacia arriba.
    • Corto: el valor del oscilador estaba subiendo y luego gira hacia abajo.
  • Largo/Corto: Ambos.
  • Criterios de salida: La posición se invierte ante la señal opuesta o sale por stop o take‑profit.
  • Stops: Stop‑loss y take‑profit en porcentaje.
  • Filtros: Ninguno.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Elliott Wave Oscillator based strategy.
/// Buys when the oscillator turns upward.
/// Sells when the oscillator turns downward.
/// </summary>
public class ElliottWaveOscillatorStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<decimal> _takeProfitPct;
	private readonly StrategyParam<decimal> _stopLossPct;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEwo;
	private decimal _prevPrevEwo;
	private bool _isFirstValue;

	/// <summary>
	/// Fast moving average length.
	/// </summary>
	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	/// <summary>
	/// Slow moving average length.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	/// <summary>
	/// Take profit percentage.
	/// </summary>
	public decimal TakeProfitPct
	{
		get => _takeProfitPct.Value;
		set => _takeProfitPct.Value = value;
	}

	/// <summary>
	/// Stop loss percentage.
	/// </summary>
	public decimal StopLossPct
	{
		get => _stopLossPct.Value;
		set => _stopLossPct.Value = value;
	}

	/// <summary>
	/// Candle type to use.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public ElliottWaveOscillatorStrategy()
	{
		_fastLength = Param(nameof(FastLength), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast Length", "Length of the fast SMA", "Indicator")
			;

		_slowLength = Param(nameof(SlowLength), 35)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Length of the slow SMA", "Indicator")
			;

		_takeProfitPct = Param(nameof(TakeProfitPct), 1m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit %", "Percentage take profit", "Risk")
			;

		_stopLossPct = Param(nameof(StopLossPct), 1m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss %", "Percentage stop loss", "Risk")
			;

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevEwo = 0m;
		_prevPrevEwo = 0m;
		_isFirstValue = true;
	}

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

		var fastMa = new ExponentialMovingAverage { Length = FastLength };
		var slowMa = new ExponentialMovingAverage { Length = SlowLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastMa, slowMa, ProcessCandle)
			.Start();

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

		StartProtection(new Unit(TakeProfitPct / 100m, UnitTypes.Percent), new Unit(StopLossPct / 100m, UnitTypes.Percent));
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var ewoValue = fastValue - slowValue;

		if (_isFirstValue)
		{
			_prevEwo = ewoValue;
			_prevPrevEwo = ewoValue;
			_isFirstValue = false;
			return;
		}

		if (_prevEwo < _prevPrevEwo && ewoValue > _prevEwo)
		{
			// Oscillator turns upward - open long
			if (Position <= 0)
				BuyMarket();
		}
		else if (_prevEwo > _prevPrevEwo && ewoValue < _prevEwo)
		{
			// Oscillator turns downward - open short
			if (Position >= 0)
				SellMarket();
		}

		_prevPrevEwo = _prevEwo;
		_prevEwo = ewoValue;
	}
}