
MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 61): Verwendung von ADX- und CCI-Mustern mit überwachtem Lernen
Einführung
Wir setzen unseren Blick darauf fort, wie Indikatorenpaare, die verschiedene Aspekte der Märkte verfolgen, mit maschinellem Lernen gepaart werden können, um ein Handelssystem aufzubauen. In den nächsten Artikeln betrachten wir die Paarung des Average Directional Index (ADX) mit dem Commodity Channel Index (CCI). Der ADX ist in erster Linie ein Trendbestätigungsindikator, während der CCI ein Momentum-Indikator ist. Wir haben diese beiden Eigenschaften bei der Betrachtung der Muster für einzelne Indikatoren in früheren Artikeln wie diesem angesprochen. Zusammenfassend lässt sich sagen, dass die Trendbestätigung misst, wie stark ein bestimmter Preistrend ist, wobei eine Stärke auf die Eignung für einen Einstieg hinweist. Momentum-Indikatoren hingegen messen die Geschwindigkeit der Preisänderung. Je schneller sich die Preise in eine bestimmte Richtung bewegen, desto geringer ist die Wahrscheinlichkeit, dass sie sich nachteilig verändern.
Commodity Channel Index (CCI)
Wir testen unsere Netze, die Indikatorsignale als Eingangssignale verwenden, in Python. Dies liegt daran, dass Python im Vergleich zu MQL5 derzeit einen erheblichen Leistungsvorteil bietet. Wie ich jedoch bereits in den letzten Artikeln erwähnt habe, kann MQL5 diese Leistungen durch die Verwendung von OpenCL erreichen oder ihnen nahe kommen. Dies erfordert jedoch einen Grafikprozessor, um von der Geschwindigkeit von OpenCL profitieren zu können. Wenn beide Sprachen auf vergleichbaren CPUs verwendet werden, hat Python eindeutig die Nase vorn, und deshalb werden wir unsere Modelle damit testen und entwickeln.
MetaTrader hat ein Python-Modul entwickelt, das nicht nur das Laden von Broker-Kursdaten in Python ermöglicht, sondern auch das Platzieren von Handelsgeschäften aus Python heraus. Mehr dazu finden Sie hier und hier. Wir verwenden daher einen Teil dieser Module, um uns bei unserem Broker anzumelden und Kursdaten für unseren MLP mit überwachtem Lernen in Python zu übertragen. Sobald wir diese Preisdaten haben, müssen wir unsere Indikatorfunktionen definieren. Wenn wir mit der GKI beginnen, kann unsere Umsetzung wie folgt aussehen:
def CCI(df, period=14): """ Calculate Commodity Channel Index (CCI) :param df: pandas DataFrame with columns ['high', 'low', 'close'] :param period: lookback period (default 20) :return: Series with CCI values """ # Calculate Typical Price typical_price = (df['high'] + df['low'] + df['close']) / 3 # Calculate Simple Moving Average of Typical Price sma = typical_price.rolling(window=period).mean() # Calculate Mean Deviation mean_deviation = typical_price.rolling(window=period).apply( lambda x: np.mean(np.abs(x - np.mean(x))), raw=True) # Calculate CCI df['cci'] = (typical_price - sma) / (0.015 * mean_deviation) return df[['cci']]
Der CCI ist ein Oszillator, der angibt, wie stark der Kurs eines Vermögenswerts von seinem statistischen Durchschnitt abweicht. Primär kann dies für Händler hilfreich sein, um überkaufte oder überverkaufte Bedingungen zu erkennen. Unsere oben implementierte Funktion nimmt einen Pandas-Datenrahmen mit den Preisspalten „high“, „low“ und „close“ sowie einen Rückblickzeitraum (mit einem Standardwert von 14) zur Berechnung der CCI-Werte. Bei der Berechnung des „typischen Preises“ wird der Durchschnitt des Höchst-, Tiefst- und Schlusskurses so festgelegt, dass er den größten Teil der Kursbewegung über den gemittelten Zeitraum repräsentiert/abdeckt. Er ist das arithmetische Mittel dieser drei Hauptpreise für jeden Zeitrahmen und hilft, die Preisdaten auf einen einzigen repräsentativen Wert zu vereinfachen. Dies trägt dazu bei, das Rauschen von Intraday-Schwankungen zu reduzieren. Dieser Schritt ist von grundlegender Bedeutung, da der CCI auf den Abweichungen von diesem typischen Preis basiert und die Verwendung aller drei (Hoch, Tief und Schlusskurs) zu einer ausgewogenen Betrachtung der Preisentwicklung beiträgt. Daher muss sichergestellt werden, dass der Pandas-Datenrahmen, der die Broker-Kursdaten über das MetaTrader 5-Modul abruft, alle diese Spalten enthält, da fehlende Werte zu Fehlern führen würden.
Ein einfacher gleitender Durchschnitt (SMA) glättet den typischen Preis über den angegebenen Zeitraum, um eine Basislinie zu schaffen. Dazu wird der SMA über die angegebene Eingangsperiode (Standardwert 14) berechnet, sodass er wie eine Referenz wirken kann. Dies ist wichtig, da kurzfristige Preisschwankungen geglättet werden und somit ein repräsentatives „normales“ Preisniveau entsteht. Die Rolling-Funktion benötigt eine ausreichende Anzahl von Datenpunkten (mindestens die Eingangsperiode im Quadrat), um einen gültigen SMA zu berechnen. Wenn der Datensatz zu kurz ist, müssen die anfänglichen NaN-Werte möglicherweise besonders behandelt werden (mit Funktionen wie dropna()... usw.)
Die mittlere Abweichung misst dann die durchschnittliche absolute Abweichung dieser repräsentativen typischen Preise von ihrem SMA und erfasst somit die Preisvolatilität. Für jedes Fenster wird eine Berechnung der absoluten Differenzen zwischen jedem typischen Preis und dem Mittelwert des Fensters durchgeführt, und dann werden sie gemittelt. Dies ist wichtig, weil die mittlere Abweichung die Preisvolatilität misst, die für die Skalierung des CCI unerlässlich ist, der wiederum die typischen Preisschwankungen eines Vermögenswerts widerspiegelt. Dies gewährleistet auch einen Vergleich zwischen verschiedenen Vermögenswerten. Die Anwendung der Lambda-Funktion ist bei großen Datensätzen sehr rechenintensiv, weshalb es sinnvoll ist, vektorisierte Alternativen oder Bibliotheken wie ta-lib zu verwenden. In diesem Fall muss man noch NumPy importieren.
Die CCI-Formel kombiniert also alle oben genannten Komponenten, um einen Wert zu berechnen, der dann zur Normalisierung mit einer Konstante von 0,015 skaliert wird. Die Konstante von 0,015 ist ein Standard-Skalierungsfaktor, mit dem versucht wird, die CCI-Werte im Bereich von ±100 zu halten. Dies wird jedoch nicht immer erreicht, obwohl dies das Ziel ist. Dies ist der Kern der CCI-Formel, da sie rohe Preisabweichungen in einen standardisierten Oszillator umwandelt. Werte über +100 würden dann auf überkaufte Bedingungen hinweisen, während Werte unter -100 auf überverkaufte Bedingungen hindeuten würden. Bei dieser Formel sollte man auf Fehler bei der Division durch Null achten, wenn die mittlere Abweichung Null ist. Dieses Szenario ist zwar selten, aber bei Pauschalpreisen durchaus möglich. Ein kleiner Epsilon-Wert (z. B. 1e-10) kann dann bei Bedarf zum Nenner hinzugefügt werden, um dies abzumildern.
Die return-Anweisung gibt einen Datenrahmen zurück, der nur die Spalte „cci“ enthält. Wenn zusätzliche Spalten für die Fehlersuche oder zusätzliche Analysen erforderlich sind (z. B. „typical_price“), kann diese Anweisung so geändert werden, dass sie diese einschließt.
Durchschnittlicher direktionaler Index (ADX)
Der ADX misst, wie bereits erwähnt, die Trendstärke, unabhängig von der Richtung. Dazu wird der Directional Movement Index verwendet, der hauptsächlich aus 2 Puffern (+DI und -DI) besteht. Diese Funktion nimmt, genau wie der obige CCI, einen Pandas-Data-Frame mit den Spalten „high“, „low“ und „close“ sowie einen Rückblickzeitraum (standardmäßig 14), um die ADX-, +DI- und -DI-Werte zu berechnen. Die Implementierung in Python sieht wie folgt aus:
def ADX(df, period=14): """ Calculate Average Directional Index (ADX) :param df: pandas DataFrame with columns ['high', 'low', 'close'] :param period: lookback period (default 14) :return: DataFrame with ADX, +DI, -DI columns """ # Calculate +DM, -DM, and True Range df['up_move'] = df['high'] - df['high'].shift(1) df['down_move'] = df['low'].shift(1) - df['low'] df['+dm'] = np.where( (df['up_move'] > df['down_move']) & (df['up_move'] > 0), df['up_move'], 0.0 ) df['-dm'] = np.where( (df['down_move'] > df['up_move']) & (df['down_move'] > 0), df['down_move'], 0.0 ) # Calculate True Range df['tr'] = np.maximum( df['high'] - df['low'], np.maximum( abs(df['high'] - df['close'].shift(1)), abs(df['low'] - df['close'].shift(1)) )) # Smooth the values using Wilder's smoothing method (EMA with alpha=1/period) df['+dm_smoothed'] = df['+dm'].ewm(alpha=1/period, adjust=False).mean() df['-dm_smoothed'] = df['-dm'].ewm(alpha=1/period, adjust=False).mean() df['tr_smoothed'] = df['tr'].ewm(alpha=1/period, adjust=False).mean() # Calculate +DI and -DI df['+di'] = 100 * (df['+dm_smoothed'] / df['tr_smoothed']) df['-di'] = 100 * (df['-dm_smoothed'] / df['tr_smoothed']) # Calculate DX df['dx'] = 100 * (abs(df['+di'] - df['-di']) / (df['+di'] + df['-di'])) # Calculate ADX df['adx'] = df['dx'].ewm(alpha=1/period, adjust=False).mean() # Return the relevant columns return df[['adx', '+di', '-di']]
Die beiden berechneten Puffer für direktionale Bewegungen (+DM, -DM) geben Aufwärts- und Abwärtsbewegungen eine Größe, um die Stärke der Richtung zu beurteilen. Sie ergeben sich aus der Differenz zwischen aufeinanderfolgenden Hochs (Aufwärtsbewegung) und dem Gegenteil, der Differenz zwischen aufeinanderfolgenden Tiefs (Abwärtsbewegung). Das ist wichtig, weil dies die Bausteine für +DM und -DM sind, die wiederum die Richtungsimpulse setzen. Durch die Verwendung verschobener Werte ist ein Vergleich über verschiedene Zeiträume hinweg möglich. Eine Zuordnung zu +DM als Aufwärtsbewegung erfolgt, wenn sie die Abwärtsbewegung übersteigt und positiv ist; andernfalls ist +DM 0. In ähnlicher Weise erhält -DM einen Abwärtswert, wenn er den Aufwärtswert übersteigt, damit er positiv wird. Dies hilft, nicht dominante oder negative Bewegungen herauszufiltern.
Die NumPy-Funktion where() ist effizient für vektorisierte Operationen, daher sollten Sie sicherstellen, dass NumPy importiert wird. Die Überprüfung, ob die Berechnungen der Aufwärts- und Abwärtsbewegungen korrekt sind, ist ebenfalls wichtig, um eine falsche Klassifizierung von Bewegungen zu vermeiden. Die Verwendung von shift(1) führt NaN für die erste Zeile ein, das in nachgelagerten Berechnungen oder bei der Rückgabe von Ergebnissen behandelt werden muss. Die Spalten „high“ und „low“ müssen unbedingt numerisch sein.
True Range, TR, die wahre Spanne, misst die Preisvolatilität und trägt dazu bei, Gaps und Intraday-Spannen zu berücksichtigen. Für die Berechnung wird der höchste von drei Werten herangezogen: die Hoch-Tief-Spanne, die absolute Hoch-Schluss-Spanne und die absolute Tief-Schluss-Spanne. Dies hilft bei der Berücksichtigung von Preisunterschieden und Volatilität. Diese Messung der Volatilität der Vermögenswerte ist wichtig, da sie als Nenner für die Normalisierung von +DI und -DI dient. Das bedeutet, dass der ADX die Trendstärke im Verhältnis zur Kursbewegung darstellt. Die Maximum-Funktion von NumPy stellt sicher, dass der größte Bereich ausgewählt wird. Die Behandlung von NaN's aus shift(1) sollte ebenfalls beobachtet werden.
Die Glättung nach Wilder wendet einen exponentiellen gleitenden Durchschnitt mit einem bestimmten Alpha an, um +DM, -DM und TR zu glätten. Alpha ist 1/Periode und die Verwendung von False für den Adjust-Parameter bedeutet, dass die jüngsten Daten stärker gewichtet werden, was der ursprünglichen Methode von Wilder entspricht. Die Glättung trägt zur Verringerung des Rauschens bei und macht die Indikatordatensätze für die Trendanalyse zuverlässiger. Die Funktion ewm ist effizient, aber empfindlich gegenüber dem Parameter alpha.
Die Richtungsindikatoren normalisieren die geglätteten Bewegungen nach der wahren Spanne, um die Stärke der Hausse mit der Stärke der Baisse vergleichen zu können. Die Skalierung durch 100 hilft, sie als Prozentsätze auszudrücken. Dies ist wichtig, da +DI und -DI angeben, wie stark ein Trend im Verhältnis zur Volatilität nach oben oder unten tendiert. Überkreuzungen zwischen +DI und -DI signalisieren daher mögliche Trendwechsel. Der Schutz vor einer Division durch Null kann durch Hinzufügen eines kleinen Epsilonwertes erreicht werden. Der Skalierungsfaktor von 100 ist Standard, um die Interpretation zu erleichtern.
Der DX-Puffer bestimmt die skalierte absolute Differenz zwischen +DI und -DI, dividiert durch deren Summe. Dies ist wichtig für die Einschätzung der relativen Stärke der Richtungsbewegung. Der DX ist ein wichtiger Zwischenschritt zum ADX, der die Aufgabe hat, die „Intensität“ eines Trends (ob Hausse oder Baisse) zu erfassen. Es sollte darauf geachtet werden, dass die Fälle, in denen +di + -di Null sind, behandelt werden, um Divisionsfehler zu vermeiden. Es kann Null zurückgegeben werden, oder die Berechnung kann übersprungen werden.
Der ADX schließlich bildet den Durchschnitt des Richtungsindexes, um die allgemeine Trendstärke zu messen. Die Glättung der DX-Werte bei der Verwendung der Wilders EMA zur Berechnung des ADX spiegelt tendenziell die langfristige Trendstärke wider. Dies ist der letzte ausgegebene Indikator, wobei Werte über 25 einen starken Trend anzeigen, während Werte unter 20 auf einen schwachen oder schwankenden Markt hindeuten. Um die Kohärenz zu gewährleisten, ist es wichtig, dass die Alphawerte über alle Glättungsschritte hinweg konsistent sind.
Die Rückgabeanweisung liefert einen Datenrahmen mit den Spalten „adx“, „+di“ und „-di“, die den vollständigen Satz von Indikatorpuffern für den ADX-Indikator darstellen. Dies liefert Händlern die relevanten Metriken für die Trendanalyse, wobei die Zwischenspalten „dx“ oder „tr“ zur Fehlersuche oder Anpassung des Indikators hinzugefügt werden können.
Die Merkmale
Wir führen die Messwerte dieser beiden Funktionen zusammen, um ein mehrdimensionales Signalfeld zu erstellen, das im Wesentlichen den ADX (für die Trendstärke) und den CCI (für das Momentum) kombiniert, um bestimmte Marktbedingungen zu identifizieren, wie z. B. die Einleitung eines Trends, Umkehrungen oder überkaufte/überverkaufte Zustände. Die Signale, die sich aus der Kombination dieser beiden Indikatoren ergeben, bezeichnen wir im weiteren Sinne als Merkmale. Erinnern Sie sich daran, dass wir in den letzten 4 Artikeln 5 Hauptdatensätze hatten, als wir die Indikatorenkombination aus MA und dem stochastischen Oszillator betrachteten. Diese waren Merkmale, Zustände, Aktionen, Belohnungen und Verschlüsselungen. Diese Merkmale hier sind das Äquivalent zu dem, was wir damals hatten.
Die Paarung dieser beiden Indikatoren wird unter der Prämisse verwendet, dass aus ihrer Paarung 10 Merkmalsmuster generiert werden können. Es könnten natürlich mehr sein, aber für unsere Zwecke reicht diese Zahl aus. Wir ordnen jedem Muster eine Funktion zu. Jede Funktion gibt ein NumPy-Array zurück, in dem jede Spalte eine Bedingung (Dimension) darstellt, wobei 1 bedeutet, dass die Bedingung erfüllt wurde, und 0, dass dies nicht der Fall ist. Die Funktionen nehmen als Eingaben pandas-data-frames. Diese Eingaben haben die Bezeichnungen adx_df (mit den Spalten „adx“, „+di“, „-di“), cci_df (mit der Spalte „cci“) und optional price_df (mit den Spalten „high“, „low“, „close“).
Wir implementieren diese Funktionen in Python, um den Testprozess zu beschleunigen, benötigen aber auch eine ähnliche Implementierung in MQL5 für den Einsatz unseres endgültigen Expert Advisors. Die in MQL5 eingebaute Handhabung der oben genannten Indikatorpunkte im CCI und ADX bedeutet, dass sie kein Problem darstellen, wenn der Expert Advisor verwendet wird. Zusammenfassend lässt sich sagen, dass für Python adx_df und cci_df validiert werden sollten, um sicherzustellen, dass die erforderlichen Spalten vorhanden sind, wobei auch NaN-Werte durch Drop oder Fill behandelt werden, um Fehler bei Vergleichen zu vermeiden. Verschiebeoperationen wie shift(1) führen von Natur aus NaNs für die erste Zeile ein. Die erste Zeile auf 0 zu setzen ist daher eine Standardmethode, um dies zu erreichen. Vektorisierte Operationen sollten idealerweise für große Datensätze eingeführt werden, da die verwendete NumPy-Funktion where() und astype(int) möglicherweise nicht ausreichen.
Alle Merkmale wurden für das Paar EURUSD im täglichen Zeitrahmen vom 2020.01.01 bis 2024.01.01 getestet/trainiert. Der Zeitraum für den Vorwärtstest war 2024.01.01 bis 2025.01.01. Nur die Merkmale 2, 3 und 4 waren in der Lage, vorwärts zu gehen, und daher werden ihre Ergebnisse zusammen mit ihren jeweiligen Beschreibungen aufgeführt.
Feature_0
Dies ist ein Muster, das auf ADX > 25 und CCI kreuzt bei ±100 basiert. Er bietet eine Bestätigung der Ausbruchsdynamik oder des Beginns eines Trends. Die 25er-Marke ist für den ADX von großer Bedeutung. Wenn sie zusammen mit dem CCI-Schlüsselwert von 100 überschritten wird, ist ein neuer Trend sehr wahrscheinlich. Die Verwendung dieser 2 Indikatoren hilft, Rauschen herauszufiltern. Es ist immer wichtig, bei der Suche nach einem Trend zu warten, bis der ADX die 25-Marke testet. Alles, was unter 20 liegt, sollte vermieden werden. Es handelt sich um ein sehr wahrscheinliches Setup bei Vermögenswerten, die für einen Trend bekannt sind, wie einige Aktienindizes usw.
Der aus diesen Signalen generierte Merkmalsvektor ist ein 6-Dim-Vektor. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_0(adx_df, cci_df): """ Creates a 3D signal array with the following dimensions: 1. ADX > 25 crossover (1 when crosses above 25, else 0) 2. CCI > +100 crossover (1 when crosses above +100, else 0) 3. CCI < -100 crossover (1 when crosses below -100, else 0) """ # Initialize empty array with 3 dimensions and same length as input feature = np.zeros((len(adx_df), 6)) # Dimension 1: ADX > 25 crossover feature[:, 0] = (adx_df['adx'] > 25).astype(int) feature[:, 1] = (adx_df['adx'].shift(1) <= 25).astype(int) # Dimension 2: CCI > +100 crossover feature[:, 2] = (cci_df['cci'] > 100).astype(int) feature[:, 3] = (cci_df['cci'].shift(1) <= 100).astype(int) # Dimension 3: CCI < -100 crossover feature[:, 4] = (cci_df['cci'] < -100).astype(int) feature[:, 5] = (cci_df['cci'].shift(1) >= -100).astype(int) # Set first row to 0 (no previous values to compare) feature[0, :] = 0 return feature
if(Index == 0) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] > 25 ? 1.0f : 0.0f); _features[1] = (_adx[1] <= 25 ? 1.0f : 0.0f); _features[2] = (_cci[0] > 100 ? 1.0f : 0.0f); _features[3] = (_cci[1] <= 100 ? 1.0f : 0.0f); _features[4] = (_cci[0] < -100 ? 1.0f : 0.0f); _features[5] = (_cci[1] >= -100 ? 1.0f : 0.0f); } }
Wir haben unseren MLP-Eingangsvektor für dieses Muster in seine wichtigsten Signalbestandteile zerlegt. Das sind: Der ADX lag vorher unter 25, dann lag der ADX über 25, der CCI lag vorher unter +100, jetzt liegt der CCI über +100, der CCI lag vorher über -100, jetzt liegt der CCI unter -100. Bei diesem Aufbau können natürlich nicht alle Situationen gleichzeitig zutreffen. Es ermöglicht uns jedoch, alle unsere Preisdatenpunkte anzupassen, anstatt sie nach der typischen Musterlogik zu gruppieren.
Traditionell ist es jedoch ein Aufwärts-Setup, wenn der ADX von unter 25 beim Schlusskurs über 25 steigt, gefolgt von einem CCI, der ebenfalls von unter +100 beim Schlusskurs über +100 steigt. Ebenso wäre das Abwärtsmuster, wenn der ADX erneut die 25er-Marke überschreitet und darüber schließt, der CCI jedoch die -100er-Marke von oben überschreitet und darunter schließt. Wenn wir strenge Vektoren generieren würden, die nur auf diese „echten“ Auf- oder Abwärts-Setups testen, dann wäre unser Eingangsvektor kleiner als 3 und hätte eine geringere Variabilität in den umfangreichen Testdaten. Die von uns gewählte Option der 6-teiligen Eingabedaten erfasst nicht nur diese traditionellen Metriken, sondern auch „kontinuierliche“ Daten, die andernfalls von der eher „diskreten“/“traditionellen“ Einrichtung ignoriert würden.
Feature_1
Dieses Muster entwickelt sich um ADX > 25 und CCI kreuzt die ±50 Niveaus von entgegengesetzten Seiten. Es handelt sich um einen Momentum-Wiedereinstieg in einen etablierten Trend. Er ist ideal für Fortsetzungsgeschäfte nach einem Rücksetzer, da der ADX die Trendintegrität bestätigt und der CCI die Erholung nach einem kurzen Gegentrend erkennt. Dieses Muster eignet sich für Trendfolger, die nach einem Rücksetzer in einen Trend einsteigen wollen. Das Kreuzen des CCI an der Nulllinie ist ebenfalls ein wichtiger Hinweis, der nicht übergangen werden sollte. Für Händler, die sich bereits im Trend befinden und ihre Gewinne schützen möchten, können bei diesem Signal auch Trailing-Stops gesetzt werden. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_1(adx_df, cci_df): """ Creates a modified 3D signal array with: 1. ADX > 25 (1 when above 25, else 0) 2. CCI crosses from below 0 to above +50 (1 when condition met, else 0) 3. CCI crosses from above 0 to below -50 (1 when condition met, else 0) """ # Initialize empty array with 3 dimensions feature = np.zeros((len(adx_df), 5)) # Dimension 1: ADX above 25 (continuous, not just crossover) feature[:, 0] = (adx_df['adx'] > 25).astype(int) # Dimension 2: CCI crosses from <0 to >+50 feature[:, 1] = (cci_df['cci'] > 50).astype(int) feature[:, 2] = (cci_df['cci'].shift(1) < 0).astype(int) # Dimension 3: CCI crosses from >0 to <-50 feature[:, 3] = (cci_df['cci'] < -50).astype(int) feature[:, 4] = (cci_df['cci'].shift(1) > 0).astype(int) # Set first row to 0 (no previous values to compare) feature[0, :] = 0 return feature
else if(Index == 1) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] > 25 ? 1.0f : 0.0f); _features[1] = (_cci[0] > 50 ? 1.0f : 0.0f); _features[2] = (_cci[1] < 0 ? 1.0f : 0.0f); _features[3] = (_cci[0] < -50 ? 1.0f : 0.0f); _features[4] = (_cci[1] > 0 ? 1.0f : 0.0f); } }
Unsere Funktion generiert einen 5-Dim-Ausgangsvektor von Binärwerten, deren Bestandteile sind: der ADX über dem Niveau von 25 liegt, der vorherige CCI über 0 lag, der aktuelle CCI unter oder gleich -50 ist, der vorherige CCI unter 0 lag, der aktuelle CCI über oder gleich 50 ist. Traditionell ist ein Aufwärts-Setup gegeben, wenn der ADX über 25 liegt und der CCI zuvor unter Null lag, jetzt aber über 50 liegt. Ein Abwärts-Setup wäre, wenn der ADX wieder über 25 liegt und der CCI zuvor über 0 lag, jetzt aber unter oder gleich -50 ist. Die oben genannten Punkte, die für eine eher kontinuierliche/regressive als eine diskrete Zuordnung sprechen, gelten auch hier.
Feature_2
Dieses Muster basiert auf einem ADX > 25, wobei Preis und CCI Divergenzen liefern. Dies ist auch ein Divergenz-Setup oder eine Trendumkehr innerhalb eines Trends. Er verwendet klassische Momentum-Divergenzmuster mit ADX als Trendfilter. Er deutet auf eine mögliche Umkehrung hin, auch wenn der Trend noch aktiv ist. Dieses Muster eignet sich für Situationen, in denen es zur besseren Bestätigung mit der Preisentwicklung oder mit Unterstützung/Widerstand kombiniert wird. Sie ist auch ideal in Situationen, in denen sich die Divergenz nach einer längeren Bewegung bildet. Es ist jedoch Vorsicht geboten, da Divergenzen oft nur ein frühes Signal sind, da viele von ihnen versagen, wenn sie aus einem sehr starken Trend kommen. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_2(adx_df, cci_df, price_df): """ Creates a 5D signal array with: 1. ADX > 25 (1 when above 25, else 0) 2. Lower low (1 when current low < previous low, else 0) 3. Higher CCI (1 when current CCI > previous CCI, else 0) 4. Higher high (1 when current high > previous high, else 0) 5. Lower CCI (1 when current CCI < previous CCI, else 0) """ # Initialize empty array with 5 dimensions feature = np.zeros((len(price_df), 5)) # Dimension 1: ADX above 25 feature[:, 0] = (adx_df['adx'] > 25).astype(int) # Dimension 2: Lower low feature[:, 1] = (price_df['low'] < price_df['low'].shift(1)).astype(int) # Dimension 3: Higher CCI feature[:, 2] = (cci_df['cci'] > cci_df['cci'].shift(1)).astype(int) # Dimension 4: Higher high feature[:, 3] = (price_df['high'] > price_df['high'].shift(1)).astype(int) # Dimension 5: Lower CCI feature[:, 4] = (cci_df['cci'] < cci_df['cci'].shift(1)).astype(int) # Set first row to 0 (no previous values to compare) feature[0, :] = 0 return feature
else if(Index == 2) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2 && CopyRates(Symbol(),Period(),T, 2, _r) >= 2) { _features[0] = (_adx[0] > 25 ? 1.0f : 0.0f); _features[1] = (_r[0].low <= _r[1].low ? 1.0f : 0.0f); _features[2] = (_cci[0] > _cci[1] ? 1.0f : 0.0f); _features[3] = (_r[0].high > _r[1].high ? 1.0f : 0.0f); _features[4] = (_cci[0] < _cci[1] ? 1.0f : 0.0f); } }
Die Ausgabe für unsere Funktion ist ein 6-teiliger Vektor, der aus folgenden Angaben besteht: der ADX über 25 liegt, die Preistiefs sich nach unten bewegt haben, der CCI sich nach oben bewegt hat, die Preishochs sich nach oben bewegt haben und schließlich ob der CCI sich nach unten bewegt hat. Normalerweise würde ein Aufwärts-Setup darin bestehen, dass der ADX über 25 liegt und der Kurs bei steigendem Momentum, wie es der CCI anzeigt, niedrigere Tiefststände verzeichnet. In ähnlicher Weise würde der ADX bei einem Abwärts-Setup immer noch über 25 liegen, während der Preis höhere Höchststände markiert, während der CCI einen Rückgang verzeichnet.
Feature_3
Dieses Muster kombiniert den steigenden ADX mit dem CCI in neutralen Zonen. Es dient als Trendbestätigung mit einer neutralen Zone CCI. Er konzentriert sich auf eine anhaltende Dynamik in einem steigenden oder fallenden Trend. Wenn sich der CCI in einer neutralen Zone (0 bis +/-100) befindet, bedeutet dies oft, dass der Preis eine stetige, aber nicht extreme Bewegung vollzieht. Sie sind in der Regel sicherer als überkaufte/überverkaufte Signale und bergen ein geringeres Risiko eines falschen Einstiegs. Könnte in weniger volatilen Märkten als „Trend-is-your-friend“ betrachtet werden. In Kombination mit der Ausrichtung des gleitenden Durchschnitts oder der Preisstruktur kann er mehr Sicherheit bieten. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_3(adx_df, cci_df): """ Creates a 3D signal array with: 1. ADX rising (1 when current ADX > previous ADX, else 0) 2. CCI between 0 and +100 (1 when in range, else 0) 3. CCI between 0 and -100 (1 when in range, else 0) """ # Initialize empty array with 3 dimensions feature = np.zeros((len(adx_df), 5)) # Dimension 1: ADX rising feature[:, 0] = (adx_df['adx'] > adx_df['adx'].shift(1)).astype(int) # Dimension 2: CCI between 0 and +100 feature[:, 1] = (cci_df['cci'] > 0).astype(int) feature[:, 2] = (cci_df['cci'] < 100).astype(int) # Dimension 3: CCI between 0 and -100 feature[:, 3] = (cci_df['cci'] < 0).astype(int) feature[:, 4] = (cci_df['cci'] > -100).astype(int) # Set first row to 0 (no previous ADX value to compare) feature[0, :] = 0 return feature
else if(Index == 3) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] > _adx[1] ? 1.0f : 0.0f); _features[1] = (_cci[0] > 0 ? 1.0f : 0.0f); _features[2] = (_cci[1] < 100 ? 1.0f : 0.0f); _features[3] = (_cci[0] < 0 ? 1.0f : 0.0f); _features[4] = (_cci[1] > -100 ? 1.0f : 0.0f); } }
Unsere Funktion generiert einen 5-Dim-Vektor, der aus folgenden Elementen besteht: der ADX gestiegen ist, der CCI über 0 liegt, der CCI unter +100 liegt, der CCI unter 0 liegt und der CCI über -100 liegt. Das traditionelle Aufwärts-Setup hierfür ist ein steigender ADX, wobei der CCI über 0, aber unter +100 liegt. Das umgekehrte Abwärts-Muster ist ebenfalls ein steigender ADX, während der CCI unter 0, aber über -100 liegt. Dieses Muster unterstreicht einen steigenden ADX (nicht nur > 25). Darüber hinaus zielen neutrale CCI-Bereiche in der Regel auf frühe Trendentwicklungsphasen ab, anders als beispielsweise das extreme Kreuzen von Feature_0.
Feature_4
Dieses Muster verwendet Setups, bei denen der ADX > 25 mit CCI einer Rückkehr vom Extremum. Es handelt sich um eine fehlgeschlagene Umkehrsituation. Es fängt Momentum-Fallen ein, wenn der CCI ein extremes Niveau durchbricht, es dann aber nicht fortsetzt. Die Hinzufügung des ADX stellt sicher, dass es sich nicht um ein wildes Hin und Her innerhalb einer Konsolidierung handelt. Dieses Muster ist häufig vor Umkehrungen oder starken Rücksetzern zu beobachten. Es eignet sich am besten für volatile Handelssitzungen (oder nachrichtenorientierte Ereignisse wie die Bekanntgabe der Non-Farm-Payrolls). Der Schlüssel dazu ist jedoch, auf den Docht der Kerzen (Pin Bars) an gescheiterten Swing-Tagen zu achten, um eine stärkere Bestätigung zu erhalten. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_4(adx_df, cci_df): """ Creates a 3D signal array with: 1. ADX > 25 (1 when above 25, else 0) 2. CCI dips below -100 then closes above it (1 when condition met, else 0) 3. CCI breaks above +100 then closes below it (1 when condition met, else 0) """ feature = np.zeros((len(cci_df), 5)) # Dimension 1: ADX above 25 feature[:, 0] = (adx_df['adx'] > 25).astype(int) # Dimension 2: CCI dips below -100 then closes above it feature[:, 1] = (cci_df['cci'].shift(1) < -100).astype(int) feature[:, 2] = (cci_df['cci'] > -100).astype(int) # Dimension 3: CCI breaks above +100 then closes below it feature[:, 3] = (cci_df['cci'].shift(1) > 100).astype(int) feature[:, 4] = (cci_df['cci'] < 100).astype(int) return feature
else if(Index == 4) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] > 25 ? 1.0f : 0.0f); _features[1] = (_cci[0] < -100 ? 1.0f : 0.0f); _features[2] = (_cci[1] > -100 ? 1.0f : 0.0f); _features[3] = (_cci[0] > 100 ? 1.0f : 0.0f); _features[4] = (_cci[1] < 100 ? 1.0f : 0.0f); } }
Unsere Funktion feature_4 liefert uns einen 5-dim-Vektor, der binäre Werte von 1 und 0 ausgibt: Der ADX liegt unter 20, der CCI lag unter -100, der CCI liegt jetzt über -100, der CCI lag über +100 und der CCI liegt jetzt unter +100. Ein typisches Aufwärts-Signal, das eine Verschiebung des Momentums anstrebt, wäre also, wenn der ADX unter 20 liegt und der CCI von unter -100 auf über -100 steigt. Ein umgekehrtes Abwärts-Muster wäre demnach auch, wenn der ADX wieder unter 20 liegt, was auf einen schwachen vorherrschenden Trend hindeutet, und der CCI einen Rückgang des positiven Momentums signalisiert, indem er von über +100 beim Schlusskurs unter der +100-Marke übergeht.
Feature_5
Dieses Muster verwendet einfach ADX < 20 mit extremen CCI-Ausschlägen. Es dient als Vorläufer für eine Momentum-Spitze mit geringer Volatilität. Es hilft dabei, Ausbrüche im Frühstadium zu erkennen, indem es auf CCI-Ausbrüche während einer Niedrig-ADX-Phase achtet. Darüber hinaus soll es den Händlern helfen, eine Position aufzubauen, bevor ein Trend einsetzt. Bei der Umsetzung dieses Musters ist es oft eine gute Idee, enge Stopps zu verwenden, da viele Ausreißer einen Fake Out verursachen können. Dieses Muster kann einen zusätzlichen Vorteil bieten, wenn es mit anderen Indikatoren kombiniert wird, z. B. mit Bollinger-Band-Squeezes oder Volumen-Durchbrüchen. Er eignet sich jedoch besser für kleinere Zeitrahmen (z. B. M15 bis H1), da diese den schnellen Momentum-Handel besser ermöglichen. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_5(adx_df, cci_df): """ Creates a 3D signal array with: 1. ADX < 20 (1 when below 20, else 0) - indicates weak trend 2. CCI spikes above 150 (1 when condition met, else 0) - extreme overbought 3. CCI drops below -150 (1 when condition met, else 0) - extreme oversold """ # Initialize array feature = np.zeros((len(cci_df), 5)) # Dimension 1: ADX below 20 (weak trend) feature[:, 0] = (adx_df['adx'] < 20).astype(int) # Dimension 2: CCI spikes above 150 (sudden extreme overbought) # Using 2-bar momentum to detect "sudden" spikes feature[:, 1] = (cci_df['cci'] > 150).astype(int) feature[:, 2] = (cci_df['cci'].shift(1) < 130).astype(int) # Dimension 3: CCI drops below -150 (sudden extreme oversold) # Using 2-bar momentum to detect "sudden" drops feature[:, 3] = (cci_df['cci'] < -150).astype(int) feature[:, 4] = (cci_df['cci'].shift(1) > -130).astype(int) return feature
else if(Index == 5) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] < 20? 1.0f : 0.0f); _features[1] = (_cci[0] > 150 ? 1.0f : 0.0f); _features[2] = (_cci[1] < 130 ? 1.0f : 0.0f); _features[3] = (_cci[0] < -150 ? 1.0f : 0.0f); _features[4] = (_cci[1] > -130 ? 1.0f : 0.0f); } }
Unsere Merkmalsfunktion 5 generiert einen 5-Dim-Vektor, der in unseren MLP eingespeist wird. Erfasste Signale sind: der ADX unter 20 liegt, der CCI über +150 liegt, der CCI zuvor unter +130 lag, der CCI unter -150 liegt und schließlich ob der CCI über -130 lag. Es verwendet den ADX-Marker von über 25, um sicherzustellen, dass ein starker Trend im Spiel ist, zielt darauf ab, CCI-Erholungen von extremen Niveaus zu erkennen und konzentriert sich im Allgemeinen auf Umkehrungen oder Momentumverschiebungen.
Ein typisches Aufwärts-Setup liegt vor, wenn der ADX über 25 liegt, der CCI unter +130 war und jetzt bei +150 liegt. Für eine rückläufige Entwicklung müsste auch der ADX über 25 liegen und der CCI bei -150, nachdem er zuvor -130 getestet hatte.
Feature_6
In diesem Beitrag geht es um das Kreuzen des ADX unter 40 mit einem CCI-Kreuz. Dieses Muster ist ein Ausstiegssignal für die Erschöpfung eines Trends und wird durch einen fallenden ADX gekennzeichnet, der eine Abschwächung des Trends signalisiert. Sobald der CCI wieder in den neutralen Bereich oder auf die entgegengesetzte Seite kippt, deutet dies ebenfalls auf ein nachlassendes Momentum hin. Er kann als Signal zur Risikoreduzierung verstanden werden, das als Marker für die Anpassung des Trailing-Stops oder für Gewinnmitnahmen dient. Es kann auch mit Kerzenmustern kombiniert werden, um sauberere Ausstiege zu erzielen. Allerdings ist es oft nicht ratsam, mit diesem Setup neue Handelsgeschäften einzugehen. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_6(adx_df, cci_df): """ Creates a 3D signal array with: 1. ADX crosses below 40 (1 when crosses down, else 0) 2. CCI crosses below +100 (1 when crosses down, else 0) 3. CCI crosses above -100 (1 when crosses up, else 0) """ # Initialize array with zeros feature = np.zeros((len(cci_df), 6)) # Dimension 1: ADX crosses below 40 feature[:, 0] = (adx_df['adx'] < 40).astype(int) feature[:, 1] = (adx_df['adx'].shift(1) >= 40).astype(int) # Dimension 2: CCI crosses below +100 feature[:, 2] = (cci_df['cci'] < 100).astype(int) feature[:, 3] = (cci_df['cci'].shift(1) >= 100).astype(int) # Dimension 3: CCI crosses above -100 feature[:, 4] = (cci_df['cci'] > -100).astype(int) feature[:, 5] = (cci_df['cci'].shift(1) <= -100).astype(int) return feature
else if(Index == 6) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] < 40? 1.0f : 0.0f); _features[1] = (_adx[1] < 40? 1.0f : 0.0f); _features[2] = (_cci[0] < 100 ? 1.0f : 0.0f); _features[3] = (_cci[1] >= 100 ? 1.0f : 0.0f); _features[4] = (_cci[0] > -100 ? 1.0f : 0.0f); _features[5] = (_cci[1] <= -100 ? 1.0f : 0.0f); } }
Unsere Funktion Feature_6 gibt einen 6-teiligen Vektor aus, der Folgendes umfasst: der ADX jetzt unter 40 liegt, der ADX zuvor über 40 lag, der CCI unter 100 liegt, der CCI zuvor über 100 lag, der CCI über -100 liegt und schließlich, der CCI zuvor unter -100 lag. Ein Abwärts-Terminierungsmuster (das Äquivalent zu aufwärts) liegt vor, wenn der ADX von 40 auf unter 40 fällt und der CCI unter -100 lag, nun aber darüber liegt. Umgekehrt ist das Aufwärts-Beendigungsmuster (gleichbedeutend mit abwärts), wenn der ADX wieder von 40 abfällt und der CCI ebenfalls von +100 abfällt und unter dieses Niveau fällt. Es eignet sich am besten als Ausstiegs- oder Ausstiegswarnmuster, wird hier jedoch nur zu Testzwecken als Einstiegssignal aufgenommen.
Feature_7
Es handelt sich um einen ADX > 25 mit Kreuzen der Nulllinie des CCI. Es ist ein Trendfänger, sobald der CCI die Nulllinie durchquert. Der Grund dafür ist, dass der CCI beim Überschreiten der Nulllinie als Momentum-Drehpunkt fungiert. Da der ADX ebenfalls Stärke bestätigt, bietet dieses Setup saubere Einstiegsmöglichkeiten in der Mitte des Trends. Dieses Muster ist in der Regel zuverlässiger, wenn der Kurs höhere Höchst- oder niedrigere Tiefststände erreicht. Ein Einstieg an mehreren Punkten mit diesem Muster als Signal könnte eine Überlegung wert sein. Backtests sollte für die zeitliche Ausrichtung oder das Sitzungsvolatilitätsfenster durchgeführt werden. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_7(adx_df, cci_df): """ Creates Feature-7 3D signal array with: 1. ADX > 25 (1 when above 25, else 0) - trend strength 2. CCI crosses above 0 (1 when bullish crossover, else 0) 3. CCI crosses below 0 (1 when bearish crossover, else 0) """ # Initialize array with zeros feature = np.zeros((len(cci_df), 5)) # Dimension 1: ADX above 25 (continuous signal) feature[:, 0] = (adx_df['adx'] > 25).astype(int) # Dimension 2: CCI crosses above 0 (bullish) feature[:, 1] = (cci_df['cci'] > 0).astype(int) feature[:, 2] = (cci_df['cci'].shift(1) <= 0).astype(int) # Dimension 3: CCI crosses below 0 (bearish) feature[:, 3] = (cci_df['cci'] < 0).astype(int) feature[:, 4] = (cci_df['cci'].shift(1) >= 0).astype(int) return feature
else if(Index == 7) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] > 25? 1.0f : 0.0f); _features[1] = (_cci[0] > 0? 1.0f : 0.0f); _features[2] = (_cci[1] <= 0 ? 1.0f : 0.0f); _features[3] = (_cci[0] < 0 ? 1.0f : 0.0f); _features[4] = (_cci[1] >= 0 ? 1.0f : 0.0f); } }
Unsere Funktion feature_7 liefert ebenfalls einen 5-Dim-Ausgangsvektor. Dieser Vektor protokolliert: der ADX über 25 liegt, der CCI über 0 liegt, der CCI zuvor unter oder gleich 0 war, der CCI unter 0 liegt und schließlich ob der CCI zuvor über oder gleich 0 war. Die typischen Muster, von denen es abgeleitet ist, zeigen ein Aufwärts-Signal an, wenn der ADX über 25 liegt und der CCI unter 0 war, jetzt aber über 0 liegt. Ähnlich ist das Abwärts-Muster, wenn der ADX wieder über 25 liegt und der CCI nun unter 0 liegt, nachdem er zuvor über 0 lag.
Feature_8
Unser 9. Merkmalssignal stützt sich auf ADX < 20 mit CCI extreme Rücksetzer. Es handelt sich um einen ADX-Stärkefilter plus einen CCI-Indikator für überkaufte/überverkaufte Kurse. Ein klassisches Range-Reversal, das durch den ADX gefiltert wird. In Märkten mit schwacher Tendenz oder in Märkten, die unter der Wippe stehen, sind CCI-Umkehrungen tendenziell besser. Er sollte idealerweise nur dann verwendet werden, wenn der ADX wirklich niedrig ist (unter 20), und er sollte nicht auf Märkten verwendet werden, die sich im Trend befinden. Die Kopplung mit Bollinger-Bändern oder dem RSI kann für eine Multi-Indikator-Bestätigung geeignet sein. Dieses Umkehrmuster könnte ideal für Mean-Reversion-Anlagen wie Rohstoffe oder Währungspaare sein. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_8(adx_df, cci_df): """ Creates a 3D signal array with: 1. ADX < 20 (1 when below 20, else 0) - weak trend 2. CCI rises from -200 to -100 (1 when condition met, else 0) - extreme oversold bounce 3. CCI falls from +200 to +100 (1 when condition met, else 0) - extreme overbought pullback """ # Initialize array with zeros feature = np.zeros((len(cci_df), 5)) # Dimension 1: ADX below 20 (weak trend) feature[:, 0] = (adx_df['adx'] < 20).astype(int) # Dimension 2: CCI rises from -200 to -100 # Using 2-bar lookback to detect the move feature[:, 1] = (cci_df['cci'] > -100).astype(int) feature[:, 2] = (cci_df['cci'].shift(1) <= -200).astype(int) # Dimension 3: CCI falls from +200 to +100 # Using 2-bar lookback to detect the move feature[:, 3] = (cci_df['cci'] < 100).astype(int) feature[:, 4] = (cci_df['cci'].shift(1) >= 200).astype(int) return feature
else if(Index == 8) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 2) { _features[0] = (_adx[0] < 20? 1.0f : 0.0f); _features[1] = (_cci[0] > -100? 1.0f : 0.0f); _features[2] = (_cci[1] <= -200 ? 1.0f : 0.0f); _features[3] = (_cci[0] < 100 ? 1.0f : 0.0f); _features[4] = (_cci[1] >= 200 ? 1.0f : 0.0f); } }
Die Funktionsausgabe von Feature_8 ist ebenfalls ein 5-Dim-Vektor von Binärwerten. Markieren Sie: ADX ist unter 20; CCI ist über -100; CCI war unter -200; CCI ist unter +100; war über +200. Das Aufwärts-Signal, von dem diese Muster abgeleitet werden, ist daher, wenn der ADX unter 20 liegt und der CCI über -100 steigt, nachdem er zuvor -200 getestet hat. Umgekehrt liegt ein rückläufiges Muster vor, wenn der ADX wieder unter 20 liegt und der CCI auf unter +100 fällt, nachdem er zuvor über +200 lag.
Feature_9
Unser letztes Merkmal verwendet wiederum den ADX > 25 mit einem verzögerten Kreuzens des CCI. Dieses Muster stellt eine gegenläufige Signalunterdrückung oder einen Trap-Filter dar. Er ist in der Lage, falsche Durchbrüche oder Fake Outs gegen den vorherrschenden Trend zu erkennen. In solchen Situationen suggeriert der Kurs oft eine Umkehr, doch der CCI weist diese Annahme zurück, indem er den vorherrschenden Trend bestätigt. Er ist für den Schutz vor Trendfallen geeignet. Sie kann mit einer Bestätigung durch Kerzen oder dem Volumenabfall nach einem Fake-Out kombiniert werden. Gut für Händler, die durch falsche vorherige Signale „verbrannt“ wurden und einen Vertrauensfilter benötigen. Unsere Python- und MQL5-Implementierung sieht folgendermaßen aus:
def feature_9(adx_df, cci_df): feature = np.zeros((len(cci_df), 7)) cci = cci_df['cci'].values # Dimension 1 feature[:, 0] = (adx_df['adx'] > 25).astype(int) # Dimension 2: Below 0 then above +50 within 20 periods feature[:, 1] = (cci < 0).astype(int) feature[:, 2] = (np.roll(cci, 1) >= 0).astype(int) below_zero = (feature[:, 1]==1) & (feature[:, 2]==1) feature[:, 3] = 0 for i in np.where(below_zero)[0]: if i+20 < len(cci) and np.max(cci[i+1:i+21]) > 50: feature[:, 3] = 1 break # Dimension 3: Above 0 then below -50 within 20 periods feature[:, 4] = (cci > 0).astype(int) feature[:, 5] = (np.roll(cci, 1) <= 0).astype(int) feature[:, 6] = 0 above_zero = (feature[:, 4]==1) & (feature[:, 5]==1) for i in np.where(above_zero)[0]: if i+20 < len(cci) and np.min(cci[i+1:i+21]) < -50: feature[:, 6] = 1 break return feature
else if(Index == 9) { if(CopyBuffer(A.Handle(), 0, T, 2, _adx) >= 2 && CopyBuffer(C.Handle(), 0, T, 1, _cci) >= 21) { _features[0] = (_adx[0] > 25? 1.0f : 0.0f); _features[1] = (_cci[0] < 0? 1.0f : 0.0f); _features[2] = (_cci[1] >= 0 ? 1.0f : 0.0f); _features[3] = (_cci[ArrayMaximum(_cci,1,20)] > 50 ? 1.0f : 0.0f); _features[4] = (_cci[0] > 0? 1.0f : 0.0f); _features[5] = (_cci[1] <= 0 ? 1.0f : 0.0f); _features[6] = (_cci[ArrayMinimum(_cci,1,20)] < -50 ? 1.0f : 0.0f); } }
Dieses Muster erzeugt einen 7-Dim-Vektor, der eine Abbildung darstellt: ADX über 25 liegt, der CCI unter 0 liegt, der vorherige CCI über 0 lag, der CCI in einem Zeitraum von 20 Balken vor dem letzten Mal über 50 lag, der CCI über 0 liegt, der vorherige CCI unter 0 lag und schließlich ob der CCI in einem Zeitraum von 20 Balken vor dem letzten Mal unter -50 fiel.
Die angegebenen Signalmuster, aus denen diese Signale erzeugt werden, sind wie folgt. Für ein Aufwärts-Signal muss der ADX über 25 liegen, und der CCI muss einen positiven Wert von über 0 wieder erreicht haben, nachdem er in den 20 Bars vor dem Einbruch mit einem Maximum von bis zu 50 darunter gefallen ist. Ebenso liegt ein Abwärts-Muster vor, wenn der CCI gerade unter 0 gefallen ist, nachdem er zuvor mit einem weiteren Tief von mindestens -50 in den 20 Bars vor dem Anstieg über 0 darüber lag. Die Testergebnisse für dieses Muster wurden nicht weitergeleitet und werden daher nicht geteilt, aber alle Quellen sind unten für weitere unabhängige Tests beigefügt.
Schlussfolgerung
Wir haben die gemeinsamen Muster des ADX und des CCI in einem MLP mit überwachtem Lernen untersucht, mit gemischten bis schlechten Ergebnissen im Vorwärtsgang. Dies war ein Versuch, den Eingabevektor kontinuierlicher und weniger diskret zu gestalten, wie wir es in Artikel 57 für den gleitenden Durchschnitt und den stochastischen Oszillator getan haben. Auch wenn dies der Grund dafür sein mag, werden wir in den nächsten Abschnitten bei diesem Ansatz bleiben, da wir auch sehen werden, wie die anderen Methoden des maschinellen Lernens mit diesen Indikatoren verwendet werden können.
Name | Beschreibung |
---|---|
61_0.onnx | MLP für Muster 0 |
61_1.onnx | MLP für Muster 1 |
61_2.onnx | MLP für Muster 2 |
61_3.onnx | MLP für Muster 3 |
61_4.onnx | MLP für Muster 4 |
61_5.onnx | MLP für Muster 5 |
61_6.onnx | MLP für Muster 6 |
61_7.0nnx | MLP für Muster 7 |
61_8.onnx | MLP für Muster 8 |
61_9.onnx | MLP für Muster 9 |
61_x.mqh | Musterverarbeitungsdatei |
SignalWZ_61.mqh | Signalklassendatei |
wz_61.mq5 | Assistent Assemblierter Expert Advisor zum Anzeigen der enthaltenen Dateien |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17910
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.