
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 13): RSI-Sentinel-Tool
Inhalt
- Einführung
- Überblick über die Strategie
- MQL5 Code
- Code-Aufschlüsselung
- Tests und Ergebnisse
- Schlussfolgerung
Einführung
Divergenz ist ein Konzept in der technischen Analyse, bei dem die Bewegung eines Indikators, z. B. des Momentums oder der Oszillatoren, von der Preisbewegung abweicht. Wenn der Kurs neue Höchst- oder Tiefststände bildet, die vom Indikator nicht widergespiegelt werden, kann dies ein Zeichen für einen sich abschwächenden Trend sein und möglicherweise eine Trendumkehr oder eine Änderung der Dynamik vorhersagen. Die RSI-Divergenz ist ein einfaches Mittel, um potenzielle Marktumkehrungen zu erkennen. Wenn sich der Kurs in eine Richtung bewegt, während der RSI in eine andere Richtung geht, könnte dies ein Zeichen für einen Trendwechsel sein. Das manuelle Scannen der Charts nach diesen Signalen kann jedoch langsam und fehleranfällig sein. Hier kommt die Automatisierung ins Spiel.
In diesem Artikel werden wir einen MQL5 Expert Advisor erstellen, der automatisch RSI-Divergenzsignale erkennt. Der EA markiert diese Signale mit klaren Pfeilen auf Ihrem Chart und liefert eine kurze Zusammenfassung, damit Sie schnell erkennen können, was passiert. Egal, ob Sie Anfänger oder erfahrener Händler sind, dieses Instrument hilft Ihnen, Handelschancen zu erkennen, die Sie vor der Ausführung von Geschäften validieren können, ohne stundenlang manuelle Analysen durchführen zu müssen. Lassen Sie uns eintauchen und sehen, wie dieser RSI Divergence EA Ihren Handelsprozess vereinfachen kann.
Überblick über die Strategie
Die RSI-Divergenz verstehen
Eine RSI-Divergenz tritt auf, wenn sich der Relative-Stärke-Index (RSI) in eine andere Richtung als der Kurs des Vermögenswerts bewegt, was auf eine potenzielle Verschiebung der Kursdynamik hinweist. Dieser Kontrast zwischen dem RSI und der Preisentwicklung ist ein Schlüsselindikator, den Händler nutzen, um Marktumkehrungen oder Trendfortsetzungen zu antizipieren. In der Regel folgt der RSI der Kursdynamik und bestätigt damit die vorherrschenden Trends. Wenn jedoch eine Divergenz auftritt, offenbart sie eine Diskrepanz, die häufig einer bedeutenden Kursbewegung vorausgeht. Das frühzeitige Erkennen dieser Signale kann für das Timing von Marktein- und -austritten entscheidend sein.
Im Zusammenhang mit der RSI-Divergenz gibt es zwei Haupttypen
1. Reguläre RSI-Divergenz
Eine Reguläre RSI-Divergenz wird im Allgemeinen als Umkehrsignal angesehen. Es deutet darauf hin, dass der aktuelle Trend an Stärke verliert und möglicherweise kurz vor einer Umkehr steht.
- Reguläre Aufwärts-Divergenz des RSI
Tritt auf, wenn der Kurs ein tieferes Tief bildet, während der RSI ein höheres Tief bildet. Dies deutet darauf hin, dass der Kurs zwar rückläufig ist, die Dynamik jedoch beginnt, sich nach oben zu verlagern, was auf eine mögliche Umkehr zu einem Aufwärtstrend hindeutet.
Abb. 1. Aufwärts-Divergenz
- Reguläre Abwärts-Divergenz des RSI
Tritt auf, wenn der Kurs ein höheres Hoch bildet, während der RSI ein niedrigeres Hoch bildet. Trotz des steigenden Kurses deutet das nachlassende Momentum (wie der RSI zeigt) darauf hin, dass ein Abschwung bevorstehen könnte.
Abb. 2. Abwärts-Divergenz
2. Verborgene RSI-Divergenz
Eine verborgene RSI-Divergenz wird als Signal für eine Trendfortsetzung und nicht für eine bevorstehende Umkehr interpretiert. Sie bestätigt, dass der aktuelle Trend immer noch stark ist, selbst wenn der RSI und der Preis vorübergehend auseinander laufen.
- Verborgene Aufwärts-Divergenz des RSI: Wenn der Kurs in einem Aufwärtstrend ein höheres Tief bildet, während der RSI ein niedrigeres Tief bildet, deutet dies darauf hin, dass die Korrektur nur vorübergehend ist und der Aufwärtstrend wahrscheinlich fortgesetzt wird.
Abb. 3. Verborgene Aufwärts-Divergenz des RSI
- Verborgene Abwärts-Divergenz des RSI: Wenn in einem Abwärtstrend der Kurs ein niedrigeres Hoch bildet, während der RSI ein höheres Hoch bildet, bestätigt dies die Stärke des Abwärtstrends und deutet darauf hin, dass die Abwärtsbewegung wahrscheinlich anhalten wird.
Abb. 4. Verborgene Abwärts-Divergenz
Nachfolgend finden Sie eine zusammenfassende Tabelle, in der die wichtigsten Unterschiede zwischen den verschiedenen Arten von RSI-Divergenzen zusammengefasst sind:
RSI-Divergenztyp | Preisaktion | RSI-Aktion | Signalart | Erwartung |
---|---|---|---|---|
Regulär Aufwärts | Tiefes Tief (LL) | Höheres Tief (HL) | Umkehr nach oben | Abwärtstrend zu Aufwärtstrend |
Regulär Abwärts | Hohes Hoch (HH) | Tieferes Hoch (LH) | Umkehr nach unten | Aufwärtstrend bis Abwärtstrend |
Verborgen Aufwärts | Hohes Tief(HL) | Tiefes Tief (LL) | Fortsetzung nach oben | Aufwärtstrend setzt sich fort |
Verborgen Abwärts | Tiefes Hoch (LH) | Hohes Hoch (HH) | Fortsetzung nach unten | Abwärtstrend setzt sich fort |
Zusammenfassend lässt sich sagen, dass dieser EA sowohl die Kurs- als auch die RSI-Daten über einen definierten Rückblickzeitraum kontinuierlich überprüft, um Diskrepanzen zwischen ihren Bewegungen zu erkennen, was wir RSI-Divergenz nennen.
Im Folgenden wird beschrieben, was sie tut:
1. Datenerhebung und -aufbereitung
Der EA sammelt die RSI-Werte zusammen mit den entsprechenden Kursdaten (Tiefst-, Höchst- und Schlusskurse sowie die Uhrzeit) der letzten Bars. Dadurch wird sichergestellt, dass die Analyse immer auf den neuesten und vollständigen Informationen beruht.2. Identifizierung von Wendepunkten
Anschließend werden sowohl in den Kurs- als auch in den RSI-Daten lokale Höchst- und Tiefststände ermittelt. Diese Swing-Punkte dienen als Referenzmarker für unsere Divergenzanalyse.3. Reguläre Divergenz erkennen
- Reguläre Aufwärts-Divergenz: Der EA sucht nach Situationen, in denen der Kurs ein tieferes Tief erreicht, während der RSI ein höheres Tief bildet, was darauf hindeutet, dass ein Abwärtstrend an Schwung verliert und sich nach oben umkehren könnte.
- Reguläre Abwärts-Divergenz: Außerdem wird geprüft, ob der Kurs ein höheres Hoch erreicht, während der RSI ein niedrigeres Hoch bildet, was darauf hindeutet, dass sich ein Aufwärtstrend seinem Ende nähert, da die Dynamik nachlässt.
- Verborgene Aufwärts-Divergenz: Wenn der Kurs in einem Aufwärtstrend ein höheres Tief bildet, der RSI jedoch ein niedrigeres Tief verzeichnet, erkennt der EA dies als Zeichen dafür, dass der allgemeine Aufwärtstrend trotz eines vorübergehenden Rückschlags weiterhin stark ist.
- Verborgene Abwärts-Divergenz: Umgekehrt gilt: Wenn der Kurs während eines Abwärtstrends ein niedrigeres Hoch erreicht, während der RSI ein höheres Hoch anzeigt, bestätigt dies, dass der Abwärtstrend wahrscheinlich anhalten wird.
5. Visuelle und protokollierte Signalerzeugung
Sobald eine Divergenz erkannt wird, egal ob sie regelmäßig oder versteckt ist, markiert der EA das Ereignis visuell auf dem Chart (mit Pfeilen und Text) und protokolliert die Details des Signals für weitere Analysen oder Backtests. Wie die oben genannten Vorgänge ablaufen, erfahren Sie im Abschnitt Codeaufschlüsselung weiter unten.
MQL5 Code
//+--------------------------------------------------------------------+ //| RSI Divergence.mql5 | //| Copyright 2025, Christian Benjamin | //| https://www.mql5.com | //+--------------------------------------------------------------------+ #property copyright "2025, MetaQuotes Software Corp." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict //---- Input parameters input int InpRSIPeriod = 14; // RSI period input int InpSwingLeft = 1; // Bars to the left for swing detection (relaxed) input int InpSwingRight = 1; // Bars to the right for swing detection (relaxed) input int InpLookback = 100; // Number of bars to scan for divergence input int InpEvalBars = 5; // Bars after which to evaluate a signal input int InpMinBarsBetweenSignals = 1; // Minimum bars between same-type signals (allows frequent re-entry) input double InpArrowOffset = 3.0; // Arrow offset (in points) for display input double InpMinSwingDiffPct = 0.05; // Lower minimum % difference to qualify as a swing input double InpMinRSIDiff = 1.0; // Lower minimum difference in RSI between swing points // Optional RSI threshold filter for bullish divergence (disabled by default) input bool InpUseRSIThreshold = false; // If true, require earlier RSI swing to be oversold for bullish divergence input double InpRSIOversold = 30; // RSI oversold level input double InpRSIOverbought = 70; // RSI overbought level (if needed for bearish) //---- Global variables int rsiHandle; // Handle for the RSI indicator double rsiBuffer[]; // Buffer for RSI values double lowBuffer[]; // Buffer for low prices double highBuffer[]; // Buffer for high prices double closeBuffer[]; // Buffer for close prices datetime timeBuffer[]; // Buffer for bar times int g_totalBars = 0; // Number of bars in our copied arrays datetime lastBarTime = 0; // Time of last closed bar //---- Structure to hold signal information struct SignalInfo { string type; // e.g. "RegBearish Divergence", "HiddenBullish Divergence" int barIndex; // Bar index where the signal was generated datetime signalTime; // Time of the signal bar double signalPrice; // Price used for the signal (swing high for bearish, swing low for bullish) }; SignalInfo signals[]; // Global array to store signals //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { rsiHandle = iRSI(_Symbol, _Period, InpRSIPeriod, PRICE_CLOSE); if(rsiHandle == INVALID_HANDLE) { Print("Error creating RSI handle"); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(rsiHandle != INVALID_HANDLE) IndicatorRelease(rsiHandle); EvaluateSignalsAndPrint(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Process once per new closed candle (using bar1's time) datetime currentBarTime = iTime(_Symbol, _Period, 1); if(currentBarTime == lastBarTime) return; lastBarTime = currentBarTime; //--- Copy RSI data ArrayResize(rsiBuffer, InpLookback); ArraySetAsSeries(rsiBuffer, true); if(CopyBuffer(rsiHandle, 0, 0, InpLookback, rsiBuffer) <= 0) { Print("Error copying RSI data"); return; } //--- Copy price and time data ArrayResize(lowBuffer, InpLookback); ArrayResize(highBuffer, InpLookback); ArrayResize(closeBuffer, InpLookback); ArraySetAsSeries(lowBuffer, true); ArraySetAsSeries(highBuffer, true); ArraySetAsSeries(closeBuffer, true); if(CopyLow(_Symbol, _Period, 0, InpLookback, lowBuffer) <= 0 || CopyHigh(_Symbol, _Period, 0, InpLookback, highBuffer) <= 0 || CopyClose(_Symbol, _Period, 0, InpLookback, closeBuffer) <= 0) { Print("Error copying price data"); return; } ArrayResize(timeBuffer, InpLookback); ArraySetAsSeries(timeBuffer, true); if(CopyTime(_Symbol, _Period, 0, InpLookback, timeBuffer) <= 0) { Print("Error copying time data"); return; } g_totalBars = InpLookback; //--- Identify swing lows and swing highs int swingLows[]; int swingHighs[]; int startIndex = InpSwingLeft; int endIndex = g_totalBars - InpSwingRight; for(int i = startIndex; i < endIndex; i++) { if(IsSignificantSwingLow(i, InpSwingLeft, InpSwingRight)) { ArrayResize(swingLows, ArraySize(swingLows) + 1); swingLows[ArraySize(swingLows) - 1] = i; } if(IsSignificantSwingHigh(i, InpSwingLeft, InpSwingRight)) { ArrayResize(swingHighs, ArraySize(swingHighs) + 1); swingHighs[ArraySize(swingHighs) - 1] = i; } } //--- Bearish Divergence (using swing highs) if(ArraySize(swingHighs) >= 2) { ArraySort(swingHighs); // ascending order: index 0 is most recent int recent = swingHighs[0]; int previous = swingHighs[1]; // Regular Bearish Divergence: Price makes a higher high while RSI makes a lower high if(highBuffer[recent] > highBuffer[previous] && rsiBuffer[recent] < rsiBuffer[previous] && (rsiBuffer[previous] - rsiBuffer[recent]) >= InpMinRSIDiff) { Print("Regular Bearish Divergence detected at bar ", recent); DisplaySignal("RegBearish Divergence", recent); } // Hidden Bearish Divergence: Price makes a lower high while RSI makes a higher high else if(highBuffer[recent] < highBuffer[previous] && rsiBuffer[recent] > rsiBuffer[previous] && (rsiBuffer[recent] - rsiBuffer[previous]) >= InpMinRSIDiff) { Print("Hidden Bearish Divergence detected at bar ", recent); DisplaySignal("HiddenBearish Divergence", recent); } } //--- Bullish Divergence (using swing lows) if(ArraySize(swingLows) >= 2) { ArraySort(swingLows); // ascending order: index 0 is most recent int recent = swingLows[0]; int previous = swingLows[1]; // Regular Bullish Divergence: Price makes a lower low while RSI makes a higher low if(lowBuffer[recent] < lowBuffer[previous] && rsiBuffer[recent] > rsiBuffer[previous] && (rsiBuffer[recent] - rsiBuffer[previous]) >= InpMinRSIDiff) { // Optionally require the earlier swing's RSI be oversold if(!InpUseRSIThreshold || rsiBuffer[previous] <= InpRSIOversold) { Print("Regular Bullish Divergence detected at bar ", recent); DisplaySignal("RegBullish Divergence", recent); } } // Hidden Bullish Divergence: Price makes a higher low while RSI makes a lower low else if(lowBuffer[recent] > lowBuffer[previous] && rsiBuffer[recent] < rsiBuffer[previous] && (rsiBuffer[previous] - rsiBuffer[recent]) >= InpMinRSIDiff) { Print("Hidden Bullish Divergence detected at bar ", recent); DisplaySignal("HiddenBullish Divergence", recent); } } } //+------------------------------------------------------------------------+ //| IsSignificantSwingLow: Determines if the bar at 'index' is a swing low | //+------------------------------------------------------------------------+ bool IsSignificantSwingLow(int index, int left, int right) { double currentLow = lowBuffer[index]; // Check left side for a local minimum condition for(int i = index - left; i < index; i++) { if(i < 0) continue; double pctDiff = MathAbs((lowBuffer[i] - currentLow) / currentLow) * 100.0; if(lowBuffer[i] < currentLow && pctDiff > InpMinSwingDiffPct) return false; } // Check right side for a local minimum condition for(int i = index + 1; i <= index + right; i++) { if(i >= g_totalBars) break; double pctDiff = MathAbs((lowBuffer[i] - currentLow) / currentLow) * 100.0; if(lowBuffer[i] < currentLow && pctDiff > InpMinSwingDiffPct) return false; } return true; } //+--------------------------------------------------------------------------+ //| IsSignificantSwingHigh: Determines if the bar at 'index' is a swing high | //+--------------------------------------------------------------------------+ bool IsSignificantSwingHigh(int index, int left, int right) { double currentHigh = highBuffer[index]; // Check left side for a local maximum condition for(int i = index - left; i < index; i++) { if(i < 0) continue; double pctDiff = MathAbs((currentHigh - highBuffer[i]) / currentHigh) * 100.0; if(highBuffer[i] > currentHigh && pctDiff > InpMinSwingDiffPct) return false; } // Check right side for a local maximum condition for(int i = index + 1; i <= index + right; i++) { if(i >= g_totalBars) break; double pctDiff = MathAbs((currentHigh - highBuffer[i]) / currentHigh) * 100.0; if(highBuffer[i] > currentHigh && pctDiff > InpMinSwingDiffPct) return false; } return true; } //+------------------------------------------------------------------+ //| DisplaySignal: Draws an arrow on the chart and records the signal| //+------------------------------------------------------------------+ void DisplaySignal(string signalText, int barIndex) { // Prevent duplicate signals on the same bar (or too close) for(int i = 0; i < ArraySize(signals); i++) { if(StringFind(signals[i].type, signalText) != -1) if(MathAbs(signals[i].barIndex - barIndex) < InpMinBarsBetweenSignals) return; } // Update a "LatestSignal" label for regular signals. if(StringFind(signalText, "Reg") != -1) { string labelName = "LatestSignal"; if(ObjectFind(0, labelName) == -1) { if(!ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0)) { Print("Failed to create LatestSignal label"); return; } ObjectSetInteger(0, labelName, OBJPROP_CORNER, 0); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, 20); ObjectSetInteger(0, labelName, OBJPROP_COLOR, clrWhite); } ObjectSetString(0, labelName, OBJPROP_TEXT, signalText); } // Create an arrow object for the signal. string arrowName = "Arrow_" + signalText + "_" + IntegerToString(barIndex); if(ObjectFind(0, arrowName) < 0) { int arrowCode = 0; double arrowPrice = 0.0; color arrowColor = clrWhite; double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); if(StringFind(signalText, "Bullish") != -1) { arrowCode = 233; // Wingdings up arrow arrowColor = clrLime; arrowPrice = lowBuffer[barIndex] - (InpArrowOffset * point); } else if(StringFind(signalText, "Bearish") != -1) { arrowCode = 234; // Wingdings down arrow arrowColor = clrRed; arrowPrice = highBuffer[barIndex] + (InpArrowOffset * point); } if(!ObjectCreate(0, arrowName, OBJ_ARROW, 0, timeBuffer[barIndex], arrowPrice)) { Print("Failed to create arrow object ", arrowName); return; } ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode); } // Record the signal for evaluation. SignalInfo sig; sig.type = signalText; sig.barIndex = barIndex; sig.signalTime = timeBuffer[barIndex]; if(StringFind(signalText, "Bullish") != -1) sig.signalPrice = lowBuffer[barIndex]; else sig.signalPrice = highBuffer[barIndex]; ArrayResize(signals, ArraySize(signals) + 1); signals[ArraySize(signals) - 1] = sig; UpdateSignalCountLabel(); } //+------------------------------------------------------------------+ //| UpdateSignalCountLabel: Updates a label showing signal counts | //+------------------------------------------------------------------+ void UpdateSignalCountLabel() { int regCount = 0, hidCount = 0; for(int i = 0; i < ArraySize(signals); i++) { if(StringFind(signals[i].type, "Reg") != -1) regCount++; else if(StringFind(signals[i].type, "Hidden") != -1) hidCount++; } string countText = "Regular Signals: " + IntegerToString(regCount) + "\nHidden Signals: " + IntegerToString(hidCount); string countLabel = "SignalCount"; if(ObjectFind(0, countLabel) == -1) { if(!ObjectCreate(0, countLabel, OBJ_LABEL, 0, 0, 0)) { Print("Failed to create SignalCount label"); return; } ObjectSetInteger(0, countLabel, OBJPROP_CORNER, 0); ObjectSetInteger(0, countLabel, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, countLabel, OBJPROP_YDISTANCE, 40); ObjectSetInteger(0, countLabel, OBJPROP_COLOR, clrYellow); } ObjectSetString(0, countLabel, OBJPROP_TEXT, countText); } //+--------------------------------------------------------------------+ //| EvaluateSignalsAndPrint: After backtesting, prints signal accuracy | //+--------------------------------------------------------------------+ void EvaluateSignalsAndPrint() { double closeAll[]; int totalBars = CopyClose(_Symbol, _Period, 0, WHOLE_ARRAY, closeAll); if(totalBars <= 0) { Print("Error copying complete close data for evaluation"); return; } ArraySetAsSeries(closeAll, true); int totalEvaluated = 0, regTotal = 0, hidTotal = 0; int regEval = 0, hidEval = 0; int regCorrect = 0, hidCorrect = 0; for(int i = 0; i < ArraySize(signals); i++) { int evalIndex = signals[i].barIndex - InpEvalBars; if(evalIndex < 0) continue; double evalClose = closeAll[evalIndex]; if(StringFind(signals[i].type, "Bullish") != -1) { if(StringFind(signals[i].type, "Reg") != -1) { regTotal++; regEval++; if(evalClose > signals[i].signalPrice) regCorrect++; } else if(StringFind(signals[i].type, "Hidden") != -1) { hidTotal++; hidEval++; if(evalClose > signals[i].signalPrice) hidCorrect++; } totalEvaluated++; } else if(StringFind(signals[i].type, "Bearish") != -1) { if(StringFind(signals[i].type, "Reg") != -1) { regTotal++; regEval++; if(evalClose < signals[i].signalPrice) regCorrect++; } else if(StringFind(signals[i].type, "Hidden") != -1) { hidTotal++; hidEval++; if(evalClose < signals[i].signalPrice) hidCorrect++; } totalEvaluated++; } } double overallAccuracy = (totalEvaluated > 0) ? (double)(regCorrect + hidCorrect) / totalEvaluated * 100.0 : 0.0; double regAccuracy = (regEval > 0) ? (double)regCorrect / regEval * 100.0 : 0.0; double hidAccuracy = (hidEval > 0) ? (double)hidCorrect / hidEval * 100.0 : 0.0; Print("----- Backtest Signal Evaluation -----"); Print("Total Signals Generated: ", ArraySize(signals)); Print("Signals Evaluated: ", totalEvaluated); Print("Overall Accuracy: ", DoubleToString(overallAccuracy, 2), "%"); Print("Regular Signals: ", regTotal, " | Evaluated: ", regEval, " | Accuracy: ", DoubleToString(regAccuracy, 2), "%"); Print("Hidden Signals: ", hidTotal, " | Evaluated: ", hidEval, " | Accuracy: ", DoubleToString(hidAccuracy, 2), "%"); } //+------------------------------------------------------------------+
Code-Aufschlüsselung
1. Kopfzeileninformationen und Eingabeparameter
Ganz oben in unserem Skript befindet sich eine klar definierte Kopfzeile, die wichtige Informationen über den Code enthält.
Informationen zu Datei und Autor
Die Kopfzeile enthält den Dateinamen (RSI Divergence.mql5), den Copyright-Vermerk und einen Link zum Profil des Autors. Dies gewährleistet eine ordnungsgemäße Zuordnung und bietet den Nutzern einen Bezugspunkt, wenn sie nach Aktualisierungen oder zusätzlicher Dokumentation suchen müssen.
Versionierung und Kompilierungsrichtlinien
Die Direktive #property legt wichtige Eigenschaften wie die Versionsnummer und die Verwendung strenger Kompilierungsregeln (#property strict) fest. Dies trägt dazu bei, die Konsistenz zu wahren und mögliche Fehler während der Entwicklung und Bereitstellung zu reduzieren. Weiter geht es mit dem Abschnitt Eingabeparameter, der für die Anpassung von wesentlicher Bedeutung ist. Mit diesen Parametern können Sie oder jeder andere Nutzer das Verhalten der Logik zur Erkennung von Divergenzen feinabstimmen, ohne den Kerncode zu ändern. Nachfolgend sind einige Highlights aufgeführt:
RSI- und Swing-Erkennungsparameter
- InpRSIPeriode: Legt den Zeitraum für den RSI-Indikator fest.
- InpSwingLeft und InpSwingRight: Legen Sie fest, wie viele Balken auf jeder Seite bei der Erkennung von Schwungpunkten berücksichtigt werden. Durch die Anpassung dieser Werte wird die Schwungerkennung entweder lockerer oder strenger.
Einstellungen für Divergenz und Signalauswertung
- InpLookback: Legt fest, wie viele Balken in der Vergangenheit das Skript nach Divergenzen durchsuchen soll.
- InpEvalBars: Gibt die Anzahl der Balken an, die gewartet wird, bevor ausgewertet wird, ob ein Signal erfolgreich war.
- InpMinBarsBetweenSignals: Hilft dabei, doppelte Signale zu vermeiden, indem ein Mindestabstand zwischen ähnlichen Signalen erzwungen wird.
Anpassungen anzeigen
- InpArrowOffset: Legt den Abstand (in Punkten) fest, um den die Pfeile vom Schwungpunkt versetzt sind, um die visuelle Klarheit auf dem Chart zu verbessern.
Optionaler RSI-Schwellenwertfilter
- InpUseRSIThreshold bietet zusammen mit InpRSIOversold und InpRSIOverbought eine zusätzliche Filterungsebene. Dadurch wird sichergestellt, dass bei einer Aufwärtsdivergenz der frühere RSI-Schwung im überverkauften Bereich liegt - sofern der Nutzer diesen Filter aktiviert hat.
//+------------------------------------------------------------------+ //| RSI Divergence.mql5 | //| Copyright 2025, Christian Benjamin | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2025, MetaQuotes Software Corp." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict //---- Input parameters input int InpRSIPeriod = 14; // RSI period input int InpSwingLeft = 1; // Bars to the left for swing detection (relaxed) input int InpSwingRight = 1; // Bars to the right for swing detection (relaxed) input int InpLookback = 100; // Number of bars to scan for divergence input int InpEvalBars = 5; // Bars after which to evaluate a signal input int InpMinBarsBetweenSignals = 1; // Minimum bars between same-type signals (allows frequent re-entry) input double InpArrowOffset = 3.0; // Arrow offset (in points) for display input double InpMinSwingDiffPct = 0.05; // Lower minimum % difference to qualify as a swing input double InpMinRSIDiff = 1.0; // Lower minimum difference in RSI between swing points // Optional RSI threshold filter for bullish divergence (disabled by default) input bool InpUseRSIThreshold = false; // If true, require earlier RSI swing to be oversold for bullish divergence input double InpRSIOversold = 30; // RSI oversold level input double InpRSIOverbought = 70; // RSI overbought level (if needed for bearish)
2. Initialisierung des Indikators
In diesem Teil initialisieren wir unseren RSI-Indikator. Die Funktion OnInit() erstellt ein Handle für den RSI-Indikator unter Verwendung von Parametern wie Symbol, Zeitrahmen und der vom Nutzer angegebenen RSI-Periode. Dieser Schritt ist von entscheidender Bedeutung, da jede nachfolgende Operation davon abhängt, dass ein gültiges RSI-Handle zum Abrufen der Indikatordaten vorhanden ist.
- Die Funktion iRSI wird mit den erforderlichen Parametern aufgerufen.
- Es ist eine Fehlerbehandlung implementiert, um jeden Fehler bei der Erstellung des Handles abzufangen.
- Die Initialisierung stellt sicher, dass unser Indikator für die Datenerfassung und -analyse bereit ist.
int OnInit() { // Create the RSI indicator handle with the specified period rsiHandle = iRSI(_Symbol, _Period, InpRSIPeriod, PRICE_CLOSE); if(rsiHandle == INVALID_HANDLE) { Print("Error creating RSI handle"); return(INIT_FAILED); } return(INIT_SUCCEEDED); }
3. Datenerfassung bei jeder neuen Kerze
In der Funktion OnTick() wird vor der Verarbeitung geprüft, ob eine neue Kerze geschlossen wurde. Dadurch wird sichergestellt, dass unsere Analyse stets mit vollständigen Daten arbeitet. Wir kopieren dann Arrays von RSI-Werten, Tiefst- und Höchstständen, Schlusskursen und Zeitdaten über einen konfigurierbaren Rückblickzeitraum. Die Einstellung der Arrays als Serie stellt sicher, dass die Daten mit dem jüngsten Balken bei Index 0 geordnet sind.
- Der Code wartet auf die nächste geschlossene Kerze, um die Verarbeitung unvollständiger Daten zu vermeiden.
- RSI- und Kursdaten werden mit Funktionen wie CopyBuffer und CopyLow/High/Close/Time abgerufen.
- Bei der Verwendung von ArraySetAsSeries bleibt die richtige Reihenfolge für die Zeitreihenanalyse erhalten.
void OnTick() { // Process only once per new closed candle by comparing bar times datetime currentBarTime = iTime(_Symbol, _Period, 1); if(currentBarTime == lastBarTime) return; lastBarTime = currentBarTime; // Copy RSI data for a given lookback period ArrayResize(rsiBuffer, InpLookback); ArraySetAsSeries(rsiBuffer, true); if(CopyBuffer(rsiHandle, 0, 0, InpLookback, rsiBuffer) <= 0) { Print("Error copying RSI data"); return; } // Copy price data (lows, highs, closes) and time data for analysis ArrayResize(lowBuffer, InpLookback); ArrayResize(highBuffer, InpLookback); ArrayResize(closeBuffer, InpLookback); ArraySetAsSeries(lowBuffer, true); ArraySetAsSeries(highBuffer, true); ArraySetAsSeries(closeBuffer, true); if(CopyLow(_Symbol, _Period, 0, InpLookback, lowBuffer) <= 0 || CopyHigh(_Symbol, _Period, 0, InpLookback, highBuffer) <= 0 || CopyClose(_Symbol, _Period, 0, InpLookback, closeBuffer) <= 0) { Print("Error copying price data"); return; } ArrayResize(timeBuffer, InpLookback); ArraySetAsSeries(timeBuffer, true); if(CopyTime(_Symbol, _Period, 0, InpLookback, timeBuffer) <= 0) { Print("Error copying time data"); return; } g_totalBars = InpLookback; // (Further processing follows here...) }
4. Swing Detection (Erkennung von Swing Lows und Swing Highs)
Bevor wir Divergenzen erkennen können, müssen wir zunächst wichtige Umkehrpunkte ausfindig machen. Zwei Hilfsfunktionen, IsSignificantSwingLow und IsSignificantSwingHigh, werden verwendet, um lokale Minima und Maxima zu identifizieren. Dazu wird der Tiefst- oder Höchststand eines Balkens mit den benachbarten Balken innerhalb eines bestimmten Fensters verglichen und geprüft, ob die prozentuale Differenz einen festgelegten Schwellenwert erreicht.- Die Funktionen prüfen sowohl links als auch rechts des aktuellen Balkens.
- Sie berechnen die prozentuale Differenz, um sicherzustellen, dass nur signifikante Schwankungen markiert werden.
- Diese Filterung reduziert das Rauschen und gewährleistet, dass sich unsere Divergenzanalyse auf aussagekräftige Marktbewegungen konzentriert.
bool IsSignificantSwingLow(int index, int left, int right) { double currentLow = lowBuffer[index]; // Check left side for local minimum condition for(int i = index - left; i < index; i++) { if(i < 0) continue; double pctDiff = MathAbs((lowBuffer[i] - currentLow) / currentLow) * 100.0; if(lowBuffer[i] < currentLow && pctDiff > InpMinSwingDiffPct) return false; } // Check right side for local minimum condition for(int i = index + 1; i <= index + right; i++) { if(i >= g_totalBars) break; double pctDiff = MathAbs((lowBuffer[i] - currentLow) / currentLow) * 100.0; if(lowBuffer[i] < currentLow && pctDiff > InpMinSwingDiffPct) return false; } return true; } bool IsSignificantSwingHigh(int index, int left, int right) { double currentHigh = highBuffer[index]; // Check left side for local maximum condition for(int i = index - left; i < index; i++) { if(i < 0) continue; double pctDiff = MathAbs((currentHigh - highBuffer[i]) / currentHigh) * 100.0; if(highBuffer[i] > currentHigh && pctDiff > InpMinSwingDiffPct) return false; } // Check right side for local maximum condition for(int i = index + 1; i <= index + right; i++) { if(i >= g_totalBars) break; double pctDiff = MathAbs((currentHigh - highBuffer[i]) / currentHigh) * 100.0; if(highBuffer[i] > currentHigh && pctDiff > InpMinSwingDiffPct) return false; } return true; }
5. Erkennung von Divergenzen: Auf- und Abwärts-Divergenzen
Sobald die Schwankungspunkte identifiziert sind, vergleicht der Algorithmus die jüngsten Schwankungen, um Divergenzen zu erkennen. Bei Abwärts-Divergenz betrachtet der Code zwei Swing-Hochs und prüft, ob der Kurs ein höheres Hoch erreicht, während der RSI ein niedrigeres Hoch anzeigt (oder umgekehrt bei verborgenen Abwärts-Divergenz). Bei einer Aufwärts-Divergenz werden in ähnlicher Weise zwei Tiefststände verglichen. Ein optionaler RSI-Schwellenwert kann Aufwärtssignale weiter validieren, indem er sicherstellt, dass der frühere RSI-Wert im überverkauften Bereich liegt.
- Für die Divergenzanalyse werden zwei aktuelle Swing-Punkte (entweder Höchst- oder Tiefstwerte) verwendet.
- Die Bedingungen für reguläre und versteckte Abweichungen sind klar voneinander getrennt.
- Optionale Parameter (wie die RSI-Oversold-Bedingung) ermöglichen eine zusätzliche Filterung der Signalstärke.
// --- Bearish Divergence (using swing highs) if(ArraySize(swingHighs) >= 2) { ArraySort(swingHighs); // Ensure ascending order: index 0 is most recent int recent = swingHighs[0]; int previous = swingHighs[1]; // Regular Bearish Divergence: Price makes a higher high while RSI makes a lower high if(highBuffer[recent] > highBuffer[previous] && rsiBuffer[recent] < rsiBuffer[previous] && (rsiBuffer[previous] - rsiBuffer[recent]) >= InpMinRSIDiff) { Print("Regular Bearish Divergence detected at bar ", recent); DisplaySignal("RegBearish Divergence", recent); } // Hidden Bearish Divergence: Price makes a lower high while RSI makes a higher high else if(highBuffer[recent] < highBuffer[previous] && rsiBuffer[recent] > rsiBuffer[previous] && (rsiBuffer[recent] - rsiBuffer[previous]) >= InpMinRSIDiff) { Print("Hidden Bearish Divergence detected at bar ", recent); DisplaySignal("HiddenBearish Divergence", recent); } } // --- Bullish Divergence (using swing lows) if(ArraySize(swingLows) >= 2) { ArraySort(swingLows); // Ensure ascending order: index 0 is most recent int recent = swingLows[0]; int previous = swingLows[1]; // Regular Bullish Divergence: Price makes a lower low while RSI makes a higher low if(lowBuffer[recent] < lowBuffer[previous] && rsiBuffer[recent] > rsiBuffer[previous] && (rsiBuffer[recent] - rsiBuffer[previous]) >= InpMinRSIDiff) { // Optionally require the earlier RSI swing to be oversold if(!InpUseRSIThreshold || rsiBuffer[previous] <= InpRSIOversold) { Print("Regular Bullish Divergence detected at bar ", recent); DisplaySignal("RegBullish Divergence", recent); } } // Hidden Bullish Divergence: Price makes a higher low while RSI makes a lower low else if(lowBuffer[recent] > lowBuffer[previous] && rsiBuffer[recent] < rsiBuffer[previous] && (rsiBuffer[previous] - rsiBuffer[recent]) >= InpMinRSIDiff) { Print("Hidden Bullish Divergence detected at bar ", recent); DisplaySignal("HiddenBullish Divergence", recent); } }
6. Signalanzeige und -aufzeichnung
Wenn eine Divergenz entdeckt wird, ist es wichtig, das Signal visuell zu markieren und seine Details für eine spätere Auswertung aufzuzeichnen. Die Funktion DisplaySignal() erstellt nicht nur einen Pfeil auf dem Chart (mit unterschiedlichen Pfeilcodes und Farben für Auf- und Abwärtssignale), sondern aktualisiert auch eine Beschriftung für das neueste Signal und speichert die Metadaten des Signals in einem globalen Array. Diese systematische Aufzeichnung ermöglichen spätere Backtests der Strategie.
- Doppelte Signale werden verhindert, indem geprüft wird, ob bereits ein Signal für einen ähnlichen Balken existiert.
- Visuelle Anhaltspunkte wie Pfeile und Beschriftungen verbessern die Lesbarkeit des Charts.
- Jedes Signal wird mit Details wie Typ, Bar-Index, Zeit und Preis gespeichert, was eine spätere Leistungsbewertung erleichtert.
void DisplaySignal(string signalText, int barIndex) { // Prevent duplicate signals on the same or nearby bars for(int i = 0; i < ArraySize(signals); i++) { if(StringFind(signals[i].type, signalText) != -1) if(MathAbs(signals[i].barIndex - barIndex) < InpMinBarsBetweenSignals) return; } // Update a label for the latest regular signal if(StringFind(signalText, "Reg") != -1) { string labelName = "LatestSignal"; if(ObjectFind(0, labelName) == -1) { if(!ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0)) { Print("Failed to create LatestSignal label"); return; } ObjectSetInteger(0, labelName, OBJPROP_CORNER, 0); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, 20); ObjectSetInteger(0, labelName, OBJPROP_COLOR, clrWhite); } ObjectSetString(0, labelName, OBJPROP_TEXT, signalText); } // Create an arrow object to mark the signal on the chart string arrowName = "Arrow_" + signalText + "_" + IntegerToString(barIndex); if(ObjectFind(0, arrowName) < 0) { int arrowCode = 0; double arrowPrice = 0.0; color arrowColor = clrWhite; double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); if(StringFind(signalText, "Bullish") != -1) { arrowCode = 233; // Wingdings up arrow arrowColor = clrLime; arrowPrice = lowBuffer[barIndex] - (InpArrowOffset * point); } else if(StringFind(signalText, "Bearish") != -1) { arrowCode = 234; // Wingdings down arrow arrowColor = clrRed; arrowPrice = highBuffer[barIndex] + (InpArrowOffset * point); } if(!ObjectCreate(0, arrowName, OBJ_ARROW, 0, timeBuffer[barIndex], arrowPrice)) { Print("Failed to create arrow object ", arrowName); return; } ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode); } // Record the signal details for later backtesting evaluation SignalInfo sig; sig.type = signalText; sig.barIndex = barIndex; sig.signalTime = timeBuffer[barIndex]; if(StringFind(signalText, "Bullish") != -1) sig.signalPrice = lowBuffer[barIndex]; else sig.signalPrice = highBuffer[barIndex]; ArrayResize(signals, ArraySize(signals) + 1); signals[ArraySize(signals) - 1] = sig; UpdateSignalCountLabel(); }
Backtest-Auswertung zur Deinitialisierung
Schließlich wird die Funktion EvaluateSignalsAndPrint() aufgerufen, wenn der Experte deinitialisiert wird. Diese Funktion wertet alle aufgezeichneten Signale rückwirkend aus, indem sie die Preisbewegung einige Balken nach dem Signal mit dem aufgezeichneten Preis des Signals vergleicht. Es berechnet die Genauigkeit sowohl für reguläre als auch für versteckte Signale und liefert so wertvolles Feedback über die Leistung unserer Divergenzstrategie.
- Die Funktion ruft die vollständigen historischen Abschlussdaten ab.
- Jedes Signal wird nach einer festen Anzahl von Balken ausgewertet (wie in InpEvalBars festgelegt).
- Genauigkeitsmetriken werden sowohl für die Gesamtsignale als auch getrennt für reguläre und versteckte Signale berechnet, was die Leistungsvalidierung erleichtert.
void EvaluateSignalsAndPrint() { double closeAll[]; int totalBars = CopyClose(_Symbol, _Period, 0, WHOLE_ARRAY, closeAll); if(totalBars <= 0) { Print("Error copying complete close data for evaluation"); return; } ArraySetAsSeries(closeAll, true); int totalEvaluated = 0, regTotal = 0, hidTotal = 0; int regEval = 0, hidEval = 0; int regCorrect = 0, hidCorrect = 0; for(int i = 0; i < ArraySize(signals); i++) { int evalIndex = signals[i].barIndex - InpEvalBars; if(evalIndex < 0) continue; double evalClose = closeAll[evalIndex]; if(StringFind(signals[i].type, "Bullish") != -1) { if(StringFind(signals[i].type, "Reg") != -1) { regTotal++; regEval++; if(evalClose > signals[i].signalPrice) regCorrect++; } else if(StringFind(signals[i].type, "Hidden") != -1) { hidTotal++; hidEval++; if(evalClose > signals[i].signalPrice) hidCorrect++; } totalEvaluated++; } else if(StringFind(signals[i].type, "Bearish") != -1) { if(StringFind(signals[i].type, "Reg") != -1) { regTotal++; regEval++; if(evalClose < signals[i].signalPrice) regCorrect++; } else if(StringFind(signals[i].type, "Hidden") != -1) { hidTotal++; hidEval++; if(evalClose < signals[i].signalPrice) hidCorrect++; } totalEvaluated++; } } double overallAccuracy = (totalEvaluated > 0) ? (double)(regCorrect + hidCorrect) / totalEvaluated * 100.0 : 0.0; double regAccuracy = (regEval > 0) ? (double)regCorrect / regEval * 100.0 : 0.0; double hidAccuracy = (hidEval > 0) ? (double)hidCorrect / hidEval * 100.0 : 0.0; Print("----- Backtest Signal Evaluation -----"); Print("Total Signals Generated: ", ArraySize(signals)); Print("Signals Evaluated: ", totalEvaluated); Print("Overall Accuracy: ", DoubleToString(overallAccuracy, 2), "%"); Print("Regular Signals: ", regTotal, " | Evaluated: ", regEval, " | Accuracy: ", DoubleToString(regAccuracy, 2), "%"); Print("Hidden Signals: ", hidTotal, " | Evaluated: ", hidEval, " | Accuracy: ", DoubleToString(hidAccuracy, 2), "%"); }
Tests und Ergebnisse
Nachdem Sie Ihren EA mit MetaEditor erfolgreich kompiliert haben, ziehen Sie ihn zum Testen auf den Chart. Stellen Sie sicher, dass Sie ein Demokonto verwenden, um kein echtes Geld zu riskieren. Sie können auch den RSI-Indikator zu Ihrem Chart hinzufügen, um beim Testen Ihres EA eine einfache Signalbestätigung zu erhalten. Gehen Sie dazu auf die Registerkarte „Indikatoren“, wählen Sie den RSI-Indikator im Ordner „Panels“ aus und stellen Sie die gewünschten Parameter ein, die mit denen Ihres EA übereinstimmen müssen. Im folgenden GIF sehen Sie, wie Sie das RSI-Indikator-Fenster zu einem MetaTrader 5-Chart hinzufügen können. Sie können auch das bestätigte Signal sehen, eine reguläre Aufwärts-Divergenz auf einem einminütigen Zeitrahmen.
Abb. 5. Einstellung Anzeige und Testergebnis 1
Nachfolgend sehen Sie einen weiteren Test, den wir für Boom 500 durchgeführt haben. Sowohl die Kursentwicklung als auch der RSI-Indikator bestätigen ein Verkaufssignal.
Abb. 6. Testergebnis 2
Ein weiterer Test wurde mittels Backtests auf dem unten stehenden GIF durchgeführt, das mehrere positive Verschiebungen zeigt. Wenn Sie genau hinsehen, werden Sie sowohl versteckte Fortsetzungssignale als auch reguläre Signale erkennen. Einige Signale müssen jedoch trotz ihrer positiven Auswirkungen herausgefiltert werden, da sie nicht bestätigt wurden.
Abb. 7. Testergebnis 3
Schlussfolgerung
Dieses Instrument hat sich als extrem preisorientiert erwiesen, was das Hauptziel unserer Serie ist, so viele Preisaktionsanalyse-Tools wie möglich zu entwickeln. Ich habe es wirklich zu schätzen gewusst, wie effektiv der RSI-Indikator mit der Preisbewegung interagiert, indem er positive Signale aus Divergenzen extrahiert. Die von uns durchgeführten Tests haben vielversprechende Ergebnisse und einen positiven Trend gezeigt.
Ich bin jedoch der Meinung, dass es an der Zeit ist, eine weitere Verbesserung einzuführen, die externe Bibliotheken zur präzisen und genauen Identifizierung von Schwüngen nutzt und damit die Signalgenauigkeit verbessert. Ich empfehle Ihnen, das Instrument gründlich zu testen und seine Parameter an Ihren Handelsstil anzupassen. Denken Sie daran, dass jedes generierte Signal vor dem Einstieg gegengeprüft werden sollte, da das Instrument Ihnen helfen soll, den Markt zu beobachten und Ihre Gesamtstrategie zu bestätigen.
Datum | Name des Werkzeugs | Beschreibung | Version | Aktualisierungen | Hinweis |
---|---|---|---|---|---|
01/10/24 | Chart Projector | Skript zur Überlagerung der Kursentwicklung des Vortages mit Geistereffekt. | 1.0 | Erste Veröffentlichung | Erstes Werkzeug in Lynnchris Tool Chest |
18/11/24 | Analytical Comment | Er liefert Informationen zum Vortag in Tabellenform und nimmt die zukünftige Marktentwicklung vorweg. | 1.0 | Erste Veröffentlichung | Zweites Werkzeug in Lynnchris Tool Chest |
27/11/24 | Analytics Master | Reguläre Aktualisierung der Marktmetriken alle zwei Stunden. | 1.01 | Zweite Veröffentlichung | Drittes Werkzeug in Lynnchris Tool Chest |
02/12/24 | Analytics Forecaster | Reguläre Aktualisierung der Marktmetriken alle zwei Stunden mit Telegram-Integration. | 1.1 | Dritte Auflage | Werkzeug Nummer 4 |
09/12/24 | Volatility Navigator | Der EA analysiert die Marktbedingungen anhand der Indikatoren Bollinger Bands, RSI und ATR. | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 5 |
19/12/24 | Mean Reversion Signal Reaper | Analysiert den Markt anhand der Strategie „Umkehr zur Mitte“ und liefert Signale. | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 6 |
9/01/25 | Signal-Impuls | Analysator für mehrere Zeitrahmen. | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 7 |
17/01/25 | Metrics Board | Bedienfeld mit Taste für die Analyse. | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 8 |
21/01/25 | External Flow | Analytik durch externe Bibliotheken. | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 9 |
27/01/25 | VWAP | Volumengewichteter Durchschnittspreis | 1.3 | Erste Veröffentlichung | Werkzeug Nummer 10 |
02/02/25 | Heikin Ashi | Trendglättung und Identifizierung von Umkehrsignalen | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 11 |
04/02/25 | FibVWAP | Signalerzeugung durch Python-Analyse | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 12 |
14/02/25 | RSI DIVERGENCE | Kursentwicklung versus RSI-Divergenzen | 1.0 | Erste Veröffentlichung | Werkzeug Nummer 13 |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17198
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.






- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.