MetaTrader5
Hull Moving Average: Ein unverzichtbarer Indikator für MetaTrader 5
Willkommen zurück, Trader-Freunde! Heute möchte ich euch einen spannenden Indikator vorstellen: den Hull Moving Average (HMA). Ich war selbst neugierig und habe ihn implementiert, da ich die Quellen anderer HMA-Implementierungen nicht ganz nachvollziehen konnte. Der HMA hat vier Eingabeparameter, die ich euch hier näherbringen möchte: InpHmaPeriod = 20 InpColorKind = single_color InpColorIndex = color_index_3 InpMaxHistoryBars = 240 Diese Parameter sind selbsterklärend. Die Enumeration ENUM_COLOR_KIND erlaubt es uns, zwischen einfarbiger und mehrfarbiger Darstellung zu wählen, wobei standardmäßig die einfarbige Variante gewählt wird. Im mehrfarbigen Modus zeigt der Hull MA eine andere Farbe für steigende und fallende Werte. Im einfarbigen Modus legt ENUM_COLOR_INDEX die Farbe des Hull MA fest. Standardmäßig ist die Farbe grau; bei Aufwärtstrends wird sie grün und bei Abwärtstrends rot. Ihr könnt das in den folgenden Bildern sehen: Hier ist der Code für den HMA: //+------------------------------------------------------------------+
//| MelzHull.mq5 |
//| Copyright 2022, wm1@gmx.de |
//| https://melz.one |
//+------------------------------------------------------------------+
/*
=== Meine Hull Moving Average Implementierung
In meinem Indikator könnt ihr zwischen einfarbiger und mehrfarbiger Darstellung für die Indikatorlinie wählen.
*/
enum ENUM_COLOR_KIND { // einfarbige oder wechselnde Farben
single_color,
multi_color
};
enum ENUM_COLOR_INDEX { // Index der Indikatorfarben
color_index_0,
color_index_1,
color_index_2,
color_index_3,
color_index_4,
color_index_5,
color_index_6
};
#property copyright "Copyright 2022 by W. Melz, wm1@gmx.de"
#property link "https://melz.one"
#property version "1.00"
#property description "Implementierung meines Hull Moving Average"
//--- Indikatoreinstellungen
#property indicator_chart_window // im Chartfenster zeichnen
#property indicator_buffers 4 // Buffer für: fullWMA, halfWMA, vHull, cHull
#property indicator_plots 1 // nur eine Linie darstellen
#property indicator_type1 DRAW_COLOR_LINE // als farbige Linie darstellen
// Farbindex zur Auswahl: 0 1 2 3 4 5 6, erweiterbar bis zu 64 Farben
#property indicator_color1 clrGray,clrGreen,clrRed,clrBlue,clrGreenYellow,clrDodgerBlue,clrFireBrick
#property indicator_width1 1 // Linienstärke
#property indicator_label1 "HMA" // Name des Indikators
//--- Eingabeparameter
input int InpHmaPeriod = 20; // Indikatorperiode, standard 20
input ENUM_COLOR_KIND InpColorKind = single_color; // Art der Indikatorfarbe, einfarbig oder mehrfarbig
input ENUM_COLOR_INDEX InpColorIndex = color_index_3; // Farbe der einfarbigen Anzeige
input int InpMaxHistoryBars = 240; // maximale historische Balken, standard 240
//--- Indikatorpuffer
double valueBuffer[]; // speichert Hull-Indikatorwerte
double colorBuffer[]; // speichert die Farbe des Hull-Indikators
double fullWMABuffer[]; // speichert das Ergebnis der WMA-Berechnung für die volle Periode
double halfWMABuffer[]; // speichert das Ergebnis der WMA-Berechnung für die halbe Periode
//--- Globale Variablen des Indikators
int hmaPeriod, fullPeriod, halfPeriod, sqrtPeriod, maxHistoryBars; // speichert Eingabewerte oder Standardwerte
//+------------------------------------------------------------------+
//| Funktion zur Initialisierung des benutzerdefinierten Indikators |
//+------------------------------------------------------------------+
int OnInit() {
ENUM_INIT_RETCODE result = checkInput(); // Überprüfen der Eingabeparameter
SetIndexBuffer(0,valueBuffer,INDICATOR_DATA); // Zuordnung des Indikatorpuffers
SetIndexBuffer(1,colorBuffer,INDICATOR_COLOR_INDEX); // Zuordnung der Kerzenfarbe des Indikators
SetIndexBuffer(2,fullWMABuffer,INDICATOR_CALCULATIONS); // Zuordnung des Ergebnisses der vollen WMA-Berechnung
SetIndexBuffer(3,halfWMABuffer,INDICATOR_CALCULATIONS); // Zuordnung des Ergebnisses der halben WMA-Berechnung
IndicatorSetInteger(INDICATOR_DIGITS,_Digits); // Setzen der Indikatorstellen
string shortName = StringFormat("HMA(%d)",hmaPeriod); // Name für DataWindow und Indikatorunterfenster
IndicatorSetString(INDICATOR_SHORTNAME,shortName);
PlotIndexSetString(0,PLOT_LABEL,shortName);
// Berechnung der globalen Werte für den Indikator
fullPeriod = hmaPeriod; // Periode aus der Eingabe
halfPeriod = fullPeriod / 2; // Berechnung der halben Periode
sqrtPeriod = (int)round(sqrt((double)fullPeriod)); // Berechnung der Quadratwurzel der Periode
return(result); // Erfolg oder Misserfolg, Init abgeschlossen
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ENUM_INIT_RETCODE checkInput(void) { // Diese Funktion für eigene Indikatorparameter anpassen
if(InpHmaPeriod <= 0) { // Überprüfung der Eingabewerte
hmaPeriod = 14; // Bei ungültigem Input auf 14 setzen
PrintFormat("Ungültiger Eingabeparameter InpTestPeriod = %d. Indikator verwendet Wert %d für Berechnungen.",InpHmaPeriod,hmaPeriod);
} else
hmaPeriod = InpHmaPeriod; // Periode aus der Eingabe setzen
maxHistoryBars = InpMaxHistoryBars; // andernfalls Eingabewert verwenden
return(INIT_SUCCEEDED); // oder INIT_FAILED
}
//------------------------------------------------------------------
// Funktion zur Deinitialisierung des benutzerdefinierten Indikators
//------------------------------------------------------------------
void OnDeinit(const int reason) {
ArrayFree(valueBuffer);
ArrayFree(colorBuffer);
ArrayFree(fullWMABuffer);
ArrayFree(halfWMABuffer);
}
//+------------------------------------------------------------------+
//| Funktion zur Berechnung des benutzerdefinierten Indikators |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[]) {
if(rates_total < maxHistoryBars + hmaPeriod) // Überprüfung der verfügbaren Balken, Anpassung für die Periode bei der Berechnung anderer Indikatoren
return(0); // Wenn keine Balken verfügbar sind, nichts tun bei diesem Tick.
int startBar; // speichert Indexwerte
if(prev_calculated == 0) { // Wenn keine historischen Balken zuvor berechnet wurden
//Print("--- Berechnung historischer Balken");
// Erster Tick, berechnet alle historischen Balken, ältester Index 0, plus rates_total - InpMaxHistoryBars -1 für Startindex
startBar = rates_total - maxHistoryBars - hmaPeriod - 1;
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN, startBar + hmaPeriod); // Setzt den Plotstart von dem Balken mit Index startBar + hmaPeriod
// Berechnung
CalcHma(startBar,rates_total,close); // Berechnet die MA über das Volumen und vergleicht es mit der Balkengröße
}
if(rates_total - prev_calculated == 1) {
//Print("-- Berechnung neuer Balken");
startBar = rates_total - 1; // Berechnet den aktuellen neuen offenen Balken
// Berechnung
CalcHma(startBar,rates_total,close); // Berechnet die MA über das Volumen und vergleicht es mit der Balkengröße
}
// Berechnung
//Print("- Berechnung bei jedem Tick");
return(rates_total); // Gibt den Wert von prev_calculated für den nächsten Aufruf zurück
}
// Berechnung der MA von startBar bis rates_total im Array buf
void CalcHma(int startBar, const int rates_total, const double &buf[]) {
for(int bar = startBar; bar < rates_total && !IsStopped(); bar++) { // Schleife über die Balken
// (1) Indikatorberechnungen, WMA volle Periode
double sum = 0.0; // speichert den Periodensummenwert für die spätere Division
double wMA = 0.0; // speichert den berechneten Wert für diesen Balken
int wf = 1; // Startgewichtungsfaktor auf 1 setzen
int sumWf = 0; // Summe der Gewichtungsfaktoren auf 0 setzen
for(int i = fullPeriod - 1; i >= 0 ; i--) { // Schleife über die volle Periode für den aktuellen Balken
// sum += getPrice(open,high,low,close,(bar - i)) * wf; // Preis abrufen und Preise über n Balken addieren, ab ältestem Balken, niedrigster Index
sum += buf[(bar - i)] * wf; // Preis abrufen und Preise über n Balken addieren, ab ältestem Balken, niedrigster Index
sumWf += wf; // Alle Gewichtungsfaktoren zur Division addieren
wf += 1; // Gewichtungsfaktoren für die lineare Gewichtung des nächsten neueren Balkens erhöhen
}
wMA = sum / sumWf; // Berechnung des linear gewichteten Durchschnittswertes für die volle MA-Periode
fullWMABuffer[bar] = wMA; // Wert im Puffer für die spätere Verwendung speichern
// (2) Indikatorberechnungen, WMA halbe Periode
sum = 0.0 // speichert den Periodensummenwert für die spätere Division
wMA = 0.0 // speichert den berechneten Wert für diesen Balken
wf = 1 // Startgewichtungsfaktor auf 1 setzen
sumWf = 0 // Summe der Gewichtungsfaktoren auf 0 setzen
for(int i = halfPeriod - 1; i >= 0 ; i--) { // Schleife über die halbe Periode für den aktuellen Balken
// sum += getPrice(open,high,low,close,(bar - i)) * wf; // Preis abrufen und Preise über n Balken addieren, ab ältestem Balken, niedrigster Index
sum += buf[(bar - i)] * wf; // Preis abrufen und Preise über n Balken addieren, ab ältestem Balken, niedrigster Index
sumWf += wf; // Alle Gewichtungsfaktoren zur Division addieren
wf += 1 // Gewichtungsfaktoren für die lineare Gewichtung des nächsten neueren Balkens erhöhen
}
wMA = sum / sumWf; // Berechnung des linear gewichteten Durchschnittswertes für die halbe MA-Periode
halfWMABuffer[bar] = wMA; // Wert im Puffer für die spätere Verwendung speichern
// (3) Indikatorberechnungen, Hull berechnen
sum = 0.0 // speichert den Periodensummenwert für die spätere Division
wf = 1 // Startgewichtungsfaktor auf 1 setzen
sumWf = 0 // Summe der Gewichtungsfaktoren auf 0 setzen
for(int i = sqrtPeriod - 1; i >= 0 ; i--) { // Schleife über die halbe Periode für den aktuellen Balken
sum += (2 * halfWMABuffer[bar - i] - fullWMABuffer[bar - i]) * wf;// Berechnung der Summe der Quadratwurzel(Periode) und Multiplikation mit dem Gewichtungsfaktor
sumWf += wf; // Alle Gewichtungsfaktoren zur Division addieren
wf += 1 // Gewichtungsfaktoren für die lineare Gewichtung des nächsten neueren Balkens erhöhen
}
wMA = sum / sumWf; // Berechnung des linear gewichteten Durchschnittswertes für die halbe MA-Periode
valueBuffer[bar] = wMA; // Speichert den HMA zur Anzeige
// (4) Indikatorfarbberechnungen, anpassen nach Bedarf
colorBuffer[bar] = getColor(bar);
}
}
// Berechnung der Farbe für jeden Balken, nach Bedarf anpassen
double getColor(int bar) {
double retval; // Speichert den Rückgabewert
if(InpColorKind == single_color) // Einfarbige Darstellung
retval = InpColorIndex; // blau
// retval = InpHullColor;
else { // Mehrfarbige Darstellung, standard ist grau
retval = 0 // grau
if(valueBuffer[bar - 1] < valueBuffer[bar]) // Bei Aufwärtstrend, grün
retval = 1 // grün
if(valueBuffer[bar - 1] > valueBuffer[bar]) // Bei Abwärtstrend, rot
retval = 2 // rot
}
return(retval); // Rückgabewert der berechneten Farbe
}
//+------------------------------------------------------------------+ Ich hoffe, ihr findet diesen Indikator genauso nützlich wie ich. Viel Spaß beim Trading!
2023.09.21