Estratégia MACD Zero Cross
Este sistema opera mudanças de momentum quando o histograma do Moving Average Convergence Divergence (MACD) se aproxima da linha zero. Um MACD ascendente abaixo de zero ou um MACD descendente acima de zero sinaliza uma possível reversão.
Os testes indicam um retorno anual médio de aproximadamente 136%. Funciona melhor no mercado de ações.
A estratégia aguarda que a linha MACD se aproxime de zero enquanto ainda está no lado oposto. Quando o momentum diminui, ela entra antecipando uma oscilação no preço.
As operações saem quando o MACD cruza sua linha de sinal ou um stop-loss é ativado.
Detalhes
- Critérios de entrada: MACD tendendo para zero de qualquer lado.
- Comprado/Vendido: Ambos os lados.
- Critérios de saída: MACD cruza a linha de sinal ou stop.
- Stops: Sim.
- Valores padrão:
FastPeriod= 12SlowPeriod= 26SignalPeriod= 9StopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoria: Momentum
- Direção: Ambos
- Indicadores: MACD
- Stops: Sim
- Complexidade: Básico
- Período: Intradiário
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
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>
/// Strategy that trades MACD crossings of the zero line.
/// Buys when MACD crosses above zero, sells when MACD crosses below zero.
/// </summary>
public class MacdZeroStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevMacd;
private bool _hasPrev;
private int _cooldown;
/// <summary>
/// Fast EMA period for MACD calculation.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period for MACD calculation.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Signal line period for MACD calculation.
/// </summary>
public int SignalPeriod
{
get => _signalPeriod.Value;
set => _signalPeriod.Value = value;
}
/// <summary>
/// Type of candles used for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initialize the MACD Zero strategy.
/// </summary>
public MacdZeroStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 8)
.SetDisplay("Fast EMA", "Fast EMA period for MACD", "MACD")
.SetOptimize(8, 16, 2);
_slowPeriod = Param(nameof(SlowPeriod), 17)
.SetDisplay("Slow EMA", "Slow EMA period for MACD", "MACD")
.SetOptimize(15, 30, 2);
_signalPeriod = Param(nameof(SignalPeriod), 9)
.SetDisplay("Signal", "Signal line period for MACD", "MACD")
.SetOptimize(7, 12, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 700)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacd = 0;
_hasPrev = false;
_cooldown = 0;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = FastPeriod },
LongMa = { Length = SlowPeriod },
},
SignalMa = { Length = SignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, macd);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFormed)
return;
var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
if (macdTyped.Macd is not decimal macdLine || macdTyped.Signal is not decimal signal)
return;
if (!_hasPrev)
{
_prevMacd = macdLine;
_hasPrev = true;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevMacd = macdLine;
return;
}
// Zero line crossover signals
var prevBelow = _prevMacd < 0;
var currAbove = macdLine >= 0;
var prevAbove = _prevMacd >= 0;
var currBelow = macdLine < 0;
if (Position == 0 && prevBelow && currAbove)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && prevAbove && currBelow)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && prevAbove && currBelow)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && prevBelow && currAbove)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevMacd = 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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class macd_zero_strategy(Strategy):
"""
MACD Zero line crossover strategy.
Buys when MACD crosses above zero, sells when crosses below.
"""
def __init__(self):
super(macd_zero_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 8).SetDisplay("Fast EMA", "Fast EMA period for MACD", "MACD")
self._slow_period = self.Param("SlowPeriod", 17).SetDisplay("Slow EMA", "Slow EMA period for MACD", "MACD")
self._signal_period = self.Param("SignalPeriod", 9).SetDisplay("Signal", "Signal line period for MACD", "MACD")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 700).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._prev_macd = 0.0
self._has_prev = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_zero_strategy, self).OnReseted()
self._prev_macd = 0.0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(macd_zero_strategy, self).OnStarted2(time)
self._prev_macd = 0.0
self._has_prev = False
self._cooldown = 0
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self._fast_period.Value
macd.Macd.LongMa.Length = self._slow_period.Value
macd.SignalMa.Length = self._signal_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(macd, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, macd)
self.DrawOwnTrades(area)
def _process_candle(self, candle, macd_val):
if candle.State != CandleStates.Finished:
return
if not macd_val.IsFormed:
return
if macd_val.Macd is None or macd_val.Signal is None:
return
macd_line = float(macd_val.Macd)
if not self._has_prev:
self._prev_macd = macd_line
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_macd = macd_line
return
cd = self._cooldown_bars.Value
prev_below = self._prev_macd < 0
curr_above = macd_line >= 0
prev_above = self._prev_macd >= 0
curr_below = macd_line < 0
if self.Position == 0 and prev_below and curr_above:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and prev_above and curr_below:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and prev_above and curr_below:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and prev_below and curr_above:
self.BuyMarket()
self._cooldown = cd
self._prev_macd = macd_line
def CreateClone(self):
return macd_zero_strategy()