Открыть на GitHub

Стратегия PA Oscillator

Стратегия является портом эксперта MQL5 Exp_PA_Oscillator.mq5. Она использует две экспоненциальные скользящие средние (EMA) по цене закрытия свечей и анализирует производную разницы между ними.

Логика

  1. Рассчитываются быстрая и медленная EMA.
  2. Вычисляется разница между ними и её изменение относительно предыдущего значения.
  3. На основании производной определяется цветовой код:
    • 0 – производная положительная, MACD растёт.
    • 1 – производная равна нулю.
    • 2 – производная отрицательная, MACD падает.
  4. По двум последним закрытым свечам формируются сигналы:
    • Две свечи назад цвет был 0, а последняя свеча имеет другой цвет → открытие длинной позиции и закрытие короткой.
    • Две свечи назад цвет был 2, а последняя свеча имеет другой цвет → открытие короткой позиции и закрытие длинной.

Параметры

Имя Описание
FastLength Период быстрой EMA.
SlowLength Период медленной EMA.
BuyPosOpen Разрешить открытие длинных позиций.
SellPosOpen Разрешить открытие коротких позиций.
BuyPosClose Разрешить закрытие длинных позиций.
SellPosClose Разрешить закрытие коротких позиций.
CandleType Таймфрейм свечей для расчётов.

Примечания

  • Обрабатываются только завершённые свечи.
  • Для входа и выхода используются рыночные заявки.
  • Реализация предназначена для демонстрационных целей, а не для гарантированной прибыльности.
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;
	}
}