Ver en GitHub

Estrategia PA Oscilador

Esta estrategia es un port del experto MQL5 Exp_PA_Oscillator.mq5. Aplica dos medias móviles exponenciales (EMAs) a los precios de cierre de las velas y analiza la derivada de su diferencia.

Lógica

  1. Calcular EMAs rápida y lenta.
  2. Calcular la diferencia entre ellas y rastrear su cambio respecto al valor anterior.
  3. Determinar un código de color para la derivada:
    • 0 – la derivada es positiva y el MACD está subiendo.
    • 1 – la derivada es cero.
    • 2 – la derivada es negativa y el MACD está bajando.
  4. Usar los colores de las dos últimas velas completadas para generar señales:
    • Hace dos barras el color era 0 y la barra anterior cambió desde 0 → abrir posición larga y cerrar posición corta.
    • Hace dos barras el color era 2 y la barra anterior cambió desde 2 → abrir posición corta y cerrar posición larga.

Parámetros

Nombre Descripción
FastLength Longitud del EMA rápido.
SlowLength Longitud del EMA lento.
BuyPosOpen Habilitar la apertura de posiciones largas.
SellPosOpen Habilitar la apertura de posiciones cortas.
BuyPosClose Habilitar el cierre de posiciones largas.
SellPosClose Habilitar el cierre de posiciones cortas.
CandleType Marco temporal de velas utilizado para los cálculos.

Notas

  • Solo se procesan velas completadas.
  • Se usan órdenes de mercado para entradas y salidas.
  • Esta implementación se centra en la claridad y los fines educativos, no en la rentabilidad.
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>
/// Strategy based on the PA Oscillator indicator.
/// It trades when the derivative of the difference between fast and slow EMAs changes sign.
/// </summary>
public class PaOscillatorStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevMacd;
	private int? _prevColor;
	private int? _prevPrevColor;

	/// <summary>
	/// Length of the fast EMA.
	/// </summary>
	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	/// <summary>
	/// Length of the slow EMA.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

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

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public PaOscillatorStrategy()
	{
		_fastLength = Param(nameof(FastLength), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA Length", "Fast EMA period", "Indicators");

		_slowLength = Param(nameof(SlowLength), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA Length", "Slow EMA period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for strategy", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevMacd = null;
		_prevColor = null;
		_prevPrevColor = null;
	}

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

		var fastEma = new ExponentialMovingAverage { Length = FastLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowLength };

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();

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

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

		var macd = fast - slow;

		if (_prevMacd is null)
		{
			_prevMacd = macd;
			_prevColor = 1;
			_prevPrevColor = 1;
			return;
		}

		var osc = macd - _prevMacd.Value;
		var color = osc > 0 ? 0 : osc < 0 ? 2 : 1;

		if (_prevPrevColor == 0 && _prevColor > 0)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (_prevPrevColor == 2 && _prevColor < 2)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}

		_prevMacd = macd;
		_prevPrevColor = _prevColor;
		_prevColor = color;
	}
}