This strategy implements a hedged martingale grid. It starts by placing stop orders on both sides of the current price and doubles position size in the opposite direction whenever the market moves against the current exposure by a specified step. All trades are closed once accumulated profit exceeds the target.
Details
Entry Criteria:
Place a buy stop above and a sell stop below the market at distance Step.
When an order triggers, cancel the opposite stop.
Position Management:
Track the price of the last executed order.
If price moves against the open position by Step * orderCount, send a market order in the opposite direction with double the previous volume.
Exit Criteria:
Close all positions when unrealized profit reaches ProfitClose.
Long/Short: Both.
Stops: Uses stop orders for initial entries; no stop-loss.
Indicators: None.
Filters: None.
Parameters
Step – price step in absolute units.
ProfitClose – profit threshold to close all trades.
InitialVolume – starting volume for the first order.
CandleType – candle series used for price updates.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Mean reversion strategy inspired by martingale.
/// Enters on RSI extremes, exits when price returns to SMA.
/// </summary>
public class MartiniMartingaleStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<DataType> _candleType;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MartiniMartingaleStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA for mean reversion target", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var sma = new SimpleMovingAverage { Length = SmaPeriod };
SubscribeCandles(CandleType).Bind(rsi, sma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal sma)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
// RSI oversold => buy
if (rsi < 30 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// RSI overbought => sell
else if (rsi > 70 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
// Exit long at SMA
else if (Position > 0 && close >= sma && rsi > 50)
{
SellMarket();
}
// Exit short at SMA
else if (Position < 0 && close <= sma && rsi < 50)
{
BuyMarket();
}
}
}
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 RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class martini_martingale_strategy(Strategy):
def __init__(self):
super(martini_martingale_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 7) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._sma_period = self.Param("SmaPeriod", 20) \
.SetDisplay("SMA Period", "SMA for mean reversion target", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def sma_period(self):
return self._sma_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(martini_martingale_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
sma = SimpleMovingAverage()
sma.Length = self.sma_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, sma, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, rsi, sma):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
# RSI oversold => buy
if rsi < 30 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# RSI overbought => sell
elif rsi > 70 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Exit long at SMA
elif self.Position > 0 and close >= sma and rsi > 50:
self.SellMarket()
# Exit short at SMA
elif self.Position < 0 and close <= sma and rsi < 50:
self.BuyMarket()
def CreateClone(self):
return martini_martingale_strategy()