The strategy replicates the behaviour of the original MostasHaR15 Pivot MQL5 Expert Advisor using StockSharp's high level API. It combines classic daily floor-pivot calculations with momentum filters from ADX, EMA differentials and the MACD histogram (OsMA). The strategy operates on an intraday candle stream (1 hour by default) and consumes the previous completed daily candle to rebuild the pivot map on every bar.
Trading Logic
Pivot grid – the previous daily high, low and close are used to calculate the main pivot (P), three resistance levels (R1–R3), three support levels (S1–S3) and six midpoints (M0–M5). The current candle close is compared with this ladder to identify the surrounding support and resistance segment. A special case inherited from the EA maps prices between M5 and R3 back to the S3/M0 range.
Distance filter – trades are only allowed when the distance to the nearest take-profit level is larger than MinimumDistancePips (14 pips by default), which matches the original dif1/dif2 filters.
Long entries require all of the following:
ADX main line exceeds AdxThreshold (20) and +DI is both rising and above –DI.
The 5-period EMA on candle closes is at least EmaSlopePips (5 pips) above the 8-period EMA on candle opens, and the previous bar showed the same bullish EMA ordering.
MACD histogram (OsMA) increased compared to the previous bar.
Short entries mirror the long conditions with −DI strength, bearish EMA spread and a falling MACD histogram.
Only one net position is allowed. Orders are placed with market execution via BuyMarket()/SellMarket().
Position Management
Stop-loss – optional, located StopLossPips below/above the entry price. Setting the parameter to 0 disables the initial stop, as in the EA.
Take-profit – fixed at the nearest pivot boundary that surrounds the current price when the position is opened.
Trailing stop – replicates the original trailing logic. Once price advances more than TrailingStopPips + TrailingStepPips from entry, the stop is moved to maintain a trailing distance of TrailingStopPips. Trailing can be disabled by setting TrailingStopPips to 0.
If either stop-loss, trailing stop or take-profit is hit during a candle, the position is flattened at the close of that candle.
Strategy Parameters
Parameter
Description
Default
CandleType
Intraday candle series used for trading.
1 hour time frame
DailyCandleType
Daily candle series for pivot calculations.
1 day time frame
StopLossPips
Stop-loss distance in pips. Set 0 to disable.
20
TrailingStopPips
Trailing stop distance in pips.
5
TrailingStepPips
Minimum favourable move before the trail updates. Must be >0 if trailing is enabled.
5
MinimumDistancePips
Minimum pip distance to the nearest pivot boundary before entering a trade.
14
EmaSlopePips
Required separation between the close EMA and the open EMA.
5
AdxThreshold
Minimum ADX reading for both long and short trades.
20
AdxPeriod
ADX indicator length.
14
EmaClosePeriod
EMA period applied to candle closes.
5
EmaOpenPeriod
EMA period applied to candle opens.
8
MacdFastPeriod
Fast EMA period inside the MACD histogram.
12
MacdSlowPeriod
Slow EMA period inside the MACD histogram.
26
MacdSignalPeriod
Signal EMA period inside the MACD histogram.
9
Conversion Notes
The strategy keeps the unusual behaviour of the EA where the price range between mid-level M5 and resistance R3 maps back to the S3/M0 support/resistance pair.
All indicator values are processed on finished candles only. No historical collections are stored; all state is held in scalar fields as recommended by the repository guidelines.
Comments in the strategy remain in English per repository instructions.
Usage Tips
Adjust CandleType and DailyCandleType when applying the strategy to markets with different trading sessions.
Because stop-loss and trailing logic are evaluated on closed candles, additional slippage can appear in fast markets compared to tick-level execution in the original EA.
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>
/// MostasHar15 Pivot strategy (simplified).
/// Uses daily pivot levels with RSI filter for entries.
/// </summary>
public class MostasHar15PivotStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<DataType> _dailyCandleType;
private readonly StrategyParam<int> _rsiLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public DataType DailyCandleType
{
get => _dailyCandleType.Value;
set => _dailyCandleType.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public MostasHar15PivotStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Trading candles", "General");
_dailyCandleType = Param(nameof(DailyCandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Daily Candle Type", "Higher timeframe for pivots", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiLength };
decimal pivotHigh = 0;
decimal pivotLow = 0;
decimal pivotMid = 0;
bool hasPivot = false;
// Subscribe to higher timeframe for pivot levels
var dailySub = SubscribeCandles(DailyCandleType);
dailySub
.Bind((ICandleMessage candle) =>
{
if (candle.State != CandleStates.Finished)
return;
pivotMid = (candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 3m;
pivotHigh = 2m * pivotMid - candle.LowPrice;
pivotLow = 2m * pivotMid - candle.HighPrice;
hasPivot = true;
})
.Start();
// Subscribe to trading timeframe with RSI
var tradeSub = SubscribeCandles(CandleType);
tradeSub
.Bind(rsi, (ICandleMessage candle, decimal rsiVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!hasPivot)
return;
var close = candle.ClosePrice;
// Long: price above pivot, RSI momentum confirms
if (close > pivotMid && rsiVal > 55 && Position <= 0)
BuyMarket();
// Short: price below pivot, RSI confirms weakness
else if (close < pivotMid && rsiVal < 45 && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, tradeSub);
DrawIndicator(area, rsi);
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class mostas_har15_pivot_strategy(Strategy):
def __init__(self):
super(mostas_har15_pivot_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Trading candles", "General")
self._daily_candle_type = self.Param("DailyCandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Daily Candle Type", "Higher timeframe for pivots", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._pivot_mid = 0.0
self._has_pivot = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def DailyCandleType(self):
return self._daily_candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
def OnReseted(self):
super(mostas_har15_pivot_strategy, self).OnReseted()
self._pivot_mid = 0.0
self._has_pivot = False
def OnStarted2(self, time):
super(mostas_har15_pivot_strategy, self).OnStarted2(time)
self._pivot_mid = 0.0
self._has_pivot = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiLength
daily_sub = self.SubscribeCandles(self.DailyCandleType)
daily_sub.Bind(self._on_daily_candle).Start()
trade_sub = self.SubscribeCandles(self.CandleType)
trade_sub.Bind(rsi, self._on_trade_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, trade_sub)
self.DrawOwnTrades(area)
def _on_daily_candle(self, candle):
if candle.State != CandleStates.Finished:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
self._pivot_mid = (high + low + close) / 3.0
self._has_pivot = True
def _on_trade_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._has_pivot:
return
close = float(candle.ClosePrice)
rv = float(rsi_value)
if close > self._pivot_mid and rv > 55 and self.Position <= 0:
self.BuyMarket()
elif close < self._pivot_mid and rv < 45 and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return mostas_har15_pivot_strategy()