Открыть на GitHub

Стратегия Sidus Alligator

Обзор

Стратегия Sidus переносит логику классического эксперта MetaTrader «Sidus» в инфраструктуру StockSharp. В основе лежит комбинация индикатора Аллигатор Билла Вильямса и RSI с периодом 14. Система отслеживает пересечение RSI уровня 50 вверх или вниз, сопровождаемое одновременным расширением трёх линий Аллигатора в ту же сторону. После появления сигнала мгновенно рассчитываются защитные уровни и при необходимости включается трейлинг-стоп в пипсах, скорректированных под шаг цены выбранного инструмента.

Индикаторы и данные

  • Аллигатор: три сглаженные средние по медианной цене свечи (high + low ÷ 2). Длины и сдвиги для челюсти, зубов и губ настраиваются отдельно. Для фильтрации используются разности между двумя предыдущими сформированными значениями.
  • RSI: осциллятор с периодом 14 по ценам закрытия. В расчёт входят только завершённые свечи, что исключает заглядывание вперёд.
  • Свечи: тип данных выбирается параметром CandleType. По умолчанию используется минутный таймфрейм.

Логика торговли

  1. Подтверждение RSI
    • Лонг: RSI[t-2] < 50 и RSI[t-1] > 50, то есть индикатор пробивает середину диапазона вверх.
    • Шорт: RSI[t-2] > 50 и RSI[t-1] < 50, что означает нисходящее пересечение уровня 50.
  2. Фильтр по наклонам Аллигатора
    • Для покупки разности между последними двумя значениями каждой линии (с учётом сдвигов) должны превышать порог Delta.
    • Для продажи те же разности должны быть меньше Delta, указывая на сжатие или разворот вниз.
  3. Управление позицией
    • При появлении сигнала на покупку короткая позиция закрывается, если CloseOpposite = true, после чего выставляется рыночная заявка на объём OrderVolume.
    • При сигнале на продажу длинная позиция при необходимости закрывается и открывается шорт тем же объёмом.

Выходы и управление рисками

  • Начальный стоп: рассчитывается от минимума (для лонга) или максимума (для шорта) предыдущей свечи с учётом OffsetPips. Если расстояние некорректно (например, стоп не ниже цены покупки), сделка пропускается.
  • Тейк-профит: задаётся параметром TakeProfitPips. Нулевое значение отключает цель.
  • Трейлинг-стоп: активируется, когда цена проходит в прибыльном направлении не менее TrailingStopPips + TrailingStepPips. Новый уровень ставится на расстоянии TrailingStopPips от максимума (для лонга) или минимума (для шорта), достигнутого внутри свечи.
  • Контроль выхода: срабатывания стопа, тейк-профита и трейлинга проверяются на каждой завершённой свече с учётом экстремумов бара.

Параметры

  • OrderVolume (по умолчанию 0.1) — торговый объём в лотах или контрактах.
  • OffsetPips (3) — величина защитного стопа в пипсах от экстремума предыдущей свечи.
  • TakeProfitPips (75) — расстояние до тейк-профита; при нуле цель отключена.
  • TrailingStopPips (5) — базовое расстояние трейлинг-стопа.
  • TrailingStepPips (15) — дополнительный ход цены, после которого стоп подтягивается.
  • Delta (0.00003) — минимальное значение наклона каждой линии Аллигатора для допуска сигнала.
  • CloseOpposite (по умолчанию false) — при true противоположные позиции закрываются перед открытием новой сделки.
  • JawPeriod, TeethPeriod, LipsPeriod — периоды линий Аллигатора (13/8/5).
  • JawShift, TeethShift, LipsShift — сдвиги линий (8/5/3), учитываемые при сравнении наклонов.
  • RsiPeriod (14) — период RSI.
  • CandleType — тип/таймфрейм свечей.

Особенности реализации

  • Все расстояния в пипсах автоматически переводятся в денежные единицы с учётом шага цены инструмента. Для инструментов с 3 или 5 знаками после запятой шаг умножается на десять, что соответствует определению пипса в MetaTrader.
  • Для расчёта наклонов хранятся только необходимые значения индикаторов, что позволяет повторить логику эксперта без создания громоздких коллекций.
  • Сделки отправляются через высокоуровневые методы BuyMarket и SellMarket, поэтому стратегия концентрируется на генерации сигналов, а исполнение остаётся на стороне StockSharp.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Sidus Alligator strategy using triple EMA alignment.
/// </summary>
public class SidusAlligatorStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _jawPeriod;
	private readonly StrategyParam<int> _teethPeriod;
	private readonly StrategyParam<int> _lipsPeriod;

	private decimal? _prevLips;
	private decimal? _prevTeeth;

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

	public int JawPeriod
	{
		get => _jawPeriod.Value;
		set => _jawPeriod.Value = value;
	}

	public int TeethPeriod
	{
		get => _teethPeriod.Value;
		set => _teethPeriod.Value = value;
	}

	public int LipsPeriod
	{
		get => _lipsPeriod.Value;
		set => _lipsPeriod.Value = value;
	}

	public SidusAlligatorStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_jawPeriod = Param(nameof(JawPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Jaw Period", "Slow EMA (Jaw)", "Indicators");

		_teethPeriod = Param(nameof(TeethPeriod), 25)
			.SetGreaterThanZero()
			.SetDisplay("Teeth Period", "Medium EMA (Teeth)", "Indicators");

		_lipsPeriod = Param(nameof(LipsPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Lips Period", "Fast EMA (Lips)", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevLips = null;
		_prevTeeth = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevLips = null;
		_prevTeeth = null;

		var jaw = new ExponentialMovingAverage { Length = JawPeriod };
		var teeth = new ExponentialMovingAverage { Length = TeethPeriod };
		var lips = new ExponentialMovingAverage { Length = LipsPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(jaw, teeth, lips, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal jawVal, decimal teethVal, decimal lipsVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevLips = lipsVal;
			_prevTeeth = teethVal;
			return;
		}

		if (_prevLips == null || _prevTeeth == null)
		{
			_prevLips = lipsVal;
			_prevTeeth = teethVal;
			return;
		}

		// Lips crosses above teeth with alligator aligned (lips > teeth > jaw)
		if (_prevLips.Value <= _prevTeeth.Value && lipsVal > teethVal && lipsVal > jawVal)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		// Lips crosses below teeth with alligator aligned (lips < teeth < jaw)
		else if (_prevLips.Value >= _prevTeeth.Value && lipsVal < teethVal && lipsVal < jawVal)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}

		_prevLips = lipsVal;
		_prevTeeth = teethVal;
	}
}