This strategy replicates the "rainbow" moving average system from the original MQL expert.
It uses eleven exponential moving averages together with MACD and ADX filters.
How it works
Calculate EMA(2), EMA(3), EMA(5), EMA(8), EMA(13), EMA(21), EMA(34), EMA(55), EMA(89), EMA(144) and EMA(233) on close prices.
Calculate MACD (Fast, Slow, Signal) and use the signal line.
Calculate ADX to measure trend strength.
Buy when:
MACD signal line is above zero.
All EMAs are strictly ascending (each faster EMA above the slower one).
ADX value is above the threshold.
Sell when:
MACD signal line is below zero.
All EMAs are strictly descending.
ADX value is above the threshold.
Positions are reversed when an opposite signal appears.
Parameters
Name
Description
FastMacd
Fast EMA period for MACD.
SlowMacd
Slow EMA period for MACD.
SignalPeriod
Signal line period for MACD.
AdxPeriod
Period for ADX indicator.
AdxThreshold
Minimum ADX value required to trade.
CandleType
Candle timeframe used for calculations.
Notes
Strategy uses market orders via BuyMarket and SellMarket.
Only one position is kept at a time; an opposite signal reverses the position.
This is a direct conversion of the original MQL strategy without the optional martingale logic.
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>
/// EMA rainbow trend following strategy.
/// </summary>
public class MagnaRapaxCopperStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MagnaRapaxCopperStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 13)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}