Открыть на GitHub

Стратегия Martingale MA Breakout (ID 2861)

Общее описание

Стратегия Martingale MA Breakout — порт оригинального эксперта MetaTrader 5 Martingale.mq5. Алгоритм отслеживает, насколько далеко текущая цена уходит от скользящей средней старшего таймфрейма. Как только отклонение превышает заданное количество пунктов, стратегия открывает позицию в сторону движения и сопровождает её фиксированным стоп-лоссом, тейк-профитом и трейлинг-стопом. Размер позиции подстраивается по принципу мартингейла: после убыточной серии объём увеличивается, после прибыльной — уменьшается.

По умолчанию расчёты ведутся по 6-минутным свечам, однако сам терминал может работать на любом базовом таймфрейме. Все индикаторы используют выбранный тип свечей, а заявки отправляются рыночными ордерами.

Логика входов и выходов

  1. На каждой свече вычисляется значение скользящей средней с выбранным методом сглаживания, типом цены и сдвигом.
  2. Заданная дистанция в пунктах переводится в абсолютный ценовой шаг. При расчёте учитывается оригинальная особенность MQL: для инструментов с 3 или 5 знаками шаг умножается на 10.
  3. После закрытия свечи:
    • если цена закрытия находится выше сдвинутой скользящей средней более чем на DistanceFromMaPips пунктов и нет длинной позиции, отправляется рыночная покупка;
    • если цена закрытия расположена ниже сдвинутой скользящей средней больше чем на DistanceFromMaPips пунктов и нет короткой позиции, отправляется рыночная продажа.
  4. На каждой завершённой свече проверяются условия стоп-лосса и тейк-профита, а также обновляется трейлинг-стоп. При закрытии позиции метод ResetTradeState очищает все сохранённые уровни.

Управление капиталом

  • Параметр RiskPercent превращается в денежный риск через Portfolio.CurrentValue (или BeginValue, если сделок ещё не было). При наличии стоп-лосса риск делится на расстояние до стопа и множитель инструмента, что даёт оценку максимально допустимого объёма.
  • После расчёта по риску объём передаётся в ApplyMartingale: если сохранённый баланс после прошлой сделки оказался выше текущего, объём увеличивается на 1 лот; если ниже — уменьшается на 1 лот, но никогда не опускается ниже базового объёма стратегии.
  • Трейлинг-стоп повторяет логику оригинального советника: когда цена проходит расстояние TrailingStopPips + TrailingStepPips в прибыльную сторону, стоп подтягивается на значение TrailingStopPips. Стратегия дополнительно проверяет, что при включённом трейлинге TrailingStepPips не равен нулю, и при нарушении условий прерывает запуск.

Параметры

Параметр Описание
StopLossPips Стоп-лосс в пунктах. Ноль отключает стоп и риск-менеджмент.
TakeProfitPips Тейк-профит в пунктах. Ноль отключает цель.
TrailingStopPips Отступ трейлинг-стопа в пунктах. Используется вместе с TrailingStepPips.
TrailingStepPips Дополнительное движение цены перед переносом трейлинг-стопа. Не может быть нулём при активном трейлинге.
DistanceFromMaPips Минимальное отклонение от сдвинутой скользящей средней для открытия позиции.
CandleType Тип свечей для расчётов (по умолчанию 6-минутные).
MaPeriod Период скользящей средней.
MaShift Сдвиг скользящей средней в барах; реализован через буфер последних значений.
MaMethod Метод сглаживания: Simple, Exponential, Smoothed, Weighted.
MaAppliedPrice Тип цены свечи для расчёта скользящей средней (close, open, high, low, median, typical, weighted).
RiskPercent Процент текущего капитала, выделенный под риск стоп-лосса.

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

  • Стратегия работает только по закрытым свечам, что воспроизводит обработку «по новому бару» из MQL. При смене направления BuyMarket/SellMarket автоматически переворачивают позицию, добавляя абсолютный объём противоположной стороны.
  • Стопы и тейки моделируются в коде: контроль осуществляется по цене закрытия, поскольку в высокоуровневом API нет прямого доступа к тикам.
  • Мартингейл использует слепок баланса, сделанный сразу после открытия предыдущей сделки, как и в оригинальном советнике.
  • Если инструмент не содержит валидного шага цены или мультипликатора, используются значения по умолчанию 0.0001 и 1 для предотвращения деления на ноль.

Отличия от оригинального советника

  • В MQL применялись bid/ask котировки; в портированной версии используется цена закрытия свечи, так как тиковые данные недоступны в высокоуровневом API.
  • Расчёт объёма опирается на капитал портфеля и множитель инструмента вместо класса CMoneyFixedMargin.
  • Графическое отображение ограничено свечами; дополнительные индикаторы не добавляются автоматически.
  • Проверка TrailingStepPips > 0 выполняется при запуске и выбрасывает исключение, заменяя всплывающее предупреждение Alert.
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// Martingale MA Breakout strategy (simplified).
/// Enters long when price crosses above EMA, enters short when below.
/// Uses simple position flipping with market orders.
/// </summary>
public class MartingaleMaBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<int> _atrPeriod;

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

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public int AtrPeriod
	{
		get => _atrPeriod.Value;
		set => _atrPeriod.Value = value;
	}

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

		_maPeriod = Param(nameof(MaPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Moving average period", "Indicators");

		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period for volatility filter", "Indicators");
	}

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

		var ema = new ExponentialMovingAverage { Length = MaPeriod };
		var atr = new AverageTrueRange { Length = AtrPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, atr, (ICandleMessage candle, decimal emaValue, decimal atrValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var distance = Math.Abs(candle.ClosePrice - emaValue);

				// Buy when price breaks above MA by at least half ATR
				if (candle.ClosePrice > emaValue && distance > atrValue && Position <= 0)
				{
					BuyMarket();
				}
				// Sell when price breaks below MA by at least half ATR
				else if (candle.ClosePrice < emaValue && distance > atrValue && Position >= 0)
				{
					SellMarket();
				}
			})
			.Start();

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