Auf GitHub ansehen

MAMACD No Volatility Strategy

Overview

MAMACD No Volatility is a direct port of the MetaTrader 4 expert advisor MAMACD_novlt.mq4. The strategy combines three moving averages calculated on candle lows and closes with a MACD momentum filter. It waits until the fast EMA drops below (for longs) or rises above (for shorts) two low-based LWMA filters, arms a pending setup, and triggers an entry only after the MACD main line confirms the momentum shift.

Indicators

  • Fast EMA (FastEmaPeriod) calculated on close prices.
  • First LWMA (FirstLowWmaPeriod) calculated on low prices.
  • Second LWMA (SecondLowWmaPeriod) calculated on low prices.
  • MACD main line with fast period FastSignalEmaPeriod and slow period SlowEmaPeriod.

All indicators operate on the timeframe defined by CandleType (default: 5-minute candles).

Parameters

Parameter Description Default
FirstLowWmaPeriod Period of the first LWMA built from candle lows. 85
SecondLowWmaPeriod Period of the second LWMA built from candle lows. 75
FastEmaPeriod Period of the fast EMA built from candle closes. 5
SlowEmaPeriod Slow EMA period for the MACD calculation. 26
FastSignalEmaPeriod Fast EMA period for the MACD calculation. 15
StopLossPoints Stop-loss distance in price steps (0 disables the stop-loss). 15
TakeProfitPoints Take-profit distance in price steps (0 disables the take-profit). 15
TradeVolume Order volume used for market entries. 0.1
CandleType Candle series used for all indicators. 5-minute timeframe

Trading Rules

  1. Arm long setup: Fast EMA is below both LWMA filters.
  2. Arm short setup: Fast EMA is above both LWMA filters.
  3. Enter long:
    • Fast EMA crosses back above both LWMAs,
    • A long setup was armed previously,
    • MACD main line is positive or has increased compared to the previous value,
    • Current net position is not long.
  4. Enter short:
    • Fast EMA crosses back below both LWMAs,
    • A short setup was armed previously,
    • MACD main line is negative or has decreased compared to the previous value,
    • Current net position is not short.
  5. Risk management: Optional take-profit and stop-loss are applied automatically through the built-in protection service.

The strategy does not implement a dedicated exit signal; positions are managed by the configured stop-loss/take-profit levels or manual intervention.

Notes

  • The MACD confirmation replicates the MQL logic: the main line must be either above zero or rising (for longs) or below zero or falling (for shorts).
  • The LWMA calculations use candle low prices to reflect the original indicator configuration.
  • Volume scaling mirrors the original EA by using the TradeVolume parameter for every order.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;

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

using StockSharp.Algo;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that replicates the MAMACD_novlt MetaTrader expert advisor.
/// It prepares long or short setups when a fast EMA is below or above two LWMA values
/// built from candle lows, and then confirms entries with the MACD main line momentum.
/// </summary>
public class MamacdNovltStrategy : Strategy
{
	private readonly StrategyParam<int> _firstLowWmaPeriod;
	private readonly StrategyParam<int> _secondLowWmaPeriod;
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<int> _fastSignalEmaPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;
	private readonly StrategyParam<DataType> _candleType;

	private bool _isLongSetupPrepared;
	private bool _isShortSetupPrepared;
	private decimal? _previousMacd;

	/// <summary>
	/// Period of the first LWMA calculated on low prices.
	/// </summary>
	public int FirstLowWmaPeriod
	{
		get => _firstLowWmaPeriod.Value;
		set => _firstLowWmaPeriod.Value = value;
	}

	/// <summary>
	/// Period of the second LWMA calculated on low prices.
	/// </summary>
	public int SecondLowWmaPeriod
	{
		get => _secondLowWmaPeriod.Value;
		set => _secondLowWmaPeriod.Value = value;
	}

	/// <summary>
	/// Period of the fast EMA calculated on close prices.
	/// </summary>
	public int FastEmaPeriod
	{
		get => _fastEmaPeriod.Value;
		set => _fastEmaPeriod.Value = value;
	}

	/// <summary>
	/// Slow period of the MACD indicator.
	/// </summary>
	public int SlowEmaPeriod
	{
		get => _slowEmaPeriod.Value;
		set => _slowEmaPeriod.Value = value;
	}

	/// <summary>
	/// Fast period of the MACD indicator.
	/// </summary>
	public int FastSignalEmaPeriod
	{
		get => _fastSignalEmaPeriod.Value;
		set => _fastSignalEmaPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in absolute price units.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in absolute price units.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Candle type used for indicator calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes strategy parameters that mirror the original MetaTrader inputs.
	/// </summary>
	public MamacdNovltStrategy()
	{
		_firstLowWmaPeriod = Param(nameof(FirstLowWmaPeriod), 85)
			.SetGreaterThanZero()
			.SetDisplay("First LWMA Period", "First LWMA period on lows", "Indicators");

		_secondLowWmaPeriod = Param(nameof(SecondLowWmaPeriod), 75)
			.SetGreaterThanZero()
			.SetDisplay("Second LWMA Period", "Second LWMA period on lows", "Indicators");

		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA Period", "Fast EMA period on closes", "Indicators");

		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("MACD Slow Period", "Slow EMA period for MACD", "Indicators");

		_fastSignalEmaPeriod = Param(nameof(FastSignalEmaPeriod), 15)
			.SetGreaterThanZero()
			.SetDisplay("MACD Fast Period", "Fast EMA period for MACD", "Indicators");

		_stopLossPoints = Param(nameof(StopLossPoints), 500)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss distance", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit distance", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return new[] { (Security, CandleType) };
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_isLongSetupPrepared = false;
		_isShortSetupPrepared = false;
		_previousMacd = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		var fastCloseEma = new EMA { Length = FastEmaPeriod };
		var firstLowWma = new WeightedMovingAverage { Length = FirstLowWmaPeriod };
		var secondLowWma = new WeightedMovingAverage { Length = SecondLowWmaPeriod };

		var macd = new MovingAverageConvergenceDivergence();
		macd.ShortMa.Length = FastSignalEmaPeriod;
		macd.LongMa.Length = SlowEmaPeriod;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastCloseEma, firstLowWma, secondLowWma, macd, ProcessCandle)
			.Start();

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

		var takeProfitUnit = TakeProfitPoints > 0 ? new Unit(TakeProfitPoints, UnitTypes.Absolute) : null;
		var stopLossUnit = StopLossPoints > 0 ? new Unit(StopLossPoints, UnitTypes.Absolute) : null;
		StartProtection(takeProfitUnit, stopLossUnit);

		base.OnStarted2(time);
	}

	private void ProcessCandle(ICandleMessage candle, decimal ema, decimal firstLwma, decimal secondLwma, decimal macdLine)
	{
		if (candle.State != CandleStates.Finished)
			return;

		// Track when the fast EMA moves below both LWMA values to arm the long setup.
		if (ema < firstLwma && ema < secondLwma)
		{
			_isLongSetupPrepared = true;
		}

		// Track when the fast EMA moves above both LWMA values to arm the short setup.
		if (ema > firstLwma && ema > secondLwma)
		{
			_isShortSetupPrepared = true;
		}

		var hasPreviousMacd = _previousMacd.HasValue;
		var macdPrev = _previousMacd ?? macdLine;

		var macdBullish = macdLine > 0m || (hasPreviousMacd && macdLine > macdPrev);
		var macdBearish = macdLine < 0m || (hasPreviousMacd && macdLine < macdPrev);

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_previousMacd = macdLine;
			return;
		}

		// Enter long when EMA crosses above both LWMAs after being below, with bullish MACD
		if (ema > firstLwma && ema > secondLwma && _isLongSetupPrepared && macdBullish && Position <= 0)
		{
			if (Position < 0)
				BuyMarket(Math.Abs(Position));
			BuyMarket(Volume);
			_isLongSetupPrepared = false;
		}

		// Enter short when EMA crosses below both LWMAs after being above, with bearish MACD
		if (ema < firstLwma && ema < secondLwma && _isShortSetupPrepared && macdBearish && Position >= 0)
		{
			if (Position > 0)
				SellMarket(Position);
			SellMarket(Volume);
			_isShortSetupPrepared = false;
		}

		_previousMacd = macdLine;
	}
}