Converted from the original MQL expert advisor PINBAR.mq4 (folder MQL/22269). The strategy detects pin bar reversals on the primary timeframe and confirms them with higher timeframe momentum and MACD filters. It reproduces the spirit of the source system while using StockSharp high-level API features.
Trading Logic
Primary timeframe – configurable candle type used to identify price action patterns.
Higher timeframe – configurable candle type used to confirm momentum and MACD trend bias.
Pin bar detection – a bar is accepted when the real body is small relative to the full range and one wick dominates the candle (configurable body and wick ratios).
Trend filter – fast EMA must be above (or below) the slow EMA for long (or short) setups, mirroring the LWMA filters from the original code.
Momentum confirmation – momentum on the higher timeframe must be above (long) or below (short) a configurable threshold for at least one of the last three higher-timeframe bars.
MACD confirmation – the MACD value must be above its signal line for long trades and below the signal line for shorts, matching the monthly MACD confirmation used in the MQL expert.
Fractal confirmation – the strategy maintains a rolling five-bar window and requires the presence of the latest bullish/bearish fractal before accepting a new trade, similar to the FindFractals() gate in the source.
Risk management – configurable stop-loss, take-profit, break-even trigger/offset and trailing stop logic track the open position. The trade is exited when any level is touched or when the trailing level is breached.
Entry Rules
Long Setup
Latest candle on the primary timeframe forms a bullish pin bar (long lower wick, small body).
Fast EMA > slow EMA.
Latest higher timeframe momentum (or one of the two previous values) is above the threshold.
Higher timeframe MACD is above its signal line.
A bullish fractal has been detected recently and price has not invalidated it.
Strategy is flat or short (shorts are reversed).
Short Setup
Latest candle on the primary timeframe forms a bearish pin bar (long upper wick, small body).
Fast EMA < slow EMA.
Latest higher timeframe momentum (or one of the two previous values) is below the negative threshold.
Higher timeframe MACD is below its signal line.
A bearish fractal has been detected recently and price has not invalidated it.
Strategy is flat or long (longs are reversed).
Exit Rules
Stop-loss and take-profit are expressed in percent relative to the entry price.
Break-even activates once price moves by the trigger percentage; the stop is moved to entry plus/minus an offset.
Trailing stop activates after the activation percentage is achieved and follows price at the configured distance.
Opposite signals also reverse the position.
Parameters
Name
Default
Description
CandleType
15-minute candles
Primary timeframe for pattern detection.
TrendCandleType
1-hour candles
Higher timeframe for momentum/MACD filters.
FastMaLength
6
Fast EMA length (replaces fast LWMA).
SlowMaLength
85
Slow EMA length (replaces slow LWMA).
MomentumLength
14
Momentum indicator length on higher timeframe.
MomentumThreshold
0.1
Minimum absolute momentum value for confirmation.
MacdFastLength
12
MACD fast EMA length.
MacdSlowLength
26
MACD slow EMA length.
MacdSignalLength
9
MACD signal EMA length.
BodyToRangeRatio
0.3
Maximum body size relative to candle range.
WickRatio
0.6
Minimum dominant wick ratio defining a pin bar.
StopLossPercent
2
Protective stop size in percent.
TakeProfitPercent
4
Profit target size in percent.
BreakEvenTriggerPercent
1.5
Profit required to move the stop to break-even.
BreakEvenOffsetPercent
0.2
Additional offset added to the break-even stop.
TrailingActivationPercent
2.5
Profit threshold for enabling trailing stop.
TrailingDistancePercent
1
Distance of the trailing stop once activated.
Notes
Volume is fixed to 1 contract by default; adjust the strategy volume for different position sizing.
The fractal detection resets when price breaches the recorded fractal level, requiring a fresh pattern before a new trade.
Optimisation ranges are included for key parameters to facilitate backtesting and tuning in StockSharp Designer.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class PinbarReversal2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast, _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 PinbarReversal2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 6).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 25).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(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 fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast; _prevSlow = slow;
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 pinbar_reversal2_strategy(Strategy):
def __init__(self):
super(pinbar_reversal2_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", 6) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 25) \
.SetDisplay("Slow EMA", "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(pinbar_reversal2_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(pinbar_reversal2_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 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return pinbar_reversal2_strategy()