Combo EA4 FSF R Updated 5 Strategy
Overview
This strategy is a StockSharp conversion of the MetaTrader expert advisor "Combo_EA4FSFrUpdated5". It combines five different technical modules—moving averages, RSI, stochastic oscillator, parabolic SAR and a zero-lag MACD—to validate every trading decision. A position is opened only when all enabled modules point to the same direction, recreating the strict consensus logic of the original EA. Optional trailing management, automatic signal-based exits and the ability to flip into the opposite direction after closing are also preserved.
Indicator stack
- Moving averages – Three configurable averages (MA1, MA2, MA3) with ATR-based buffers that reduce false crossover signals. Five different aggregation modes replicate the EA's "MA_MODE" options.
- Relative Strength Index (RSI) – Multiple confirmation modes including classic overbought/oversold, slope-based trend detection, a combined mode and zone-based validation.
- Stochastic oscillator – Fast/slow/slowdown lengths with optional high/low band filtering.
- Parabolic SAR – Provides a trend polarity check against the previous candle close.
- Zero-lag MACD – Uses zero-lag exponential moving averages to match the bundled
ZeroLag_MACD.mq4 indicator. Supports three signal modes (trend structure, zero-line cross or combined).
- Average True Range (ATR) – Drives stop-loss/take-profit distances and the MA crossover buffers.
Trading logic
Entry conditions
- The indicator values for all enabled modules must be available (the strategy automatically waits for warm-up).
- For each enabled module a bullish or bearish direction is computed according to its mode:
- Moving averages – MA1/MA2/MA3 combinations with ATR buffers to confirm direction changes.
- RSI – Four modes covering thresholds, momentum and zone logic.
- Stochastic – K/D cross confirmation with optional high/low filters.
- Parabolic SAR – Requires price to be above/below the SAR value of the previous candle.
- Zero-lag MACD – Either trend alignment, zero-line cross confirmation or both.
- If every enabled module returns
Buy, the strategy sends a market buy order. If every module returns Sell, a market sell order is issued. Otherwise no trade is opened.
Exit conditions
- Signal-based exits – When
AutoClose is enabled the same consensus logic is evaluated using the dedicated exit flags (UseMaClosing, UseMacdClosing, etc.). A long position is closed when all enabled exit modules agree on a bearish signal; a short position is closed when they agree on a bullish signal. If OpenOppositeAfterClose is true, the opposite position is queued immediately after the closing fill.
- Protective levels – Initial stop-loss and take-profit levels are derived from the current ATR value (
AtrPeriod) multiplied by AtrMultiplier. The EA's pip buffer is emulated with the instrument's step size. Long trades use ATR × multiplier − buffer for stops and ATR × multiplier + buffer for targets (mirrored for shorts).
- Trailing stop – When
UseTrailingStop is enabled, the stop price is adjusted on every finished candle using the configured point distance (TrailingStop).
- Hard exits – If price reaches the stop-loss or take-profit intrabar, the position is closed immediately and no opposite entry is triggered.
Position sizing
- Static mode – When
UseStaticVolume is true, trades are placed with the fixed StaticVolume parameter.
- Dynamic mode – Otherwise the strategy derives an approximate size from the portfolio's current value and
RiskPercent, falling back to the base Volume if portfolio or price data are unavailable.
Parameters
| Group |
Parameter |
Description |
| Entries |
UseMa |
Enable moving average confirmation. |
| Entries |
MaMode |
Selects the MA combination (fast/medium, medium/slow, combined, etc.). |
| Indicators |
Ma1Period, Ma2Period, Ma3Period |
Periods of the three moving averages. |
| Indicators |
Ma1BufferPeriod, Ma2BufferPeriod |
ATR periods used as buffer for MA cross checks. |
| Indicators |
Ma1Method, Ma2Method, Ma3Method |
Moving average calculation types (SMA, EMA, SMMA, LWMA). |
| Indicators |
Ma1Price, Ma2Price, Ma3Price |
Applied price for each moving average. |
| Entries |
UseRsi |
Enable RSI confirmation. |
| Indicators |
RsiPeriod |
RSI calculation period. |
| Entries |
RsiMode |
RSI confirmation mode (overbought/oversold, trend, combined, zone). |
| Entries |
RsiBuyLevel, RsiSellLevel |
Thresholds for oversold/overbought logic. |
| Entries |
RsiBuyZone, RsiSellZone |
Zone thresholds for mode 4. |
| Entries |
UseStochastic |
Enable stochastic confirmation. |
| Indicators |
StochasticK, StochasticD, StochasticSlowing |
K/D/slow parameters. |
| Entries |
UseStochasticHighLow |
Require stochastic to break configured high/low bands. |
| Entries |
StochasticHigh, StochasticLow |
Upper and lower stochastic thresholds. |
| Entries |
UseSar |
Enable parabolic SAR confirmation. |
| Indicators |
SarStep, SarMax |
SAR acceleration settings. |
| Entries |
UseMacd |
Enable zero-lag MACD confirmation. |
| Indicators |
MacdFast, MacdSlow, MacdSignal |
MACD parameters. |
| Indicators |
MacdPrice |
Applied price for MACD. |
| Entries |
MacdMode |
MACD confirmation mode. |
| Risk |
UseTrailingStop, TrailingStop |
Trailing stop toggle and distance (in points). |
| Risk |
UseStaticVolume, StaticVolume, RiskPercent |
Position sizing controls. |
| Risk |
AtrPeriod, AtrMultiplier |
ATR settings for risk management. |
| Exits |
AutoClose |
Enable exit consensus logic. |
| Exits |
OpenOppositeAfterClose |
Flip into the opposite direction after a signal-based exit. |
| Exits |
UseMaClosing, MaModeClosing |
Moving average exit configuration. |
| Exits |
UseMacdClosing, MacdModeClosing |
MACD exit configuration. |
| Exits |
UseRsiClosing, RsiModeClosing |
RSI exit configuration. |
| Exits |
UseStochasticClosing |
Stochastic exit toggle. |
| Exits |
UseSarClosing |
SAR exit toggle. |
| General |
CandleType |
Primary timeframe (default 5-minute candles). |
Notes
- The strategy operates one net position at a time (long, short or flat), mirroring MetaTrader's "maximum same orders" restriction with a simpler StockSharp-friendly approach.
- Pending opposite entries are queued only for signal-based exits and are skipped if a stop-loss or take-profit closes the trade.
- Because account margin requirements are broker-specific, the dynamic position sizing uses an approximate risk-based formula; verify the resulting volume before live deployment.
- Ensure that the zero-lag MACD and ATR indicators have sufficient warm-up history before expecting trades, just as in the original EA.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Combo EA: Triple EMA confirmation with RSI filter and ATR stops.
/// </summary>
public class ComboEa4FsfrUpdated5Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public ComboEa4FsfrUpdated5Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 8)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 21)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, rsi, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var close = candle.ClosePrice;
if (Position > 0)
{
if (fastVal < slowVal && _prevFast >= _prevSlow)
{
SellMarket();
_entryPrice = 0;
}
else if (close <= _entryPrice - atrVal * 2m)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
BuyMarket();
_entryPrice = 0;
}
else if (close >= _entryPrice + atrVal * 2m)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50)
{
_entryPrice = close;
BuyMarket();
}
else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50)
{
_entryPrice = close;
SellMarket();
}
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
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, RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class combo_ea4_fsfr_updated5_strategy(Strategy):
"""
Combo EA: Triple EMA confirmation with RSI filter and ATR stops.
"""
def __init__(self):
super(combo_ea4_fsfr_updated5_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._fast_ema_length = self.Param("FastEmaLength", 8) \
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators")
self._slow_ema_length = self.Param("SlowEmaLength", 21) \
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(combo_ea4_fsfr_updated5_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(combo_ea4_fsfr_updated5_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_ema_length.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_ema_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ema, slow_ema, rsi, atr, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def on_process(self, candle, fast_val, slow_val, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0.0 or self._prev_slow == 0.0 or atr_val <= 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
if self.Position > 0:
if (fast_val < slow_val and self._prev_fast >= self._prev_slow) or close <= self._entry_price - atr_val * 2:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if (fast_val > slow_val and self._prev_fast <= self._prev_slow) or close >= self._entry_price + atr_val * 2:
self.BuyMarket()
self._entry_price = 0.0
if self.Position == 0:
if fast_val > slow_val and self._prev_fast <= self._prev_slow and rsi_val > 50:
self._entry_price = close
self.BuyMarket()
elif fast_val < slow_val and self._prev_fast >= self._prev_slow and rsi_val < 50:
self._entry_price = close
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return combo_ea4_fsfr_updated5_strategy()