This strategy is a StockSharp port of the MetaTrader expert Exp_AbsolutelyNoLagLwma_Digit_NN3_MMRec. It keeps the original multi-timeframe architecture built around the "AbsolutelyNoLagLWMA" indicator and reproduces the money-management recovery rules (MMRec). Three independent modules (A/B/C) monitor 12-hour, 4-hour and 2-hour candles respectively. Every module can open and close its own position slice while the strategy tracks the combined exposure.
Each module computes a double weighted moving average (WMA of a WMA) of a configurable price source. The smoothed value is rounded to the requested number of digits, exactly as in the MQL indicator. A change in the slope of the smoothed line (value rises after falling or vice versa) is treated as a direction switch and generates trading actions for that module.
Trading Rules
Wait for a finished candle from the module timeframe.
Read the applied price (close, open, median, typical, etc.).
Process the price through the primary WMA and feed its result into a secondary WMA to emulate "AbsolutelyNoLagLWMA".
Round the smoothed value to the configured number of digits and compare it with the previous value.
Upward slope (value > previous):
Close the module short leg if short exits are enabled.
If long entries are enabled and no long exposure is active, open a long position using the current module volume.
Recalculate stop-loss and take-profit levels (expressed in price steps) for the long slice.
Downward slope (value < previous):
Close the module long leg if long exits are enabled.
If short entries are enabled and no short exposure is active, open a short position.
Update the protective levels for the short slice.
On every candle the module checks whether the candle's high/low pierced the current stop-loss or take-profit level. If touched, the position slice is flattened at that price and the trade result is recorded for the money-management logic.
Money management keeps a queue of the most recent trade results for each direction. When the last N trades (where N equals the loss trigger) were losing, the next order uses the reduced volume; otherwise the normal volume is used. Losing trade detection is based on the entry price that was stored when the slice was opened and the exit price (stop/target/close) used to flatten it.
The strategy uses market orders for entries and exits and assumes fills at the candle close for signals and at the protective price for stop/target exits.
Parameters
Every module owns an identical set of parameters. Defaults correspond to the source MQL expert.
Parameter
Description
ACandleType / BCandleType / CCandleType
Time frame of the module candles (12h / 4h / 2h by default).
ALength / BLength / CLength
Length of the AbsolutelyNoLagLWMA smoothing (applied to both WMAs).
AAppliedPrice / BAppliedPrice / CAppliedPrice
Price source used in the indicator (close, open, high, low, median, typical, weighted, simple, quarter, TrendFollow1, TrendFollow2, Demark).
Flags controlling whether the module is allowed to open/close long or short slices.
ASmallVolume, ANormalVolume
Reduced and normal order volumes. The same values are reused for short trades.
ABuyLossTrigger, ASellLossTrigger
Number of consecutive losing trades that activates the reduced volume for longs/shorts.
AStopLossPoints, ATakeProfitPoints
Protective levels expressed in price steps for the module slice. Identical parameters exist for modules B and C.
The money-management queues are reset when the corresponding trigger is set to zero. The price-step calculations rely on Security.Step; if the security does not expose it, a step of 1 is used.
Notes
Each module manages its own internal position volume; therefore, different modules can be long or short simultaneously. The main strategy position is the sum of all module slices.
Stop-loss and take-profit levels are checked on every finished candle using the candle's high/low to detect breaches.
The AppliedPrices enumeration matches the original indicator options, including both TrendFollow formulas and the DeMark variant.
The strategy does not add indicators to the chart; it relies on the high-level Bind API and keeps indicator instances private to each module as required by the guidelines.
The logic closes and opens trades only when the slope changes direction, which prevents duplicated orders on consecutive bars with the same trend state.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Double WMA crossover strategy with money management recovery.
/// Uses fast and slow weighted moving averages and trades on crossovers.
/// </summary>
public class AbsolutelyNoLagLwmaDigitMmRecStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private int _prevSignal;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public AbsolutelyNoLagLwmaDigitMmRecStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastLength = Param(nameof(FastLength), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Length", "Fast WMA period", "Indicators");
_slowLength = Param(nameof(SlowLength), 14)
.SetGreaterThanZero()
.SetDisplay("Slow Length", "Slow WMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSignal = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSignal = 0;
var fastWma = new WeightedMovingAverage { Length = FastLength };
var slowWma = new WeightedMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastWma, slowWma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastWma);
DrawIndicator(area, slowWma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var signal = fastVal > slowVal ? 1 : fastVal < slowVal ? -1 : _prevSignal;
if (signal == _prevSignal)
return;
var oldSignal = _prevSignal;
_prevSignal = signal;
if (signal == 1 && oldSignal <= 0)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (signal == -1 && oldSignal >= 0)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class absolutely_no_lag_lwma_digit_mm_rec_strategy(Strategy):
def __init__(self):
super(absolutely_no_lag_lwma_digit_mm_rec_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_length = self.Param("FastLength", 5) \
.SetDisplay("Fast Length", "Fast WMA period", "Indicators")
self._slow_length = self.Param("SlowLength", 14) \
.SetDisplay("Slow Length", "Slow WMA period", "Indicators")
self._prev_signal = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastLength(self):
return self._fast_length.Value
@property
def SlowLength(self):
return self._slow_length.Value
def OnReseted(self):
super(absolutely_no_lag_lwma_digit_mm_rec_strategy, self).OnReseted()
self._prev_signal = 0
def OnStarted2(self, time):
super(absolutely_no_lag_lwma_digit_mm_rec_strategy, self).OnStarted2(time)
self._prev_signal = 0
fast_wma = WeightedMovingAverage()
fast_wma.Length = self.FastLength
slow_wma = WeightedMovingAverage()
slow_wma.Length = self.SlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_wma, slow_wma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_wma)
self.DrawIndicator(area, slow_wma)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if fv > sv:
signal = 1
elif fv < sv:
signal = -1
else:
signal = self._prev_signal
if signal == self._prev_signal:
return
old_signal = self._prev_signal
self._prev_signal = signal
if signal == 1 and old_signal <= 0:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif signal == -1 and old_signal >= 0:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return absolutely_no_lag_lwma_digit_mm_rec_strategy()