Открыть на GitHub

Trading Panel Batch Strategy

Обзор

TradingPanelBatchStrategy — порт советника MetaTrader 4 EA_TradingPanel на платформу StockSharp. В оригинале пользователю показывалась ручная панель: задавались количество сделок в серии, объём каждой заявки и расстояния до стоп-лосса/тейк-профита, после чего нажималась кнопка BUY или SELL. В StockSharp тот же сценарий реализован параметрами: достаточно установить Direction, и стратегия на следующей закрывшейся свече отправит пакет рыночных заявок, затем автоматически вернёт направление к значению None.

Логика намеренно упрощена, чтобы модуль легко комбинировался с внешними сигналами или ручным контролем. Все ордера наследуют опциональные стопы и тейки в пипсах — это полностью повторяет инструменты управления рисками из MQL-версии.

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

  1. При старте стратегия вычисляет размер пипса из Security.PriceStep. Для инструментов с 1/3/5 знаками после запятой шаг дополнительно умножается на 10, как и в MetaTrader при переходе от point к pip.
  2. Если заданы ненулевые отступы для стопа или тейка, вызывается StartProtection, которая сопровождает позиции рыночными заявками.
  3. Подписывается свечной поток, указанный в CandleType. После формирования каждой свечи проверяется текущее значение Direction.
  4. Если задано направление и торговля разрешена, стратегия отправляет NumberOfOrders рыночных ордеров объёмом OrderVolume.
  5. После рассылки заявок событие логируется, а 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;
	}
}