TradingPanelBatchStrategy — порт советника MetaTrader 4 EA_TradingPanel на платформу StockSharp. В оригинале пользователю показывалась ручная панель: задавались количество сделок в серии, объём каждой заявки и расстояния до стоп-лосса/тейк-профита, после чего нажималась кнопка BUY или SELL. В StockSharp тот же сценарий реализован параметрами: достаточно установить Direction, и стратегия на следующей закрывшейся свече отправит пакет рыночных заявок, затем автоматически вернёт направление к значению None.
Логика намеренно упрощена, чтобы модуль легко комбинировался с внешними сигналами или ручным контролем. Все ордера наследуют опциональные стопы и тейки в пипсах — это полностью повторяет инструменты управления рисками из MQL-версии.
Алгоритм работы
При старте стратегия вычисляет размер пипса из Security.PriceStep. Для инструментов с 1/3/5 знаками после запятой шаг дополнительно умножается на 10, как и в MetaTrader при переходе от point к pip.
Если заданы ненулевые отступы для стопа или тейка, вызывается StartProtection, которая сопровождает позиции рыночными заявками.
Подписывается свечной поток, указанный в CandleType. После формирования каждой свечи проверяется текущее значение Direction.
Если задано направление и торговля разрешена, стратегия отправляет NumberOfOrders рыночных ордеров объёмом OrderVolume.
После рассылки заявок событие логируется, а Direction автоматически сбрасывается в None, готовя стратегию к следующему запросу.
Таким образом, между сериями сделок стратегия не хранит состояние. Трейдер может в любой момент выставить Direction = Buy или Direction = Sell, и при закрытии ближайшей свечи будет сформирована новая партия заявок — это позволяет избежать решений по незавершённым данным.
Параметры
Название
Тип
Значение по умолчанию
Описание
NumberOfOrders
int
1
Количество рыночных ордеров в очередной серии.
OrderVolume
decimal
0.01
Объём каждого рыночного ордера.
StopLossPips
decimal
2
Дистанция стоп-лосса в пипсах, преобразуется в абсолютную цену по данным инструмента. Значение 0 отключает стоп.
TakeProfitPips
decimal
10
Дистанция тейк-профита в пипсах. Значение 0 отключает тейк.
Direction
TradeDirection
None
Направление для следующего исполнения; после отправки заявок параметр сбрасывается.
CandleType
DataType
TimeFrameCandle(1m)
Свечной поток, по закрытию которого срабатывает стратегия.
Примечания
Стратегии необходим инструмент с корректно настроенными PriceStep и (желательно) Decimals. При отсутствии этих данных размер пипса падает к значению 1.
StartProtection использует рыночные ордера для закрытия, что отражает механику MQL-панели при срабатывании стопов и тейков.
Исполнение привязано к закрытым свечам, поэтому можно заранее установить нужное направление и синхронизировать пакетные сделки с аналитикой или ручными сигналами.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Trading Panel Batch strategy: DEMA crossover.
/// Buys when fast DEMA crosses above slow DEMA, sells on cross below.
/// </summary>
public class TradingPanelBatchStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
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 TradingPanelBatchStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow DEMA", "Slow DEMA 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);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
SellMarket();
}
else
{
if (fastValue > slowValue && Position <= 0)
BuyMarket();
else if (fastValue < slowValue && Position >= 0)
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
}
}