Стратегия MAMACD No Volatility
Описание
MAMACD No Volatility — прямой порт советника MetaTrader 4 MAMACD_novlt.mq4. Стратегия объединяет три скользящие средние, рассчитанные по минимумам и ценам закрытия свечей, с фильтром импульса MACD. Сначала быстрая EMA должна опуститься ниже (для покупки) или подняться выше (для продажи) двух LWMA, построенных по минимумам. После этого формируется «заряженный» сигнал, который исполняется только тогда, когда основная линия MACD подтверждает изменение импульса.
Индикаторы
- Быстрая EMA (
FastEmaPeriod) по ценам закрытия.
- LWMA 1 (
FirstLowWmaPeriod) по минимумам свечей.
- LWMA 2 (
SecondLowWmaPeriod) по минимумам свечей.
- Основная линия MACD с быстрым периодом
FastSignalEmaPeriod и медленным периодом SlowEmaPeriod.
Все индикаторы работают на таймфрейме, задаваемом параметром CandleType (по умолчанию 5-минутные свечи).
Параметры
| Параметр |
Описание |
Значение по умолчанию |
FirstLowWmaPeriod |
Период первой LWMA по минимумам. |
85 |
SecondLowWmaPeriod |
Период второй LWMA по минимумам. |
75 |
FastEmaPeriod |
Период быстрой EMA по ценам закрытия. |
5 |
SlowEmaPeriod |
Медленный период для расчёта MACD. |
26 |
FastSignalEmaPeriod |
Быстрый период для расчёта MACD. |
15 |
StopLossPoints |
Размер стоп-лосса в шагах цены (0 — без стоп-лосса). |
15 |
TakeProfitPoints |
Размер тейк-профита в шагах цены (0 — без тейк-профита). |
15 |
TradeVolume |
Объём заявки при входе в рынок. |
0.1 |
CandleType |
Таймфрейм для расчёта индикаторов. |
5 минут |
Правила торговли
- Подготовка покупки: быстрая EMA находится ниже обеих LWMA.
- Подготовка продажи: быстрая EMA находится выше обеих LWMA.
- Вход в лонг:
- быстрая EMA вновь поднимается выше обеих LWMA,
- ранее был подготовлен сигнал на покупку,
- основная линия MACD положительна или выросла относительно предыдущего значения,
- текущая позиция не лонговая.
- Вход в шорт:
- быстрая EMA вновь опускается ниже обеих LWMA,
- ранее был подготовлен сигнал на продажу,
- основная линия MACD отрицательна или снизилась относительно предыдущего значения,
- текущая позиция не шортовая.
- Управление рисками: стоп-лосс и тейк-профит задаются через встроенную защиту. Если параметр равен нулю, соответствующий уровень не используется.
Выход из позиции осуществляется сработавшими защитными уровнями или вручную — дополнительных условий закрытия стратегия не задаёт.
Примечания
- Проверка MACD точно повторяет оригинальную логику: для покупок линия должна быть выше нуля или расти, для продаж — ниже нуля или снижаться.
- LWMA рассчитываются по минимумам свечей, как и в исходном советнике.
- Параметр
TradeVolume напрямую определяет объём каждой рыночной сделки, что соответствует поведению MQL-версии.
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, UnitTypes, Unit
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import (
ExponentialMovingAverage,
WeightedMovingAverage,
MovingAverageConvergenceDivergence,
)
class mamacd_novlt_strategy(Strategy):
def __init__(self):
super(mamacd_novlt_strategy, self).__init__()
self._first_low_wma_period = self.Param("FirstLowWmaPeriod", 85) \
.SetDisplay("First LWMA Period", "First LWMA period on lows", "Indicators")
self._second_low_wma_period = self.Param("SecondLowWmaPeriod", 75) \
.SetDisplay("Second LWMA Period", "Second LWMA period on lows", "Indicators")
self._fast_ema_period = self.Param("FastEmaPeriod", 5) \
.SetDisplay("Fast EMA Period", "Fast EMA period on closes", "Indicators")
self._slow_ema_period = self.Param("SlowEmaPeriod", 26) \
.SetDisplay("MACD Slow Period", "Slow EMA period for MACD", "Indicators")
self._fast_signal_ema_period = self.Param("FastSignalEmaPeriod", 15) \
.SetDisplay("MACD Fast Period", "Fast EMA period for MACD", "Indicators")
self._stop_loss_points = self.Param("StopLossPoints", 500) \
.SetDisplay("Stop Loss", "Stop-loss distance", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 500) \
.SetDisplay("Take Profit", "Take-profit distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._is_long_setup_prepared = False
self._is_short_setup_prepared = False
self._previous_macd = None
@property
def FirstLowWmaPeriod(self):
return self._first_low_wma_period.Value
@property
def SecondLowWmaPeriod(self):
return self._second_low_wma_period.Value
@property
def FastEmaPeriod(self):
return self._fast_ema_period.Value
@property
def SlowEmaPeriod(self):
return self._slow_ema_period.Value
@property
def FastSignalEmaPeriod(self):
return self._fast_signal_ema_period.Value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(mamacd_novlt_strategy, self).OnStarted2(time)
fast_close_ema = ExponentialMovingAverage()
fast_close_ema.Length = self.FastEmaPeriod
first_low_wma = WeightedMovingAverage()
first_low_wma.Length = self.FirstLowWmaPeriod
second_low_wma = WeightedMovingAverage()
second_low_wma.Length = self.SecondLowWmaPeriod
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.FastSignalEmaPeriod
macd.LongMa.Length = self.SlowEmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_close_ema, first_low_wma, second_low_wma, macd, self.ProcessCandle).Start()
tp = Unit(self.TakeProfitPoints, UnitTypes.Absolute) if self.TakeProfitPoints > 0 else None
sl = Unit(self.StopLossPoints, UnitTypes.Absolute) if self.StopLossPoints > 0 else None
self.StartProtection(tp, sl)
def ProcessCandle(self, candle, ema, first_lwma, second_lwma, macd_line):
if candle.State != CandleStates.Finished:
return
ema = float(ema)
first_lwma = float(first_lwma)
second_lwma = float(second_lwma)
macd_line = float(macd_line)
if ema < first_lwma and ema < second_lwma:
self._is_long_setup_prepared = True
if ema > first_lwma and ema > second_lwma:
self._is_short_setup_prepared = True
has_prev = self._previous_macd is not None
macd_prev = self._previous_macd if has_prev else macd_line
macd_bullish = macd_line > 0 or (has_prev and macd_line > macd_prev)
macd_bearish = macd_line < 0 or (has_prev and macd_line < macd_prev)
if not self.IsFormedAndOnlineAndAllowTrading():
self._previous_macd = macd_line
return
if ema > first_lwma and ema > second_lwma and self._is_long_setup_prepared and macd_bullish and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(abs(self.Position))
self.BuyMarket(self.Volume)
self._is_long_setup_prepared = False
if ema < first_lwma and ema < second_lwma and self._is_short_setup_prepared and macd_bearish and self.Position >= 0:
if self.Position > 0:
self.SellMarket(self.Position)
self.SellMarket(self.Volume)
self._is_short_setup_prepared = False
self._previous_macd = macd_line
def OnReseted(self):
super(mamacd_novlt_strategy, self).OnReseted()
self._is_long_setup_prepared = False
self._is_short_setup_prepared = False
self._previous_macd = None
def CreateClone(self):
return mamacd_novlt_strategy()