XP Trade Manager Grid — это перенос эксперта MetaTrader 4 XP Trade Manager Grid.mq4 на платформу StockSharp. Стратегия строит симметричную сетку: как только цена уходит на заданное число пунктов от последней сделки, открывается новый ордер в том же направлении. В оригинале прибыль защищается тремя индивидуальными тейк-профитами, «кластером» вокруг безубыточности при большом числе позиций и процентным ограничением убытков. C# реализация воспроизводит эти механизмы средствами высокоуровневого API StockSharp.
Алгоритм работы
Первый ордер — при запуске стратегия сразу отправляет рыночный ордер в сторону, заданную параметром InitialSide (по умолчанию SELL).
Расширение сетки — если цена закрытия ушла от последней сделки на StepPoints × минимальный шаг цены, открывается ещё один ордер в ту же сторону, пока суммарное число позиций меньше MaxOrders.
Тейк-профиты для первых трёх ордеров — первые три сделки в каждом направлении получают собственные уровни тейк-профита (TakeProfit1Partitive, TakeProfit2, TakeProfit3). При достижении цели позиция закрывается встречным рыночным ордером.
Кластер безубыточности — когда активных позиций становится ≥ 4, вычисляется средняя цена безубыточности по всей сетке. В зависимости от того, какая сторона доминирует, к ней прибавляется/вычитается соответствующий показатель TakeProfitXTotal (делённый на число ордеров). При достижении этого уровня все позиции закрываются.
Повторный запуск цикла — если первый ордер цикла закрылся, но суммарный результат меньше TakeProfit1Total, стратегия ждёт обратного движения на TakeProfit1Offset пунктов от последней цены закрытия и заново открывает первый ордер.
Ограничение убытков — рассчитывается текущая плавающая прибыль (реализованная + нереализованная) в валюте счёта. Если она опускается ниже RiskPercent процентов от начального баланса, все позиции закрываются.
Стратегия ведёт учёт каждой «ноги» сетки, поддерживает частичные исполнения и хеджевые комбинации: входы противоположной стороны сперва гасят открытые сделки в том направлении, и только остаток превращается в новый ордер — как и в версии MT4.
Параметры
CandleType — тип свечей, по которым принимаются решения (по умолчанию 1 минута).
OrderVolume — объём каждой сделки.
MaxOrders — максимально допустимое число одновременных позиций.
StepPoints — шаг между соседними ордерами в пунктах.
RiskPercent — предельная плавающая просадка в процентах от стартового баланса.
TakeProfit1Total — минимальная суммарная прибыль (в пунктах) для цикла первого ордера, после которой не выполняется автоматический перезапуск.
TakeProfit1Partitive — тейк-профит для первого ордера.
TakeProfit1Offset — насколько цена должна отойти от последнего тейк-профита, чтобы снова открыть первый ордер.
TakeProfit2, TakeProfit3 — тейк-профиты для второго и третьего ордера.
TakeProfit4Total … TakeProfit15Total — значения для расчёта группового тейк-профита при соответствующем количестве позиций.
InitialSide — направление первого ордера (BUY/SELL).
Важно: все точечные параметры автоматически умножаются на PriceStep инструмента, что соответствует функции Point() в MetaTrader.
Отличия от версии MT4
В StockSharp нет прямого изменения тейк-профита уже зарегистрированного ордера, поэтому первые три сделки закрываются рыночными заявками.
Плавающий результат рассчитывается через PriceStep и StepPrice. Если брокер не предоставляет эти значения, потребуется дополнительная настройка.
Графические надписи «Profit pips / Profit currency» не отображаются. Для перезапуска первого ордера используются внутренние статистические данные.
Рекомендации
Тестируйте стратегию с небольшими объёмами, чтобы подобрать подходящие параметры сетки для конкретного инструмента.
Увеличение StepPoints снижает частоту добора и уменьшает просадки, но делает сетку менее чувствительной.
Для инструментов с широким спредом увеличьте TakeProfit1Offset, чтобы избежать слишком ранних повторных входов.
Не отключайте 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();
}
}