Открыть на GitHub

Стратегия AO Lightning

Обзор

AO Lightning переносит советника MT5 «AO_Lightning» на высокоуровневый API StockSharp. Система отслеживает наклон осциллятора Awesome, рассчитанного по медианным ценам. Когда показатель снижается, стратегия наращивает длинную позицию, а при росте осциллятора выстраивает короткую пирамиду. Максимальное количество слоёв ограничено параметром, при смене направления противоположные позиции закрываются до открытия новых.

Торговая логика

  1. Подписаться на выбранные свечи и вычислить Awesome Oscillator с коротким периодом 5 и длинным периодом 34 (значения взяты из исходного MQL-кода).
  2. Обрабатывать только завершённые свечи, чтобы избежать повторных срабатываний.
  3. Значение AO первой завершённой свечи сохраняется как базовое для сравнения.
  4. Когда текущее значение AO меньше предыдущего:
    • При наличии открытой короткой позиции отправляется рыночная покупка, которая закрывает весь шорт и одновременно добавляет один длинный слой.
    • Если шорта нет и текущая длинная экспозиция меньше лимита, добавляется ещё один длинный слой.
  5. Когда текущее значение AO больше предыдущего:
    • При наличии длинной позиции выставляется рыночная продажа, закрывающая существующий лонг и сразу открывающая один короткий слой.
    • Если лонга нет и короткая экспозиция меньше лимита, добавляется новый короткий слой.
  6. Если значение AO не изменилось, позиция остаётся без изменений.
  7. Метод StartProtection() активируется один раз при запуске, чтобы в Designer можно было подключить стопы и другие защитные модули.

Логика полностью повторяет оригинальный советник: направление задаёт наклон AO, противоположные сделки закрываются до переворота, а позиции наращиваются слоями до установленного ограничения.

Управление позицией

  • TradeVolume определяет размер каждого дополнительного слоя и соответствует параметру MT5 LotFixed.
  • MaxPositions повторяет входной параметр MT5 Orders, ограничивая количество слоёв в каждом направлении.
  • Пирамидинг линейный: каждый сигнал добавляет ровно один слой указанного объёма, пока лимит не достигнут.
  • Переворот выполняется одним комбинированным ордером, который закрывает противоположную позицию и сразу открывает новый слой в нужную сторону.

Параметры

Имя Описание Значение по умолчанию
TradeVolume Объём ордера для каждого слоя. 1
MaxPositions Максимальное число длинных или коротких слоёв. 10
AoShortPeriod Длина быстрой SMA внутри Awesome Oscillator (по медианной цене). 5
AoLongPeriod Длина медленной SMA для Awesome Oscillator. 34
CandleType Тип свечей, используемый стратегией. Таймфрейм 5 минут

Примечания

  • В исходном советнике MT5 параметры названы Period_sma_slow и Period_sma_fast, но значения (5 и 34) перепутаны местами. В версии StockSharp использованы интуитивные AoShortPeriod и AoLongPeriod при сохранении поведения.
  • Python-реализация не создавалась, как и требовалось в задаче.
  • Тесты не включены; рекомендуется провести нужную проверку в Designer или собственной тестовой среде перед запуском на реальных торгах.
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// AO Lightning strategy.
/// Trades based on the Awesome Oscillator momentum slope direction.
/// Buys when AO is rising, sells when AO is falling.
/// </summary>
public class AoLightningStrategy : Strategy
{
	private readonly StrategyParam<int> _aoShortPeriod;
	private readonly StrategyParam<int> _aoLongPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevAo;
	private bool _initialized;

	public int AoShortPeriod
	{
		get => _aoShortPeriod.Value;
		set => _aoShortPeriod.Value = value;
	}

	public int AoLongPeriod
	{
		get => _aoLongPeriod.Value;
		set => _aoLongPeriod.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public AoLightningStrategy()
	{
		_aoShortPeriod = Param(nameof(AoShortPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("AO Fast", "Short SMA period for Awesome Oscillator", "Indicators");

		_aoLongPeriod = Param(nameof(AoLongPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("AO Slow", "Long SMA period for Awesome Oscillator", "Indicators");

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevAo = 0m;
		_initialized = false;
	}

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

		_prevAo = 0;
		_initialized = false;

		var ao = new AwesomeOscillator
		{
			ShortMa = { Length = AoShortPeriod },
			LongMa = { Length = AoLongPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ao, OnProcess)
			.Start();

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

	private void OnProcess(ICandleMessage candle, decimal aoValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (!_initialized)
		{
			_prevAo = aoValue;
			_initialized = true;
			return;
		}

		// Buy when AO is rising (bullish momentum)
		if (aoValue > _prevAo && Position <= 0)
		{
			BuyMarket();
		}
		// Sell when AO is falling (bearish momentum)
		else if (aoValue < _prevAo && Position >= 0)
		{
			SellMarket();
		}

		_prevAo = aoValue;
	}
}