Strategie MACD Zero Cross
Dieses System handelt Momentum-Wechsel, wenn das Moving Average Convergence Divergence (MACD)-Histogramm sich der Nulllinie nähert. Ein steigender MACD unterhalb der Null oder ein fallender MACD oberhalb der Null signalisiert eine mögliche Umkehr.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 136%. Es funktioniert am besten auf dem Aktienmarkt.
Die Strategie wartet darauf, dass die MACD-Linie auf null zusteuert, während sie noch auf der gegenüberliegenden Seite ist. Sobald das Momentum nachlässt, tritt sie ein und erwartet einen Preisschwung.
Trades schließen, wenn der MACD seine Signallinie kreuzt oder ein Stop-Loss ausgelöst wird.
Details
- Einstiegskriterien: MACD nähert sich von beiden Seiten der Null.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: MACD kreuzt Signallinie oder Stop.
- Stops: Ja.
- Standardwerte:
FastPeriod= 12SlowPeriod= 26SignalPeriod= 9StopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Momentum
- Richtung: Beide
- Indikatoren: MACD
- Stops: Ja
- Komplexität: Grundlegend
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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()