Открыть на GitHub

Стратегия Martingale Smart

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

Martingale Smart — конвертированная версия одноимённого эксперта MetaTrader. Стратегия всегда удерживает только одну позицию и после каждого убыточного цикла переключается между двумя наборами условий входа:

  1. Основной фильтр — пересечение двух простых скользящих средних с подтверждением направлением MACD на старшем таймфрейме. Это режим по умолчанию.
  2. Альтернативный фильтр — канал из скользящей средней и её отклонений (envelope). При отрицательном результате предыдущего цикла стратегия переключается на этот фильтр. Следующая убыточная сделка возвращает режим к основному фильтру.

Мартингейл увеличивает объём следующей сделки после убытка: можно умножить прошлый объём или добавить фиксированное приращение.

Подписки на данные

  • CandleType — таймфрейм, на котором ведутся расчёты и контроль позиции.
  • MacdTimeFrame — отдельный таймфрейм для фильтра MACD. По умолчанию это 30 дней, что соответствует месячному графику PERIOD_MN1 в исходном советнике.

Обе подписки запускаются в методе OnStarted автоматически.

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

  1. Входы рассматриваются только при отсутствии открытой позиции и после формирования всех индикаторов.
  2. Основной фильтр покупает, когда быстрая SMA находится ниже медленной и линия MACD выше сигнальной (для продаж условия зеркальны). Логика повторяет оригинальные вызовы iMA и iMACD со сдвигом на один бар.
  3. Альтернативный фильтр использует envelope: закрытие выше нижней границы даёт сигнал на покупку, ниже верхней — на продажу.
  4. После убыточного цикла стратегия меняет фильтр и рассчитывает новый объём с учётом мартингейла. При прибыльном завершении фильтр не меняется, а объём сбрасывается к начальному значению.
  5. Сразу после входа выставляются стоп-лосс и тейк-профит, заданные в пунктах.

Управление рисками

  • Перевод в безубыток — когда плавающая прибыль достигает BreakEvenTriggerPips, стоп переносится на цену входа с учётом сдвига BreakEvenOffsetPips.
  • Классический трейлинг-стоп — поддерживает стоп на расстоянии TrailingStopPips от последнего закрытия.
  • Тейк-профит по деньгам — закрывает позицию, если плавающая прибыль превышает MoneyTakeProfit.
  • Тейк-профит по проценту — аналогичный порог, выраженный как процент от текущей стоимости портфеля (PercentTakeProfit).
  • Денежный трейлинг — активируется при достижении MoneyTrailingTarget, далее отслеживает максимум прибыли и закрывает позицию при просадке больше MoneyTrailingDrawdown.

Все денежные расчёты используют PriceStep и StepPrice. Если провайдер не сообщает эти параметры, применяется запасной расчёт «разница цен × объём».

Параметры

Параметр Описание
UseMoneyTakeProfit Включить фиксированный денежный тейк-профит.
MoneyTakeProfit Порог плавающей прибыли в валюте счёта.
UsePercentTakeProfit Включить процентный тейк-профит.
PercentTakeProfit Порог прибыли в процентах от стоимости портфеля.
EnableMoneyTrailing Включить денежный трейлинг-стоп.
MoneyTrailingTarget Уровень прибыли, с которого включается трейлинг.
MoneyTrailingDrawdown Допустимая просадка прибыли после включения трейлинга.
UseBreakEven Переносить стоп в безубыток после достижения цели.
BreakEvenTriggerPips Дистанция в пунктах для активации безубытка.
BreakEvenOffsetPips Дополнительные пункты при переносе стопа.
MartingaleMultiplier Множитель объёма после убыточного цикла.
InitialVolume Начальный объём первой сделки цикла.
UseDoubleVolume Умножать объём (иначе используется LotIncrement).
LotIncrement Фиксированное увеличение объёма без умножения.
TrailingStopPips Дистанция классического трейлинга в пунктах.
StopLossPips Первичный стоп-лосс в пунктах.
TakeProfitPips Первичный тейк-профит в пунктах.
FastMaPeriod Период быстрой скользящей средней.
SlowMaPeriod Период медленной скользящей средней.
EnvelopePeriod Период SMA для envelope.
EnvelopeDeviation Ширина envelope в процентах.
MacdFastLength Быстрая EMA MACD.
MacdSlowLength Медленная EMA MACD.
MacdSignalLength Период сигнальной линии MACD.
CandleType Основной таймфрейм сигналов.
MacdTimeFrame Таймфрейм для MACD.

Практические замечания

  1. Мартингейл применяется только после полного закрытия убыточной позиции.
  2. Стратегия работает с одним нетто-позиционированием: при смене направления старая позиция полностью закрывается.
  3. Для корректных денежных расчётов необходимо задать в инструменте PriceStep, StepPrice и VolumeStep.
  4. Безубыток и трейлинг пересчитываются по закрытым свечам выбранного таймфрейма, внутридневные пики игнорируются.

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

  • Используется высокоуровневый API StockSharp (SubscribeCandles + Bind) и стандартный индикатор MovingAverageConvergenceDivergenceSignal вместо прямых вызовов iMACD.
  • Исключены брокерские проверки (freeze-level, отправка писем, обход тикетов), так как StockSharp управляет ими автоматически.
  • Денежные фильтры рассчитываются по совокупной позиции, что соответствует модели портфеля StockSharp.
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Smart Martingale strategy: MACD + MA filter with martingale volume on loss.
/// Buys when fast MA crosses above slow MA. Sells on cross below.
/// </summary>
public class MartingaleSmartStrategy : 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 MartingaleSmartStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA", "Fast SMA period", "Indicators");

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

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

		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { 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);
		}
	}
}