Открыть на GitHub

XP Trade Manager Grid (C#)

Описание

XP Trade Manager Grid — это перенос эксперта MetaTrader 4 XP Trade Manager Grid.mq4 на платформу StockSharp. Стратегия строит симметричную сетку: как только цена уходит на заданное число пунктов от последней сделки, открывается новый ордер в том же направлении. В оригинале прибыль защищается тремя индивидуальными тейк-профитами, «кластером» вокруг безубыточности при большом числе позиций и процентным ограничением убытков. C# реализация воспроизводит эти механизмы средствами высокоуровневого API StockSharp.

Алгоритм работы

  1. Первый ордер — при запуске стратегия сразу отправляет рыночный ордер в сторону, заданную параметром InitialSide (по умолчанию SELL).
  2. Расширение сетки — если цена закрытия ушла от последней сделки на StepPoints × минимальный шаг цены, открывается ещё один ордер в ту же сторону, пока суммарное число позиций меньше MaxOrders.
  3. Тейк-профиты для первых трёх ордеров — первые три сделки в каждом направлении получают собственные уровни тейк-профита (TakeProfit1Partitive, TakeProfit2, TakeProfit3). При достижении цели позиция закрывается встречным рыночным ордером.
  4. Кластер безубыточности — когда активных позиций становится ≥ 4, вычисляется средняя цена безубыточности по всей сетке. В зависимости от того, какая сторона доминирует, к ней прибавляется/вычитается соответствующий показатель TakeProfitXTotal (делённый на число ордеров). При достижении этого уровня все позиции закрываются.
  5. Повторный запуск цикла — если первый ордер цикла закрылся, но суммарный результат меньше TakeProfit1Total, стратегия ждёт обратного движения на TakeProfit1Offset пунктов от последней цены закрытия и заново открывает первый ордер.
  6. Ограничение убытков — рассчитывается текущая плавающая прибыль (реализованная + нереализованная) в валюте счёта. Если она опускается ниже RiskPercent процентов от начального баланса, все позиции закрываются.

Стратегия ведёт учёт каждой «ноги» сетки, поддерживает частичные исполнения и хеджевые комбинации: входы противоположной стороны сперва гасят открытые сделки в том направлении, и только остаток превращается в новый ордер — как и в версии MT4.

Параметры

  • CandleType — тип свечей, по которым принимаются решения (по умолчанию 1 минута).
  • OrderVolume — объём каждой сделки.
  • MaxOrders — максимально допустимое число одновременных позиций.
  • StepPoints — шаг между соседними ордерами в пунктах.
  • RiskPercent — предельная плавающая просадка в процентах от стартового баланса.
  • TakeProfit1Total — минимальная суммарная прибыль (в пунктах) для цикла первого ордера, после которой не выполняется автоматический перезапуск.
  • TakeProfit1Partitive — тейк-профит для первого ордера.
  • TakeProfit1Offset — насколько цена должна отойти от последнего тейк-профита, чтобы снова открыть первый ордер.
  • TakeProfit2, TakeProfit3 — тейк-профиты для второго и третьего ордера.
  • TakeProfit4TotalTakeProfit15Total — значения для расчёта группового тейк-профита при соответствующем количестве позиций.
  • InitialSide — направление первого ордера (BUY/SELL).

Важно: все точечные параметры автоматически умножаются на PriceStep инструмента, что соответствует функции Point() в MetaTrader.

Отличия от версии MT4

  • В StockSharp нет прямого изменения тейк-профита уже зарегистрированного ордера, поэтому первые три сделки закрываются рыночными заявками.
  • Плавающий результат рассчитывается через PriceStep и StepPrice. Если брокер не предоставляет эти значения, потребуется дополнительная настройка.
  • Графические надписи «Profit pips / Profit currency» не отображаются. Для перезапуска первого ордера используются внутренние статистические данные.

Рекомендации

  1. Тестируйте стратегию с небольшими объёмами, чтобы подобрать подходящие параметры сетки для конкретного инструмента.
  2. Увеличение StepPoints снижает частоту добора и уменьшает просадки, но делает сетку менее чувствительной.
  3. Для инструментов с широким спредом увеличьте TakeProfit1Offset, чтобы избежать слишком ранних повторных входов.
  4. Не отключайте StartProtection() — встроенная защита помогает восстановить соединение при сбоях.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "XP Trade Manager Grid" MetaTrader expert.
/// Uses RSI for entry direction with grid-style position management.
/// </summary>
public class XpTradeManagerGridStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpper;
	private readonly StrategyParam<decimal> _rsiLower;

	private RelativeStrengthIndex _rsi;
	private decimal? _prevRsi;

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

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal RsiUpper
	{
		get => _rsiUpper.Value;
		set => _rsiUpper.Value = value;
	}

	public decimal RsiLower
	{
		get => _rsiLower.Value;
		set => _rsiLower.Value = value;
	}

	public XpTradeManagerGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for signal generation", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");

		_rsiUpper = Param(nameof(RsiUpper), 70m)
			.SetDisplay("RSI Upper", "RSI threshold for sell", "Signals");

		_rsiLower = Param(nameof(RsiLower), 30m)
			.SetDisplay("RSI Lower", "RSI threshold for buy", "Signals");
	}

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

		_prevRsi = null;
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_rsi, ProcessCandle)
			.Start();

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

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

		if (!_rsi.IsFormed)
		{
			_prevRsi = rsiValue;
			return;
		}

		if (_prevRsi is null)
		{
			_prevRsi = rsiValue;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// RSI crosses below oversold -> buy
		var crossDown = _prevRsi.Value > RsiLower && rsiValue <= RsiLower;
		// RSI crosses above overbought -> sell
		var crossUp = _prevRsi.Value < RsiUpper && rsiValue >= RsiUpper;

		if (crossDown)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (crossUp)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevRsi = rsiValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_rsi = null;
		_prevRsi = null;

		base.OnReseted();
	}
}