The VR Smart Grid Lite Strategy replicates the logic of the MetaTrader expert advisor with the same name. The strategy builds a martingale-style averaging grid using market orders. Position sizing starts from a base volume and doubles each time price moves against the existing position by a user-defined distance. The strategy supports two exit modes: closing the extreme trades at a weighted take-profit price or partially reducing exposure while keeping the grid active.
Parameters
Take Profit (pips) – distance in pips used to exit when only one position is active.
Start Volume – initial order volume for the first trade in each direction.
Maximal Volume – hard cap for any single order opened by the grid.
Close Mode – Average closes the oldest and newest orders at a weighted target; PartClose closes part of the newest order and all of the oldest order.
Order Step (pips) – minimum price distance that must be travelled against the position before a new trade is opened.
Minimal Profit (pips) – additional profit margin added to the weighted average exit price.
Slippage (pips) – placeholder parameter retained from the original EA for completeness.
Candle Type – timeframe used to drive decision making (the previous completed candle determines the trading bias).
Algorithm
On every finished candle the strategy evaluates the previous candle direction.
If the previous candle closed bullish and either no long trades exist or the price moved down by the configured step, a new buy market order is placed.
If the previous candle closed bearish and either no short trades exist or the price moved up by the configured step, a new sell market order is placed.
Volumes are calculated from the lowest priced position in the direction and doubled at each new level, respecting the maximum volume and broker volume steps.
When only one position remains, the strategy applies the simple take-profit distance and exits on touch.
With multiple positions, the strategy computes weighted averages using the extreme entries:
Average mode closes both extremes when price reaches the weighted target plus the minimal profit buffer.
PartClose mode closes a portion of the newest order equal to the start volume and fully closes the oldest order, allowing the grid to keep running with reduced exposure.
All filled and closed positions are tracked to keep the internal grid state synchronized with the live portfolio.
Notes
The strategy relies on market orders, so real execution quality and slippage depend on broker conditions.
Ensure that instrument volume constraints (minimum volume and volume step) are compatible with the selected start volume.
As with any grid or martingale approach, risk can grow quickly when markets trend strongly against the position; use prudent money management.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// VR Smart Grid Lite: grid trading based on price levels with SMA filter.
/// </summary>
public class VrSmartGridLiteStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _gridPercent;
private readonly StrategyParam<int> _smaPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal GridPercent
{
get => _gridPercent.Value;
set => _gridPercent.Value = value;
}
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
public VrSmartGridLiteStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_gridPercent = Param(nameof(GridPercent), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Grid %", "Grid step percentage", "Grid");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period for trend", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = SmaPeriod };
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 * GridPercent / 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);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class vr_smart_grid_lite_strategy(Strategy):
def __init__(self):
super(vr_smart_grid_lite_strategy, self).__init__()
self._grid_percent = self.Param("GridPercent", 3.0) \
.SetDisplay("Grid %", "Grid step percentage", "Grid")
self._sma_period = self.Param("SmaPeriod", 20) \
.SetDisplay("SMA Period", "SMA period for trend", "Indicators")
self._sma = None
self._last_trade_price = None
@property
def grid_percent(self):
return self._grid_percent.Value
@property
def sma_period(self):
return self._sma_period.Value
def OnReseted(self):
super(vr_smart_grid_lite_strategy, self).OnReseted()
self._sma = None
self._last_trade_price = None
def OnStarted2(self, time):
super(vr_smart_grid_lite_strategy, self).OnStarted2(time)
self._sma = SimpleMovingAverage()
self._sma.Length = self.sma_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._sma, self._process_candle)
subscription.Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed:
return
close = float(candle.ClosePrice)
if self._last_trade_price is None:
self._last_trade_price = close
return
step = self._last_trade_price * self.grid_percent / 100.0
if close <= self._last_trade_price - step:
self.BuyMarket()
self._last_trade_price = close
elif close >= self._last_trade_price + step:
self.SellMarket()
self._last_trade_price = close
def CreateClone(self):
return vr_smart_grid_lite_strategy()