Открыть на GitHub

MultiMartinStrategy

Обзор

MultiMartinStrategy — это порт советника MultiMartin с платформы MQL5 на StockSharp. Оригинальная система работает по принципу реверсной торговли с наращиванием объёма по мартингейлу на нескольких инструментах. Перенос сохраняет ключевую логику управления капиталом и использует высокоуровневый API StockSharp для отправки заявок, контроля позиций, опционального трейлинга и обработки отказов брокера.

Стратегия всегда держит не более одной позиции по выбранному инструменту. После закрытия позиции направление сохраняется, если сделка была прибыльной, или разворачивается, если сделка завершилась убытком. Убыточные сделки запускают шаг мартингейла, увеличивая объём следующего ордера до заданного предела.

Логика работы

  1. Выбор входа
    • Торговля разрешена только внутри заданного временного окна. В остальное время новые сделки не открываются.
    • Когда позиция равна нулю и нет активного периода блокировки, стратегия отправляет рыночную заявку в текущую сторону. Первое направление задаётся пользователем (покупка или продажа).
  2. Мартингейл
    • После каждой убыточной сделки объём следующего ордера умножается на коэффициент Factor.
    • Количество последовательных увеличений ограничивается параметром Limit. Если потолок превышен, объём возвращается к базовому Volume.
    • Прибыльные сделки всегда сбрасывают объём и сохраняют текущее направление.
  3. Выход из позиции
    • Стоп-лосс и тейк-профит задаются в пунктах и переводятся в абсолютное расстояние с учётом PriceStep инструмента.
    • Доступны два режима трейлинга: перевод стопа в безубыток и прямолинейное сопровождение цены.
    • Как только экстремумы свечи достигают стопа или цели, стратегия закрывает позицию рыночной заявкой.
  4. Отказы брокера
    • При отказе в исполнении рыночного ордера включается пауза, длительность которой задаётся SkipBadTime. Опция Forever полностью блокирует дальнейшие входы до окончания работы стратегии.

Параметры

Параметр Описание
UseTimeFilter Включить или отключить внутридневной фильтр времени.
HourStart Час (0-23), начиная с которого разрешена торговля.
HourEnd Час (1-24), после которого торговля запрещена. Поддерживаются ночные окна.
Volume Базовый объём сделки (лоты или контракты).
Factor Множитель объёма после убыточной сделки.
Limit Максимальное число последовательных увеличений объёма перед сбросом.
StopLossPoints Дистанция стоп-лосса в пунктах. Значение 0 отключает стоп.
TakeProfitPoints Дистанция тейк-профита в пунктах. Значение 0 отключает цель.
StartDirection Направление первой сделки (Buy или Sell).
SkipBadTime Интервал блокировки после отказа брокера. Forever выключает дальнейшие входы.
TrailMode Режим трейлинга: None, Breakeven или Straight.
CandleType Тип свечей, используемый для контроля выхода и фильтра времени.

Отличия от MQL5-версии

  • Один экземпляр стратегии работает только с одним инструментом. Для мульти-символьной торговли запустите несколько копий.
  • Управление стопами и целями реализовано на уровне стратегии: при касании диапазоном свечи выставляется рыночный приказ на закрытие.
  • Пауза после отказа реализована через обработчик OnOrderFailed, аналогично логике исходного советника.
  • Трейлинг реализован средствами StockSharp, без прямого изменения активных заявок.

Рекомендации по использованию

  • Перед запуском задайте Security и Portfolio.
  • Убедитесь, что параметр Volume соответствует минимальному шагу и правилам объёма для инструмента.
  • Значение 0 в StopLossPoints или TakeProfitPoints отключает соответствующую защиту.
  • Для корректного бэктеста выбирайте CandleType, совпадающий с таймфреймом истории (например, минутные свечи для форекс-пар).
  • Для имитации мульти-символьной версии запускайте несколько экземпляров стратегии с разными параметрами.

Предупреждение о рисках

Мартингейл предполагает экспоненциальный рост объёма при серии убытков и может быстро исчерпать маржу. Используйте консервативные настройки, тщательно тестируйте стратегию на истории и применяйте дополнительные механизмы риск-менеджмента в реальной торговле.

namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Multi Martin reversal strategy: alternates long/short based on EMA crossover.
/// Buys when EMA fast crosses above slow, sells on cross below.
/// </summary>
public class MultiMartinStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	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 MultiMartinStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

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

		_slowPeriod = Param(nameof(SlowPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		decimal? prevFast = null;
		decimal? prevSlow = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, fastVal, slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevFast.HasValue && prevSlow.HasValue)
				{
					if (prevFast.Value <= prevSlow.Value && fastVal > slowVal && Position <= 0)
						BuyMarket();
					else if (prevFast.Value >= prevSlow.Value && fastVal < slowVal && Position >= 0)
						SellMarket();
				}

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

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