MACD RSI Strategie
MACD RSI kombiniert das Momentum des MACD mit den Überkauft-/Überverkauft-Werten des RSI. Wenn beide Indikatoren übereinstimmen, steigt die Wahrscheinlichkeit einer nachhaltigen Bewegung.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 130%. Sie funktioniert am besten am Aktienmarkt.
Die Strategie geht long, wenn der MACD nach oben kreuzt und der RSI aus dem überverkauften Bereich steigt, oder verkauft short, wenn der MACD nach unten kreuzt und der RSI aus dem überkauften Bereich fällt.
Stops auf Basis eines Kursanteils helfen, Verluste zu begrenzen, falls die Indikatoren nach dem Einstieg divergieren.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: MACD, RSI
- Stops: Ja
- Komplexität: Mittel
- 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 combining MACD and RSI indicators.
/// Uses MACD for trend direction and RSI for entry timing at extreme levels.
/// </summary>
public class MacdRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<int> _cooldownBars;
private decimal _rsiValue;
private decimal _prevMacdLine;
private decimal _prevSignalLine;
private int _cooldown;
/// <summary>
/// Data type for candles.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Period for RSI calculation.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="MacdRsiStrategy"/>.
/// </summary>
public MacdRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetRange(5, 30)
.SetDisplay("RSI Period", "Period for RSI calculation", "RSI Settings");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "RSI oversold level", "RSI Settings");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "RSI overbought level", "RSI Settings");
_cooldownBars = Param(nameof(CooldownBars), 150)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_rsiValue = 50;
_prevMacdLine = 0;
_prevSignalLine = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergenceSignal();
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
// Bind RSI separately to capture its value
subscription.Bind(rsi, OnRsi);
// Bind MACD with BindEx to get signal+macd
subscription
.BindEx(macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var macdArea = CreateChartArea();
if (macdArea != null)
DrawIndicator(macdArea, macd);
var rsiArea = CreateChartArea();
if (rsiArea != null)
DrawIndicator(rsiArea, rsi);
}
}
private void OnRsi(ICandleMessage candle, decimal rsi)
{
_rsiValue = rsi;
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
if (macdTyped.Macd is not decimal macdLine || macdTyped.Signal is not decimal signalLine)
return;
if (_cooldown > 0)
{
_cooldown--;
_prevMacdLine = macdLine;
_prevSignalLine = signalLine;
return;
}
var isUptrend = macdLine > signalLine;
// Entry: uptrend + oversold RSI = buy
if (isUptrend && _rsiValue < RsiOversold && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Entry: downtrend + overbought RSI = sell
else if (!isUptrend && _rsiValue > RsiOverbought && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit: trend reversal
if (Position > 0 && !isUptrend)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && isUptrend)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevMacdLine = macdLine;
_prevSignalLine = signalLine;
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class macd_rsi_strategy(Strategy):
"""
MACD + RSI: uses MACD for trend direction and RSI for entry timing at extreme levels.
"""
def __init__(self):
super(macd_rsi_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetDisplay("RSI Period", "Period for RSI", "RSI")
self._rsi_oversold = self.Param("RsiOversold", 30.0).SetDisplay("RSI Oversold", "RSI oversold level", "RSI")
self._rsi_overbought = self.Param("RsiOverbought", 70.0).SetDisplay("RSI Overbought", "RSI overbought level", "RSI")
self._cooldown_bars = self.Param("CooldownBars", 150).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._rsi_value = 50.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_rsi_strategy, self).OnReseted()
self._rsi_value = 50.0
self._cooldown = 0
def OnStarted2(self, time):
super(macd_rsi_strategy, self).OnStarted2(time)
macd = MovingAverageConvergenceDivergenceSignal()
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self._on_rsi)
subscription.BindEx(macd, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
macd_area = self.CreateChartArea()
if macd_area is not None:
self.DrawIndicator(macd_area, macd)
rsi_area = self.CreateChartArea()
if rsi_area is not None:
self.DrawIndicator(rsi_area, rsi)
def _on_rsi(self, candle, rsi_val):
self._rsi_value = float(rsi_val)
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
typed_val = macd_value
if typed_val.Macd is None or typed_val.Signal is None:
return
macd_line = float(typed_val.Macd)
signal_line = float(typed_val.Signal)
if self._cooldown > 0:
self._cooldown -= 1
return
is_uptrend = macd_line > signal_line
if is_uptrend and self._rsi_value < self._rsi_oversold.Value and self.Position == 0:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
elif not is_uptrend and self._rsi_value > self._rsi_overbought.Value and self.Position == 0:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
if self.Position > 0 and not is_uptrend:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position < 0 and is_uptrend:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
def CreateClone(self):
return macd_rsi_strategy()