Открыть на GitHub

Стратегия Two MA Four Level Bands

Обзор

Стратегия повторяет советник MetaTrader ytg_2MA_4Level. Она сравнивает быструю и медленную скользящие средние и открывает сделки, когда быстрая линия пересекает медленную напрямую либо в пределах четырёх настраиваемых ценовых коридоров. Позиции защищаются симметричными стоп-лоссом и тейк-профитом, заданными в пунктах, как и в оригинальном роботе.

Логика сигналов

  1. На выбранной серии свечей рассчитываются две скользящие средние. Для каждой можно задать метод усреднения (SMA, EMA, SMMA, LWMA) и тип цены.
  2. После закрытия каждой свечи стратегия берёт значения индикаторов CalculationBar баров назад (по умолчанию 1) и ещё на один бар дальше. Это полностью копирует вызов iMA(..., shift) в MetaTrader и не допускает сигналов на незакрытых свечах.
  3. Покупка возникает, когда быстрая средняя пересекает медленную сверху вниз, либо когда пересечение происходит относительно медленной средней, сдвинутой на UpperLevel1, UpperLevel2, LowerLevel1 или LowerLevel2 пунктов.
  4. Продажа использует зеркальные условия: быстрая средняя пересекает медленную сверху вниз с учётом тех же четырёх уровней допуска.
  5. Сделки открываются только при нулевой позиции и отсутствии активных заявок, что повторяет одноордерную логику MQL-советника.

Параметры

Имя Тип Значение по умолчанию Описание
TakeProfitPips int 130 Дистанция тейк-профита в пунктах. Значение 0 отключает цель.
StopLossPips int 1000 Дистанция стоп-лосса в пунктах. Значение 0 отключает защитный стоп.
TradeVolume decimal 1 Базовый лот, автоматически приводимый к шагу объёма инструмента.
CalculationBar int 1 Количество баров, на которое смещается точка сравнения средних (аналог параметра shift).
FastPeriod / SlowPeriod int 14 / 180 Периоды быстрой и медленной скользящих средних.
FastMethod / SlowMethod MovingAverageMethod Smoothed Метод усреднения: Simple, Exponential, Smoothed или LinearWeighted.
FastPrice / SlowPrice CandlePrice Median Тип цены, используемый при расчёте каждой средней.
UpperLevel1 / UpperLevel2 int 500 / 250 Положительные смещения (в пунктах), добавляемые к медленной средней для расширения условий входа.
LowerLevel1 / LowerLevel2 int 500 / 250 Отрицательные смещения (в пунктах), вычитаемые из медленной средней.
CandleType DataType таймфрейм 15m Свечная серия, на которой работают индикаторы.

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

  • Стопы и тейки задаются через StartProtection, расстояния переводятся из пунктов в денежные единицы по PriceStep. Для пятизнаков применяется привычный метатрейдеровский множитель *10.
  • Внутренние очереди хранят только минимальный набор значений для эмуляции параметра shift и не накапливают полную историю свечей.
  • Заявки отправляются методами BuyMarket / SellMarket, объём предварительно нормализуется под шаг и ограничения инструмента, чтобы интерфейс показывал фактический лот.
  • На график выводятся свечи, обе средние и сделки, что облегчает визуальный контроль за стратегией.
  • Все комментарии в коде оставлены на английском языке в соответствии с требованиями проекта.

Рекомендации по применению

  • Выбирайте тот же таймфрейм, что и в MetaTrader; значение по умолчанию 15 минут можно изменить через параметр CandleType.
  • Уменьшайте уровни UpperLevel/LowerLevel, чтобы стратегия реагировала только на «чистые» пересечения, или увеличивайте их, чтобы учитывать движения рядом с основной средней.
  • При CalculationBar = 0 сигналы формируются по последней закрытой свече; большие значения добавляют запаздывание и фильтруют шум.
  • При необходимости внешнего управления выходами установите StopLossPips = 0 и TakeProfitPips = 0, чтобы отказаться от автоматической защиты.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Two MA with four level bands: trades when fast MA crosses slow MA
/// or its offset bands. Exits on opposite crossover.
/// </summary>
public class TwoMaFourLevelBandsStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _bandMultiplier;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public TwoMaFourLevelBandsStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastPeriod = Param(nameof(FastPeriod), 14)
			.SetDisplay("Fast MA", "Fast EMA period.", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 180)
			.SetDisplay("Slow MA", "Slow SMA period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR for band calculation.", "Indicators");

		_bandMultiplier = Param(nameof(BandMultiplier), 1.5m)
			.SetDisplay("Band Mult", "ATR multiplier for offset bands.", "Bands");
	}

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public decimal BandMultiplier
	{
		get => _bandMultiplier.Value;
		set => _bandMultiplier.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, atr, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevSlow == 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var bandOffset = atrVal * BandMultiplier;

		// Check crossovers at multiple band levels
		var bullish = false;
		var bearish = false;

		// Main line cross
		if (_prevFast <= _prevSlow && fastVal > slowVal) bullish = true;
		if (_prevFast >= _prevSlow && fastVal < slowVal) bearish = true;

		// Upper band cross
		if (_prevFast <= _prevSlow + bandOffset && fastVal > slowVal + bandOffset) bullish = true;
		if (_prevFast >= _prevSlow + bandOffset && fastVal < slowVal + bandOffset) bearish = true;

		// Lower band cross
		if (_prevFast <= _prevSlow - bandOffset && fastVal > slowVal - bandOffset) bullish = true;
		if (_prevFast >= _prevSlow - bandOffset && fastVal < slowVal - bandOffset) bearish = true;

		// Upper band 2
		if (_prevFast <= _prevSlow + bandOffset * 2 && fastVal > slowVal + bandOffset * 2) bullish = true;
		if (_prevFast >= _prevSlow + bandOffset * 2 && fastVal < slowVal + bandOffset * 2) bearish = true;

		// Lower band 2
		if (_prevFast <= _prevSlow - bandOffset * 2 && fastVal > slowVal - bandOffset * 2) bullish = true;
		if (_prevFast >= _prevSlow - bandOffset * 2 && fastVal < slowVal - bandOffset * 2) bearish = true;

		// Exit
		if (Position > 0 && bearish)
		{
			SellMarket();
			_entryPrice = 0;
		}
		else if (Position < 0 && bullish)
		{
			BuyMarket();
			_entryPrice = 0;
		}

		// Entry
		if (Position == 0)
		{
			if (bullish)
			{
				_entryPrice = candle.ClosePrice;
				BuyMarket();
			}
			else if (bearish)
			{
				_entryPrice = candle.ClosePrice;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}