Ver no GitHub

Trading Panel Batch Strategy

Overview

TradingPanelBatchStrategy is a StockSharp port of the MetaTrader 4 expert advisor EA_TradingPanel. The original script exposed a manual panel where the trader configured the number of simultaneous trades, lot size and protective distances before pressing BUY or SELL. In the StockSharp version the same behaviour is automated: once the operator sets the Direction parameter the strategy fires a batch of market orders on the next finished candle and instantly resets the direction back to None.

The logic is intentionally simple so that the module can be combined with external signals or manual supervision. All orders inherit optional stop-loss and take-profit distances measured in pips, mirroring the risk controls available in the MQL implementation.

Workflow

  1. When the strategy starts it calculates the pip size from Security.PriceStep. For 1/3/5-digit Forex symbols the value is multiplied by ten, matching the MetaTrader conversion between points and pips.
  2. If stop-loss or take-profit offsets are non-zero the strategy enables StartProtection to manage exits with market orders.
  3. The strategy subscribes to the candle series specified by CandleType. After each finished candle it checks the Direction parameter.
  4. If a direction is requested and the engine allows trading, the strategy sends NumberOfOrders market orders using OrderVolume for each ticket.
  5. After the batch is dispatched the strategy logs the action and automatically sets Direction back to None, ready for the next manual trigger.

This design keeps the module stateless between executions. Traders can repeatedly set Direction to Buy or Sell whenever they require a new batch of orders; the execution always happens on the next completed candle to avoid acting on partially formed market data.

Parameters

Name Type Default Description
NumberOfOrders int 1 Number of market orders sent in the next batch.
OrderVolume decimal 0.01 Volume applied to each market order.
StopLossPips decimal 2 Stop-loss distance converted from pips to absolute price using the current instrument metadata. Set to 0 to disable.
TakeProfitPips decimal 10 Take-profit distance in pips. Set to 0 to disable.
Direction TradeDirection None Requested direction for the next execution. The strategy resets the value after the orders are placed.
CandleType DataType TimeFrameCandle(1m) Candle series used to trigger execution.

Notes

  • The strategy requires a valid Security with properly configured PriceStep (and optionally Decimals). Without this metadata pip calculations fall back to 1.
  • StartProtection uses market orders for exits to mimic how the MQL panel closed positions at stop-loss or take-profit levels.
  • Because execution happens on finished candles, traders can synchronise order batches with custom analytics or external signals by updating Direction before the candle closes.
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;
	}
}