Открыть на GitHub

Martingale VI Hybrid (C#)

Обзор

Martingale VI Hybrid — это перенос одноимённого советника MetaTrader на платформу StockSharp с использованием высокоуровневого API. Стратегия сочетает фильтр из быстрой и медленной SMA с подтверждением по MACD и реализует наращивание позиции по схеме мартингейла. При движении цены против последней точки входа на фиксированное количество пунктов открывается новая сделка, а общий тейк‑профит переносится на уровень, заданный последним ордером. Для выхода предусмотрены цели в деньгах, процентах от стартового капитала и денежный трейлинг‑стоп.

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

  1. Фильтр сигнала — используется состояние быстрых и медленных SMA и MACD на предыдущей свече. Длинный цикл стартует, если быстрая SMA была выше медленной, а основная линия MACD — ниже сигнальной. Короткий цикл запускается при обратных условиях.
  2. Первый вход — при появлении сигнала и отсутствии позиции выставляется рыночный ордер объёмом Initial Volume.
  3. Мартингейл — пока позиция открыта, отслеживается последняя цена входа. Как только цена проходит против позиции Pip Step пунктов, добавляется новый ордер объёмом предыдущий ордер × Volume Multiplier. Общее число ордеров ограничено параметром Max Trades; при достижении лимита и активной опции Close Max Orders вся позиция закрывается.
  4. Общий тейк‑профит — каждый новый ордер пересчитывает цель по прибыли на уровне цена входа ± Take Profit (pips). Когда максимум (для лонга) или минимум (для шорта) свечи достигает этого уровня, закрываются все сделки.
  5. Глобальные выходы
    • при включённом Use Money TP позиция закрывается, как только прибыль достигает Money TP;
    • при активном Use Percent TP закрытие происходит, когда прибыль соответствует Percent TP процентов от стартовой стоимости портфеля;
    • если включён Enable Trailing, после достижения Trailing Activation запускается денежный трейлинг, который закрывает позицию при просадке прибыли на Trailing Drawdown.

Параметры

Параметр Описание
Candle Type Основной таймфрейм свечей для расчёта индикаторов.
Fast MA, Slow MA Периоды быстрых и медленных SMA, формирующих трендовый фильтр.
MACD Fast, MACD Slow, MACD Signal Настройки MACD, использующегося для подтверждения направления.
Initial Volume Объём первого ордера в серии.
Volume Multiplier Множитель объёма для каждого последующего ордера.
Max Trades Максимальное количество одновременных ордеров в цепочке.
Take Profit (pips) Дистанция тейк‑профита; последний ордер задаёт общую цель.
Pip Step Сколько пунктов против позиции должно пройти цена, чтобы добавить следующий ордер.
Use Money TP, Money TP Включение и значение денежной цели по прибыли.
Use Percent TP, Percent TP Включение и значение цели в процентах от начального капитала.
Enable Trailing, Trailing Activation, Trailing Drawdown Настройки денежного трейлинг‑стопа.
Close Max Orders При включении вся позиция закрывается при достижении лимита ордеров.

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

  • Цели в абсолютных значениях и процентах позволяют фиксировать прибыль в зависимости от сценария торговли.
  • Денежный трейлинг защищает накопленную прибыль после успешной серии сделок.
  • Max Trades предотвращает бесконтрольный рост позиции, а Close Max Orders обеспечивает аварийный выход при достижении лимита.

Технические детали

  • Стратегия подписывается на свечи через высокоуровневый метод SubscribeCandles; MACD подключается через BindEx, SMA рассчитываются внутри обработчика.
  • Размер пункта вычисляется из Security.PriceStep, что позволяет корректно работать с инструментами с пятью и тремя знаками после запятой.
  • Расчёт плавающей прибыли основан на Security.PriceStep, Security.StepPrice и PositionAvgPrice, поэтому инструмент должен предоставлять эти значения.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Martingale VI Hybrid strategy (simplified).
/// Uses SMA crossover for entries.
/// </summary>
public class MartingaleViHybridStrategy : 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 MartingaleViHybridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

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

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

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

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

		decimal prevFast = 0, prevSlow = 0;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					return;
				}

				if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
					BuyMarket();
				else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
					SellMarket();

				prevFast = fastValue;
				prevSlow = slowValue;
			})
			.Start();

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