OverHedge V2 is a hedged grid system that alternates long and short positions while increasing trade size after each fill. The strategy analyses the relationship between a fast and a slow exponential moving average (EMA) to decide the dominant direction for the next cycle. Once a cycle starts, the algorithm places market orders whenever price reaches predefined tunnel levels around the starting quote. The grid expands symmetrically so that every new leg offsets the floating loss of the previous one. The cycle ends when the aggregate open profit exceeds a configurable target or when the trader manually requests a shutdown.
The implementation keeps separate tallies for long and short exposure and uses live Level 1 prices to trigger new hedges. Trade volume grows geometrically according to the chosen multiplier, which reproduces the martingale-style risk from the original MetaTrader expert advisor. Because orders are executed at market, the system automatically adapts to liquidity conditions while keeping the grid spacing expressed in points.
How it works
Direction filter – The strategy calculates two EMAs on completed candles. When the fast EMA is above the slow EMA, the next cycle starts from a long bias; otherwise it starts from a short bias.
Cycle initialisation – At the beginning of a cycle, the algorithm records the current bid price and derives two tunnel boundaries separated by the configured width and the live spread. The first order follows the EMA bias, and the opposite leg is staged at the tunnel distance.
Grid expansion – If price continues against the latest entry, additional market orders are triggered alternately (buy, sell, buy, …). Each new leg multiplies the previous volume by the hedge multiplier, allowing the overall position to recover faster on a reversal.
Profit harvesting – The cycle constantly monitors unrealised profit using the best bid/ask prices. When the target value is reached, or if the operator toggles the shutdown flag, all open legs are liquidated and the cycle resets.
Exposure tracking – The strategy maintains the average price and volume for both long and short hedges to calculate open profit precisely and to avoid sending duplicate orders while existing ones are still pending.
Default parameters
Base Volume = 0.1 lots – Initial trade size for the first grid leg.
Hedge Multiplier = 2.0 – Volume multiplier applied to each subsequent leg.
Tunnel Width (points) = 20 – Additional distance between alternating orders beyond the current spread.
Profit Target = 100 – Unrealised profit in account currency that closes the entire grid.
Short EMA = 8 – Period of the fast EMA used for direction detection.
Long EMA = 21 – Period of the slow EMA used for direction detection.
Candle Type = 1 minute – Timeframe that feeds the EMA filters.
Shutdown Grid = false – When true the strategy immediately exits all legs and stops trading.
Notes
The grid works with any instrument that provides Level 1 quotes (best bid/ask). Wider spreads increase the tunnel size automatically.
Trade volume is normalised using the security volume step to avoid rejected orders.
Because the system uses a martingale sizing scheme, large drawdowns are possible if price trends persist without hitting the profit target.
To resume trading after a shutdown, toggle the parameter back to false or restart the strategy.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// OverHedge V2 Grid strategy using RSI mean reversion with grid averaging.
/// Buy when RSI is oversold, sell when RSI is overbought.
/// </summary>
public class OverHedgeV2GridStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<DataType> _candleType;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public OverHedgeV2GridStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI period", "Indicators");
_oversold = Param(nameof(Oversold), 30m)
.SetDisplay("Oversold", "RSI oversold level", "Indicators");
_overbought = Param(nameof(Overbought), 70m)
.SetDisplay("Overbought", "RSI overbought level", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (rsiValue <= Oversold && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (rsiValue >= Overbought && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class over_hedge_v2_grid_strategy(Strategy):
"""OverHedge V2 Grid strategy using RSI mean reversion.
Buy when RSI is oversold, sell when RSI is overbought."""
def __init__(self):
super(over_hedge_v2_grid_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._oversold = self.Param("Oversold", 30.0) \
.SetDisplay("Oversold", "RSI oversold level", "Indicators")
self._overbought = self.Param("Overbought", 70.0) \
.SetDisplay("Overbought", "RSI overbought level", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def Oversold(self):
return self._oversold.Value
@property
def Overbought(self):
return self._overbought.Value
def OnReseted(self):
super(over_hedge_v2_grid_strategy, self).OnReseted()
def OnStarted2(self, time):
super(over_hedge_v2_grid_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
if rsi_val <= float(self.Oversold) and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif rsi_val >= float(self.Overbought) and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return over_hedge_v2_grid_strategy()