Ver no GitHub

MultiStrategyEA v1.2 (StockSharp Port)

Overview

This strategy is a high-level StockSharp port of the MetaTrader expert advisor MultiStrategyEA v1.2. The original EA aggregates seven oscillators and manages multiple grids of orders. The StockSharp version focuses on the signal generation aspect and trades a single net position that is driven by a consensus between the indicator modules. Order management, money management profiles, grids and recovery features from the MT5 code are intentionally omitted to keep the implementation aligned with StockSharp's high-level API and to maintain clarity.

Modules

The strategy evaluates the following indicator modules on the selected timeframe:

  1. Acceleration/Deceleration Oscillator (AC) – Uses the difference between the Awesome Oscillator and its 5-period SMA. Requires the current value to exceed the AcLevel threshold and rise (or fall) relative to the previous reading.
  2. Average Directional Index (ADX) – Confirms trends when the ADX strength is above AdxTrendLevel and the directional movement that dominates also exceeds AdxDirectionalLevel.
  3. Awesome Oscillator (AO) – Detects momentum bursts when the oscillator crosses beyond AoLevel and continues in the same direction.
  4. DeMarker – Flags possible reversals when the oscillator leaves oversold (100 - DeMarkerThreshold) or overbought (DeMarkerThreshold) territories.
  5. Force Index + Bollinger Bands – Requires the price to touch a Bollinger band while the Force Index (scaled in the port exactly as in the MT5 script) confirms momentum beyond ForceConfirmationLevel. An optional BandDistanceFilter rejects signals when the band width, measured in pips, is too narrow or too wide.
  6. Money Flow Index (MFI) – Similar to DeMarker; reacts to overbought and oversold zones determined by MfiThreshold.
  7. MACD + Stochastic – Demands that both MACD (MacdLevel) and Stochastic (StochasticLevel) confirm the same directional bias. MACD must be above/below the level and above/below its signal line. Stochastic must be over/under the threshold and above/below the signal line.

Each module contributes a buy, sell or neutral vote based on the latest finished candle.

Consensus Logic

  • When TradeAllStrategies is true (default), the strategy waits until at least RequiredConfirmations bullish votes with zero bearish votes appear before entering long. The same logic is mirrored for shorts.
  • When TradeAllStrategies is false, a single bullish or bearish vote is enough to trade.
  • If CloseInReverse is enabled, the strategy immediately closes an opposite position before opening a new one.

The implementation operates only one aggregate position and does not attempt to recreate the original EA's per-module order bookkeeping.

Risk Management

  • StopLossPips and TakeProfitPips translate to price offsets using the instrument's PriceStep. For symbols with 3 or 5 decimal digits the pip size is automatically multiplied by 10, mimicking FX pip behaviour.
  • Stops and targets are checked on every finished candle using candle highs/lows. When either threshold is reached the entire position is closed.

Differences from the MT5 Expert Advisor

  • No grid, martingale or recovery features. Position sizing is fixed via the Volume parameter.
  • Close-signal variants (CloseOrdersType options in MT5) are not implemented; exits rely on global stop-loss/take-profit or the optional reverse-on-opposite-signal behaviour.
  • Indicator configuration in StockSharp mirrors the main idea of each module but supports only the most common interpretation instead of the many mode enumerations found in the original script.
  • Money-management blocks (auto lot, account protection, symbol-specific pip valuation) are out of scope for this high-level port.

Parameters

Parameter Description
CandleType Data series used by every indicator module.
Volume Net volume traded when a consensus signal appears.
TradeAllStrategies Enables consensus voting; otherwise any single vote triggers a trade.
RequiredConfirmations Number of matching bullish or bearish votes needed when consensus is enabled.
CloseInReverse Close an existing position before opening the opposite side.
StopLossPips / TakeProfitPips Protective stop and profit target measured in pips.
UseAcModule, AcLevel Toggle and threshold for the Accelerator Oscillator module.
UseAdxModule, AdxPeriod, AdxTrendLevel, AdxDirectionalLevel ADX configuration.
UseAoModule, AoLevel Awesome Oscillator configuration.
UseDeMarkerModule, DeMarkerPeriod, DeMarkerThreshold DeMarker oscillator settings.
UseForceBollingerModule, BollingerPeriod, BollingerDeviation, ForceConfirmationLevel, BandDistanceFilter Force Index + Bollinger band filter settings.
UseMfiModule, MfiPeriod, MfiThreshold Money Flow Index settings.
UseMacdStochasticModule, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, MacdLevel, StochasticPeriod, StochasticSignalPeriod, StochasticSlowing, StochasticLevel MACD and Stochastic combo configuration.

Usage Notes

  1. Attach the strategy to an instrument with sufficient historical data for all indicators to form.
  2. Configure the timeframe and module thresholds to match the desired market conditions. The defaults replicate the values used in the MT5 EA inputs.
  3. The consensus logic is sensitive to how many modules are active. If you disable modules, consider lowering RequiredConfirmations accordingly.
  4. Because the strategy trades a single net position, it is suitable for use inside Designer, Runner or other StockSharp high-level environments without additional portfolio routing.

Disclaimer

This port focuses on signal parity rather than reproducing the entire risk and money management stack of the original MetaTrader expert. The simplified architecture makes it easier to test, extend, or integrate into StockSharp-based solutions, but results will differ from the MT5 version when complex features (grids, recovery lots, partial closes) were the main performance driver.

namespace StockSharp.Samples.Strategies;

using System;

using StockSharp.Algo;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Simplified port of the MetaTrader expert advisor "MultiStrategyEA v1.2".
/// Combines multiple oscillators (RSI, Stochastic, MACD, Bollinger, ADX)
/// and requires a configurable number of bullish or bearish confirmations before entering a trade.
/// </summary>
public class MultiEaV12Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _requiredConfirmations;

	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpper;
	private readonly StrategyParam<decimal> _rsiLower;

	private readonly StrategyParam<int> _stochKPeriod;
	private readonly StrategyParam<int> _stochDPeriod;
	private readonly StrategyParam<decimal> _stochUpper;
	private readonly StrategyParam<decimal> _stochLower;

	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerDeviation;

	private readonly StrategyParam<int> _adxPeriod;
	private readonly StrategyParam<decimal> _adxTrendLevel;

	private readonly StrategyParam<int> _macdFast;
	private readonly StrategyParam<int> _macdSlow;
	private readonly StrategyParam<int> _macdSignal;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RequiredConfirmations { get => _requiredConfirmations.Value; set => _requiredConfirmations.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public decimal RsiUpper { get => _rsiUpper.Value; set => _rsiUpper.Value = value; }
	public decimal RsiLower { get => _rsiLower.Value; set => _rsiLower.Value = value; }
	public int StochKPeriod { get => _stochKPeriod.Value; set => _stochKPeriod.Value = value; }
	public int StochDPeriod { get => _stochDPeriod.Value; set => _stochDPeriod.Value = value; }
	public decimal StochUpper { get => _stochUpper.Value; set => _stochUpper.Value = value; }
	public decimal StochLower { get => _stochLower.Value; set => _stochLower.Value = value; }
	public int BollingerPeriod { get => _bollingerPeriod.Value; set => _bollingerPeriod.Value = value; }
	public decimal BollingerDeviation { get => _bollingerDeviation.Value; set => _bollingerDeviation.Value = value; }
	public int AdxPeriod { get => _adxPeriod.Value; set => _adxPeriod.Value = value; }
	public decimal AdxTrendLevel { get => _adxTrendLevel.Value; set => _adxTrendLevel.Value = value; }
	public int MacdFast { get => _macdFast.Value; set => _macdFast.Value = value; }
	public int MacdSlow { get => _macdSlow.Value; set => _macdSlow.Value = value; }
	public int MacdSignal { get => _macdSignal.Value; set => _macdSignal.Value = value; }

	public MultiEaV12Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_requiredConfirmations = Param(nameof(RequiredConfirmations), 3)
			.SetDisplay("Required Confirmations", "Number of modules required for entry", "Consensus");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI length", "RSI");

		_rsiUpper = Param(nameof(RsiUpper), 65m)
			.SetDisplay("RSI Upper", "Overbought level", "RSI");

		_rsiLower = Param(nameof(RsiLower), 35m)
			.SetDisplay("RSI Lower", "Oversold level", "RSI");

		_stochKPeriod = Param(nameof(StochKPeriod), 10)
			.SetDisplay("Stochastic %K", "%K period", "Stochastic");

		_stochDPeriod = Param(nameof(StochDPeriod), 3)
			.SetDisplay("Stochastic %D", "%D period", "Stochastic");

		_stochUpper = Param(nameof(StochUpper), 70m)
			.SetDisplay("Stoch Upper", "Overbought", "Stochastic");

		_stochLower = Param(nameof(StochLower), 30m)
			.SetDisplay("Stoch Lower", "Oversold", "Stochastic");

		_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
			.SetDisplay("Bollinger Period", "BB length", "Bollinger");

		_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
			.SetDisplay("Bollinger Deviation", "BB width", "Bollinger");

		_adxPeriod = Param(nameof(AdxPeriod), 14)
			.SetDisplay("ADX Period", "ADX length", "ADX");

		_adxTrendLevel = Param(nameof(AdxTrendLevel), 20m)
			.SetDisplay("ADX Trend Level", "Min ADX for trend", "ADX");

		_macdFast = Param(nameof(MacdFast), 12)
			.SetDisplay("MACD Fast", "Fast EMA period", "MACD");

		_macdSlow = Param(nameof(MacdSlow), 26)
			.SetDisplay("MACD Slow", "Slow EMA period", "MACD");

		_macdSignal = Param(nameof(MacdSignal), 9)
			.SetDisplay("MACD Signal", "Signal line period", "MACD");
	}

	/// <inheritdoc />
	public override System.Collections.Generic.IEnumerable<(StockSharp.BusinessEntities.Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var stochastic = new StochasticOscillator();
		stochastic.K.Length = StochKPeriod;
		stochastic.D.Length = StochDPeriod;

		var bollinger = new BollingerBands { Length = BollingerPeriod, Width = BollingerDeviation };

		var adx = new AverageDirectionalIndex { Length = AdxPeriod };

		var macd = new MovingAverageConvergenceDivergenceSignal();
		macd.Macd.ShortMa.Length = MacdFast;
		macd.Macd.LongMa.Length = MacdSlow;
		macd.SignalMa.Length = MacdSignal;

		var subscription = SubscribeCandles(CandleType);

		subscription
			.BindEx(rsi, stochastic, bollinger, adx, macd, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, bollinger);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue rsiVal, IIndicatorValue stochVal, IIndicatorValue bbVal, IIndicatorValue adxVal, IIndicatorValue macdVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!rsiVal.IsFinal || !stochVal.IsFinal || !bbVal.IsFinal || !adxVal.IsFinal || !macdVal.IsFinal)
			return;

		if (!rsiVal.IsFormed || !stochVal.IsFormed || !bbVal.IsFormed || !adxVal.IsFormed || !macdVal.IsFormed)
			return;

		var rsi = rsiVal.GetValue<decimal>();
		var stoch = (StochasticOscillatorValue)stochVal;
		var stochK = stoch.K ?? 50m;
		var bb = (BollingerBandsValue)bbVal;
		var bbUpper = bb.UpBand ?? candle.ClosePrice;
		var bbLower = bb.LowBand ?? candle.ClosePrice;
		var adxTyped = (AverageDirectionalIndexValue)adxVal;
		var adxMain = adxTyped.MovingAverage ?? 0m;
		var adxPlus = adxTyped.Dx.Plus ?? 0m;
		var adxMinus = adxTyped.Dx.Minus ?? 0m;
		var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdVal;
		var macdLine = macdTyped.Macd ?? 0m;
		var macdSignalLine = macdTyped.Signal ?? 0m;

		var close = candle.ClosePrice;

		// Count bullish and bearish signals from each module
		var bullish = 0;
		var bearish = 0;

		// Module 1: RSI
		if (rsi < RsiLower) bullish++;
		else if (rsi > RsiUpper) bearish++;

		// Module 2: Stochastic
		if (stochK < StochLower) bullish++;
		else if (stochK > StochUpper) bearish++;

		// Module 3: Bollinger Bands
		if (close <= bbLower) bullish++;
		else if (close >= bbUpper) bearish++;

		// Module 4: ADX directional
		if (adxMain >= AdxTrendLevel)
		{
			if (adxPlus > adxMinus) bullish++;
			else if (adxMinus > adxPlus) bearish++;
		}

		// Module 5: MACD
		if (macdLine > macdSignalLine && macdLine > 0) bullish++;
		else if (macdLine < macdSignalLine && macdLine < 0) bearish++;

		var minConfirmations = RequiredConfirmations;

		// Enter on consensus
		if (bullish >= minConfirmations && bearish == 0 && Position <= 0)
		{
			BuyMarket();
		}
		else if (bearish >= minConfirmations && bullish == 0 && Position >= 0)
		{
			SellMarket();
		}
		// Exit when consensus breaks
		else if (Position > 0 && bearish >= 2)
		{
			SellMarket();
		}
		else if (Position < 0 && bullish >= 2)
		{
			BuyMarket();
		}
	}
}