View on GitHub

BrainTrend2 + AbsolutelyNoLagLWMA Strategy

Overview

This strategy combines two independent modules that were originally implemented in MetaTrader 5: BrainTrend2_V2 and AbsolutelyNoLagLWMA. Each module analyses its own candle subscription and decides when to go long, go short or return to flat. The C# port keeps both decision flows intact and aggregates their desired exposure into a single StockSharp strategy.

  • BrainTrend2 module. Uses a trend-following colour state generated by the BrainTrend2 indicator. The state is derived from an ATR-based channel that flips whenever price violates the opposite boundary.
  • AbsolutelyNoLagLWMA module. Tracks the slope of a double-smoothed linear weighted moving average calculated on a selectable applied price.

Whenever one of the modules requests a new position direction, the strategy recomputes the combined target volume and sends market orders to reach that exposure. The default setup trades on H4 candles for both indicators, but each module can subscribe to a different timeframe.

Indicators

BrainTrend2

The BrainTrend2 indicator reconstructs the five-colour candle overlay from the original MQL file:

  • A triangularly weighted true range series (period parameter) is scaled by a coefficient of 0.7 to form a dynamic band (widcha).
  • A floating reference level (Emaxtra) follows the price extremes inside the current regime.
  • Whenever the low falls below Emaxtra - widcha the regime flips to bearish. Whenever the high exceeds Emaxtra + widcha the regime flips to bullish.
  • The resulting regime determines the colour: lime/teal (values 0 or 1) for bullish contexts, maroon/magenta (values 3 or 4) for bearish contexts, grey (value 2) before the indicator is ready.

The C# indicator keeps the same mechanics, including the triangular ATR estimation, so the generated colours match the MQL reference.

AbsolutelyNoLagLWMA

The AbsolutelyNoLagLWMA module applies two consecutive linearly weighted moving averages to the selected price series. The slope of the resulting line drives the colour values:

  • 2 (blue) – line is rising.
  • 1 (grey) – line is flat.
  • 0 (violet) – line is falling.

Both indicators expose IsFormed so the strategy waits until enough history is available before reacting to colours.

Trading Logic

The strategy maintains two internal targets, _brainTrendTarget and _lwmaTarget, representing the desired volume for each module. Every time one of the modules changes its target the strategy calls RebalancePosition to adjust the aggregated position to _brainTrendTarget + _lwmaTarget.

BrainTrend2 module

  • Evaluates the colour from the candle SignalBar periods ago (default 1) and the preceding colour to detect state transitions.
  • When the current colour is bullish (< 2) and the previous colour was not bullish (> 1), the module:
    • Closes any short exposure created by this module.
    • Opens a long position with BrainTrendVolume if long entries are enabled.
  • When the current colour is bearish (> 2) and the previous colour was not bearish (< 3), the module:
    • Closes any outstanding long exposure.
    • Opens a short position with BrainTrendVolume if short entries are enabled.

AbsolutelyNoLagLWMA module

  • Uses the same SignalBar logic but reacts to colour values 2 (up) and 0 (down).
  • When the colour becomes 2 and the previous colour was different:
    • Optional closing of short exposure (LwmaCloseShortAllowed).
    • Optional opening of a long position with LwmaVolume if LwmaBuyAllowed is true.
  • When the colour becomes 0 and the previous colour was different:
    • Optional closing of long exposure (LwmaCloseLongAllowed).
    • Optional opening of a short position with LwmaVolume if LwmaSellAllowed is true.

Each module only modifies its own target volume, so both can be active at the same time. For example, the BrainTrend2 module can stay long while the LWMA module scalps shorts around the core position.

Parameters

Name Description
BrainTrendAtrPeriod Period of the triangular ATR used by BrainTrend2.
BrainTrendSignalBar Number of finished candles used to shift BrainTrend2 signals. 1 means the strategy waits for the previous bar to close.
BrainTrendBuyAllowed / BrainTrendSellAllowed Enable or disable long/short entries for the BrainTrend2 module.
BrainTrendVolume Volume placed by the BrainTrend2 module when entering a position.
BrainTrendCandleType Candle type (timeframe) subscribed by the BrainTrend2 module.
LwmaLength Length of each weighted average in the AbsolutelyNoLagLWMA indicator.
LwmaSignalBar Signal offset for the LWMA module (same semantics as the BrainTrend module).
LwmaAppliedPrice Applied price used to build the LWMA (close, open, median, Demark, etc.).
LwmaBuyAllowed / LwmaSellAllowed Enable or disable long/short entries for the LWMA module.
LwmaCloseLongAllowed / LwmaCloseShortAllowed Allow the LWMA module to close opposite exposure when a signal inverts.
LwmaVolume Volume sent by the LWMA module when it opens a trade.
LwmaCandleType Candle type (timeframe) subscribed by the LWMA module.

Position Management and Orders

  • The strategy always uses market orders (BuyMarket / SellMarket) to reach the aggregated target volume.
  • Volumes from both modules are additive. For instance, if each module requests 1 lot in opposite directions the net position becomes zero, effectively hedging the account.
  • No automatic stop-loss or take-profit is recreated from the original Expert Advisor because those functions were broker-specific in MQL. Risk control can be added via StockSharp protections if required.
  • When both modules subscribe to different timeframes the strategy automatically subscribes to both candle streams and draws them on the chart area together with fills.

Notes

  • The implementation keeps indicator calculations self-contained, so no external indicator libraries are required.
  • SignalBar = 0 allows reacting to the most recent finished candle immediately, while larger offsets enforce additional confirmation.
  • BrainTrend2 requires at least AtrPeriod + 2 historical candles before emitting valid colours; AbsolutelyNoLagLWMA needs at least Length candles.
  • Because both modules share the same Strategy.Security, their trades are reconciled through the same portfolio connection just like in the original MT5 Expert Advisor that used different magic numbers.

Extending the Strategy

  • Add StockSharp risk protections (e.g., trailing stops) if fixed stops from the MQL version are required.
  • Tune BrainTrendVolume and LwmaVolume independently to emphasise either the trend-following or the mean-reversion behaviour.
  • Combine the modules with additional filters by observing the indicator values provided inside ProcessBrainTrend and ProcessLwma.
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>
/// BrainTrend2 + AbsolutelyNoLagLwma strategy (simplified). Uses ATR-based
/// trend detection combined with weighted MA direction for entries.
/// Implemented as EMA crossover with ATR channel filter.
/// </summary>
public class BrainTrend2AbsolutelyNoLagLwmaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaFastLength;
	private readonly StrategyParam<int> _emaSlowLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _atrCoefficient;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaFastLength
	{
		get => _emaFastLength.Value;
		set => _emaFastLength.Value = value;
	}

	public int EmaSlowLength
	{
		get => _emaSlowLength.Value;
		set => _emaSlowLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public decimal AtrCoefficient
	{
		get => _atrCoefficient.Value;
		set => _atrCoefficient.Value = value;
	}

	public BrainTrend2AbsolutelyNoLagLwmaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_emaFastLength = Param(nameof(EmaFastLength), 7)
			.SetGreaterThanZero()
			.SetDisplay("EMA Fast", "Fast EMA period", "Indicators");

		_emaSlowLength = Param(nameof(EmaSlowLength), 21)
			.SetGreaterThanZero()
			.SetDisplay("EMA Slow", "Slow EMA period", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Length", "ATR period", "Indicators");

		_atrCoefficient = Param(nameof(AtrCoefficient), 0.7m)
			.SetGreaterThanZero()
			.SetDisplay("ATR Coeff", "ATR multiplier for channel", "Logic");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var emaFast = new ExponentialMovingAverage { Length = EmaFastLength };
		var emaSlow = new ExponentialMovingAverage { Length = EmaSlowLength };

		decimal prevFast = 0, prevSlow = 0;
		var hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevFast = fastVal;
					prevSlow = slowVal;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastVal;
					prevSlow = slowVal;
					return;
				}

				var close = candle.ClosePrice;

				// Fast EMA crosses above slow - bullish
				var bullishCross = prevFast <= prevSlow && fastVal > slowVal;
				// Fast EMA crosses below slow - bearish
				var bearishCross = prevFast >= prevSlow && fastVal < slowVal;

				if (bullishCross && Position <= 0)
					BuyMarket();
				else if (bearishCross && Position >= 0)
					SellMarket();

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

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