Auf GitHub ansehen

Grid Template Strategy

Overview

This strategy is a StockSharp port of the MetaTrader 4 expert advisor Grid_Template. It builds a symmetric grid of pending sto p orders around the current bid/ask, allowing the trader to plug custom entry filters or run it as a pure breakout template. Onc e all grid orders have either executed or expired, the engine immediately prepares the next grid. The implementation preserves t he optional money-management formula and the ability to automatically remove stale pending orders after a configurable number of hours.

Trading logic

  • Subscribe to Level 1 quotes to continuously track the best bid/ask prices. No candles or indicators are required.
  • Whenever the account has no open position and no active strategy orders, place GridOrders buy stop orders above the ask and G ridOrders sell stop orders below the bid.
  • The first grid level is offset by PriceDistancePips from the current market price; each subsequent level adds GridStepPips m ore distance.
  • Every entry uses the same fixed volume (or money-managed size), and the same stop-loss and take-profit distances expressed in p ips.
  • As soon as a pending order is filled, the strategy registers the corresponding protective orders (stop loss and take profit) as independent stop/limit orders. These inherit the same comment to make them easy to identify.
  • If no order is triggered before the expiration timer elapses, the template cancels all resting pending orders and re-arms the g rid.

Money management

  • When UseMoneyManagement is disabled, all orders use the fixed StaticVolume parameter.
  • When enabled, the lot size is derived from the original template formula: freeMargin * RiskPercent / 100000, rounded to the n earer VolumeStep and clamped between VolumeMin and VolumeMax. The portfolio's current value is used as a stand-in for MT4's free margin.
  • The calculated volume is normalized by the exchange contract settings; if it falls below the minimum tradable size it is set to zero, preventing order submission.

Order and risk management

  • Buy stop orders are placed at ask + PriceDistancePips + GridStepPips * level. Sell stop orders mirror the logic on the bid si de.
  • Protective stops (SellStop/BuyStop) and targets (SellLimit/BuyLimit) are registered only after a pending entry is filled . This mimics the MT4 behaviour where the stop loss and take profit belong to the same ticket.
  • PendingExpirationHours defines how long pending entry orders remain active. A zero value keeps them until they fill or are ma nually cancelled.
  • When the net position returns to zero the strategy also cancels any still-active protective orders to ensure a clean slate.

Parameters

Parameter Description
OrderComment Text assigned to every order generated by the grid, matching the original EA comment.
StaticVolume Fixed lot size used when money management is turned off.
UseMoneyManagement Enables the balance-based sizing routine.
RiskPercent Percentage used by the money-management formula; ignored when UseMoneyManagement is false.
TakeProfitPips Take-profit distance applied to every grid entry.
StopLossPips Stop-loss distance applied to every grid entry.
PriceDistancePips Initial gap (in pips) between the market price and the first grid order.
GridStepPips Additional distance (in pips) added between consecutive grid levels.
GridOrders Number of pending orders created on each side of the price.
PendingExpirationHours Lifetime of the pending grid before cancellation.

Notes

  • The template does not impose any indicator-based filters; traders can extend the class and override TryPlaceGrid to add custo m conditions.
  • Because protective stops and targets are implemented as separate orders, broker-side execution may slightly differ from MT4 tik t-style stop-loss/take-profit management, especially on partial fills.
  • Always confirm that the pip size inferred from the exchange (PriceStep and Decimals) matches the instrument being traded be fore running the strategy on a live account.
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Grid Template strategy: places trades at regular grid intervals.
/// Buys when price drops by grid step, sells when price rises by grid step.
/// </summary>
public class GridTemplateStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _gridStepPercent;

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

	public decimal GridStepPercent
	{
		get => _gridStepPercent.Value;
		set => _gridStepPercent.Value = value;
	}

	public GridTemplateStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_gridStepPercent = Param(nameof(GridStepPercent), 3.0m)
			.SetGreaterThanZero()
			.SetDisplay("Grid Step %", "Price change percentage for grid level", "Grid");
	}

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

		var sma = new SimpleMovingAverage { Length = 10 };

		decimal? lastTradePrice = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, (candle, smaVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (!lastTradePrice.HasValue)
				{
					lastTradePrice = close;
					return;
				}

				var step = lastTradePrice.Value * GridStepPercent / 100m;

				if (close <= lastTradePrice.Value - step)
				{
					BuyMarket();
					lastTradePrice = close;
				}
				else if (close >= lastTradePrice.Value + step)
				{
					SellMarket();
					lastTradePrice = close;
				}
			})
			.Start();

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