Renko Fractals Grid is a direct port of the MetaTrader 4 expert advisor "RENKO FRACTALS GRID". The strategy trades breakouts of recent Bill Williams fractals that are confirmed by a Renko-style volatility filter, a weighted moving average trend bias, and momentum strength derived from the rate of change indicator. The StockSharp version keeps the grid-style position management of the original robot, including martingale position sizing, break-even handling, trailing stops, equity protection, and optional floating profit trailing in currency units.
Trading Logic
Fractal breakout: A long setup requires the most recent bullish fractal to be broken by the last closed candle while at least one of the prior three closes remained below that level. Short trades mirror this behaviour with bearish fractals.
Renko filter: The strategy inspects the high/low range of the last CandlesToRetrace bars. A breakout is valid only when the current close is at least one Renko "box" (either a fixed pip distance or the latest ATR value) away from those extremes.
Trend filter: Fast and slow weighted moving averages must be aligned (fast above slow for longs and below for shorts).
Momentum check: The absolute deviation of the last three rate-of-change values from 100 must exceed the configured thresholds. This mimics the MQL momentum filter based on iMomentum.
MACD confirmation: Trades are allowed only when the MACD main line is on the correct side of its signal line. The same check is used for exit timing.
Risk Management
Martingale grid: Every additional position multiplies the base volume by LotExponent while the number of simultaneous trades is capped by MaxTrades.
Stop-loss and take-profit: Static price offsets in pips are applied from the average entry price.
Break-even: When the price advances by BreakEvenTriggerPips the stop moves to entry plus BreakEvenOffsetPips.
Trailing stop: A candle-based trailing stop maintains the best excursion observed since entry.
Money trailing: Optional floating profit management closes all trades after a pullback of MoneyStopLoss once the open profit exceeds MoneyTakeProfit.
Equity stop: The strategy tracks the running equity peak (based on the portfolio value and open PnL). If the drawdown exceeds EquityRiskPercent the entire position is liquidated.
Parameters
Name
Description
CandleType
Primary candle type used for all indicators.
FastMaLength / SlowMaLength
Periods of the weighted moving averages that define trend direction.
MomentumLength
Rate-of-change lookback for the momentum filter.
MomentumBuyThreshold / MomentumSellThreshold
Minimum absolute deviation from 100 required for entries.
UseAtrFilter
Use ATR instead of a fixed pip distance for the Renko confirmation.
BoxSizePips
Size of the synthetic Renko box when ATR filtering is disabled.
CandlesToRetrace
Number of candles inspected when measuring recent highs and lows.
BaseVolume
Initial trade volume before applying the martingale multiplier.
LotExponent
Multiplier applied to each new position in the grid.
MaxTrades
Maximum number of concurrent positions per direction.
StopLossPips / TakeProfitPips
Static protective stop and target distances.
TrailingStopPips
Trailing stop distance in pips (set to zero to disable).
UseBreakEven
Enable moving the stop to break even.
BreakEvenTriggerPips / BreakEvenOffsetPips
Distance required before break-even activation and the offset applied afterwards.
UseMoneyTarget
Enable floating profit trailing in currency units.
MoneyTakeProfit / MoneyStopLoss
Profit threshold that activates money trailing and the maximum permitted pullback.
UseEquityStop
Enable equity based global stop-out.
EquityRiskPercent
Maximum allowed drawdown from the equity peak before closing all trades.
Implementation Notes
The original EA evaluates MACD on the monthly timeframe. The StockSharp port uses the same indicator configuration on the working timeframe because multi-timeframe data is not available by default.
All price offsets that originated from "pips" in MQL are converted through the instrument's price step in order to work with fractional pip quotations.
Realised profit tracking is approximated via filled order events, which is sufficient for equity-drawdown logic in the absence of broker-provided account statistics.
The strategy uses high-level candle subscriptions with indicator binding as required by the project guidelines and keeps every inline comment in English as requested.
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>
/// Renko Fractals Grid strategy. Uses fast/slow WMA crossover with momentum confirmation.
/// </summary>
public class RenkoFractalsGridStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
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 RenkoFractalsGridStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 6)
.SetGreaterThanZero()
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (prevAbove && !currAbove && 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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class renko_fractals_grid_strategy(Strategy):
def __init__(self):
super(renko_fractals_grid_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 8) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(renko_fractals_grid_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(renko_fractals_grid_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return renko_fractals_grid_strategy()