Открыть на GitHub

Basic Martingale EA 3

Обзор

Basic Martingale EA 3 — это стратегия, перенесённая из MetaTrader 5. Она использует тройное экспоненциальное скользящее среднее (TEMA) для определения направления и строит сетку усредняющих сделок по значениям ATR. В версии для StockSharp сохранены исходные параметры риска, торговые часы и логика управления объёмом, при этом все настройки оформлены как параметры стратегии для удобной оптимизации.

Торговая логика

  1. Формирование сигнала. На каждой завершённой свече выбранного таймфрейма цена закрытия сравнивается со значением TEMA. Закрытие выше индикатора открывает корзину покупок, закрытие ниже — корзину продаж. Одновременно активен только один направленный набор позиций.
  2. Торговое окно. Новые корзины разрешены только между StartHour и EndHour по времени площадки. Если значения совпадают, торговля разрешена в течение суток. Параметр TradeAtNewBar ограничивает открытие корзины одним событием на свечу, что соответствует флажку «Торговать на новой свече» в MT5.
  3. Сетка усреднения. После открытия позиции стратегия отслеживает худшую/лучшую цену входа. Когда рынок смещается минимум на GridMultiplier × ATR, добавляется новая сделка в направлении, указанном параметром Averaging (усреднение против движения или по тренду). Количество сделок ограничено MaxAverageOrders, а объём рассчитывается по выбранному режиму мартингейла (Multiply или Increment).
  4. Защитные выходы. Необязательные уровни стоп-лосса и тейк-профита наследуются от первой сделки в корзине. Дополнительно реализован трейлинг: после TrailingStart пунктов прибыли стоп переносится на цена - TrailingStop (для продаж — цена + TrailingStop) и подтягивается шагом TrailingStep.
  5. Закрытие. При срабатывании любого стопа или трейлинга вся корзина закрывается по рынку, а счётчики усреднений сбрасываются.

Параметры

Параметр Тип Значение по умолчанию Описание
CandleType DataType Таймфрейм H1 Серия свечей, на которой работает стратегия.
StartVolume decimal 0.01 Базовый объём первой сделки в корзине.
StopLossPoints decimal 20 Дистанция стоп-лосса в шагах цены (0 отключает).
TakeProfitPoints decimal 20 Дистанция тейк-профита в шагах цены (0 отключает).
StartHour int 3 Час (включительно), с которого разрешено открывать новые корзины.
EndHour int 18 Час (не включительно), после которого корзины не создаются.
TemaPeriod int 50 Период индикатора TEMA.
BarsCalculated int 3 Минимальное число завершённых свечей до старта торговли.
AtrPeriod int 14 Период индикатора ATR.
GridMultiplier decimal 0.75 Множитель ATR, определяющий расстояние между усреднениями.
MaxAverageOrders int 3 Максимум сделок в одну сторону (включая стартовую).
Averaging перечисление AverageDown Режим добавления сделок: против движения, по движению или без усреднения.
Martin перечисление Multiply Схема расчёта объёма: умножение или прибавление.
LotMultiplier decimal 1.5 Множитель объёма в режиме Multiply.
LotIncrement decimal 0.1 Прибавка объёма в режиме Increment.
TradeAtNewBar bool false Ограничить создание корзины одной свечой.
TrailingStart int 100 Прибыль в пунктах для активации трейлинга.
TrailingStop int 50 Дистанция трейлинг-стопа в пунктах.
TrailingStep int 30 Минимальное улучшение цены перед очередным подтягиванием стопа.

Особенности портирования

  • Сохранены исходные индикаторы (TEMA(50) и ATR(14)), а параметр MT5 bar представлен как BarsCalculated, чтобы стратегия начинала работу только после достаточной инициализации индикаторов.
  • Контроль объёма учитывает биржевые ограничения MinVolume, MaxVolume и VolumeStep, поэтому мартингейл соблюдает торговые требования инструмента.
  • Трейлинг реализован на основе агрегированной позиции, что соответствует неттинговой модели StockSharp, но повторяет логику «безубыток + шаговое подтягивание» оригинального робота.
  • Графические объекты из MT5 не переносились: в StockSharp можно использовать стандартные панели для отображения сделок и позиций.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Basic Martingale EA 3 strategy: WMA crossover with RSI filter.
/// Buys when WMA fast crosses above slow and RSI below midline, sells on opposite conditions.
/// </summary>
public class BasicMartingaleEa3Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	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 RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }

	public BasicMartingaleEa3Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 15)
			.SetGreaterThanZero()
			.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, rsi, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue, decimal rsiValue)
	{
		if (candle.State != CandleStates.Finished) return;

		if (_hasPrev)
		{
			if (_prevFast <= _prevSlow && fastValue > slowValue && rsiValue < 45 && Position <= 0)
				BuyMarket();
			else if (_prevFast >= _prevSlow && fastValue < slowValue && rsiValue > 55 && Position >= 0)
				SellMarket();
		}
		else
		{
			if (fastValue > slowValue && rsiValue < 45 && Position <= 0)
				BuyMarket();
			else if (fastValue < slowValue && rsiValue > 55 && Position >= 0)
				SellMarket();
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
		_hasPrev = true;
	}
}