
Kausalanalyse von Zeitreihen mit Hilfe der Transferentropie
Einführung
Die Transferentropie ist ein statistisches Instrument, das die Menge an Informationen quantifiziert, die von einer Zeitreihe auf eine andere übertragen wird, und Einblicke in die Art und das Verhalten einer Zielvariablen gewährt. In diesem Artikel befassen wir uns mit dem Konzept der statistischen Kausalität, die anhand der Transferentropie berechnet wird. Wir untersuchen, wie diese Methode die Richtung des kausalen Einflusses zwischen verschiedenen Prozessen aufzeigen kann. Darüber hinaus wird eine detaillierte Beschreibung einer MQL5-Implementierung zur Messung der Transferentropie gegeben, die zeigt, wie diese Technik praktisch zur Analyse potenziell gekoppelter Zeitreihen eingesetzt werden kann. Durch die Nutzung der Transferentropie wollen wir Variablen identifizieren, die Vorhersageaufgaben verbessern können.
Kausalität
Empirische Daten können trügerisch sein. Nur weil sich zwei Variablen scheinbar parallel zueinander bewegen, heißt das nicht, dass die eine die andere verursacht. Deshalb gilt der Spruch „Korrelation ist keine Kausalität“. Die Korrelation misst lediglich, wie zwei Variablen miteinander verbunden sind, nicht warum sie miteinander verbunden sind. Stellen Sie sich zum Beispiel eine starke Korrelation zwischen dem Verkauf von Speiseeis und dem Aktienkurs im Sommer vor. Das bedeutet nicht, dass der Kauf von Eiscreme die Aktie steigen lässt! Wahrscheinlicher ist ein versteckter Faktor, wie die Jahreszeit selbst, der beide Variablen unabhängig voneinander beeinflusst. Ebenso kann ein Zusammenhang zwischen den Aktien eines Unternehmens und den Goldpreisen bestehen, aber die eigentliche Ursache könnte etwas ganz anderes sein, wie die allgemeine Marktstimmung oder die Inflation, die beide Preise beeinflusst. Diese Beispiele zeigen, dass korrelierte Daten irreführend sein können. Sie zeigen eine Verbindung, aber nicht den Grund dafür. Um wirklich zu verstehen, ob eine Sache eine andere verursacht, brauchen wir fortschrittlichere Instrumente.
Das Konzept der Kausalität, also die Vorstellung, dass ein Ereignis ein anderes hervorruft, ist für die wissenschaftliche Forschung von grundlegender Bedeutung. Die genaue Definition von Kausalität ist jedoch eine vielschichtige Herausforderung mit tiefgreifenden philosophischen, physikalischen und statistischen Überlegungen. Im Idealfall würde eine Ursache immer eine einzige Wirkung hervorrufen. Es kann jedoch schwierig sein, einen einzelnen kausalen Faktor aus dem oft komplexen Geflecht von Einflüssen zu isolieren, die sich auf ein Ergebnis auswirken. So kann beispielsweise ein Anstieg des Handelsvolumens mit einem Anstieg des Aktienkurses korrelieren, aber auch andere Faktoren wie die Marktstimmung und die Veröffentlichung von Wirtschaftsdaten können eine wichtige Rolle spielen. In solchen Szenarien verwenden die Forscher statistische Verfahren, um kausale Zusammenhänge abzuleiten.
Die Art der Kausalität, ob deterministisch (garantiertes Ergebnis) oder probabilistisch (Beeinflussung der Wahrscheinlichkeit des nachfolgenden Ereignisses), hängt von dem zugrunde liegenden Prozess ab. In deterministischen Systemen führt das erste Ereignis nachweislich zum zweiten, wie beim vorhersehbaren Fall eines fallen gelassenen Gegenstandes zu beobachten ist. Bei probabilistischen Systemen hingegen liegt der Schwerpunkt darauf, ob das erste Ereignis unsere Fähigkeit verbessert, das Eintreten des zweiten Ereignisses vorherzusagen. So könnten beispielsweise die jüngsten Regenfälle mit der späteren Blüte der Blumen in Verbindung gebracht werden, aber auch andere Umweltfaktoren könnten dazu beitragen. In solchen Fällen stellt sich die Frage, ob die Kenntnis des ersten Ereignisses unsere Fähigkeit verbessert, das zweite Ereignis vorherzusagen.
Der Wirtschaftswissenschaftler Clive Granger entwickelte, aufbauend auf der Arbeit von Norbert Wiener, das Konzept der Kausalbeziehungen und stellte die These auf, dass ein erstes Signal ein zweites Signal verursacht, wenn die zukünftigen Werte des zweiten Signals besser erklärt werden können, wenn man die Informationen aus der Vergangenheit sowohl des ersten als auch des zweiten Signals verwendet, als wenn man nur die verzögerten Werte des zweiten Signals allein verwendet. Granger stützte seine Definition der Kausalität auf zwei Prinzipien. Erstens kann sich eine Wirkung nicht vor ihrer Ursache manifestieren. Zweitens enthält eine Ursache einzigartige Informationen, die auf die Wirkung übertragen werden. Diese Grundsätze legen nahe, dass wir zur Quantifizierung der Kausalität die zeitlichen Eigenschaften der beteiligten Variablen sowie ein gewisses Maß an deren Informationsgehalt verstehen müssen. Daher eignen sich Zeitreihen gut für die Kausalanalyse.
Aufgrund der Beschaffenheit von Zeitreihendaten können wir analysieren, wie Informationen aus einer Reihe zu einem bestimmten Zeitpunkt die Vorhersagbarkeit einer anderen Reihe zu einem späteren Zeitpunkt beeinflussen. Granger definiert Kausalität als eine Verringerung der Unsicherheit. Wenn die Kenntnis der Vergangenheitswerte der Reihe X unsere Vorhersage des zukünftigen Wertes der Reihe Y im Vergleich zu den Vergangenheitswerten von Y selbst verbessert, dann wird gesagt, dass X für Y prädiktiv ist. Auf der Grundlage dieser Idee entwickelte Granger Tests für Kausalität unter Verwendung verzögerter Zeitreihen und autoregressiver Modelle. Er schlug vor, dass es keine kausale Beziehung zwischen X und Y gibt, es sei denn, die Einbeziehung vergangener Werte von X verbessert die Vorhersage zukünftiger Werte von Y erheblich. Diese Verbesserung wird in der Regel durch eine Verringerung des Vorhersagefehlers gemessen, beispielsweise durch eine bessere Anpassung eines Regressionsmodells. Mit Hilfe der Granger-Kausalität lassen sich Beziehungen zwischen Zeitreihen statistisch nachweisen. Es ist jedoch wichtig, seine Grenzen zu beachten. Die Granger-Kausalität zeigt nur eine gerichtete Beziehung auf, nicht unbedingt einen endgültigen Kausalmechanismus. Es könnten auch andere Ursachen im Spiel sein, als die, über die wir Daten haben. Da die Granger-Kausalität im Wesentlichen auf dem Rahmen der Autoregression aufbaut, ist sie zudem am effektivsten bei der Aufdeckung linearer Kausalbeziehungen. Die nichtlineare Kausalität erfordert einen anderen Ansatz.
Mathematisch lässt sich die Granger-Kausalität durch die Betrachtung zweier Zeitreihen, X und Y, ausdrücken. Die verzögerten Werte beider Reihen werden mit X(t-k) und Y(t-k) bezeichnet, was eine Verzögerung bei k darstellt. Die maximale Verzögerung wird mit p bezeichnet. Bei der Anwendung des Autoregressionsmodells wird der zukünftige Wert von Y auf seine eigenen vergangenen Werte regressiert.
Dieser Ausdruck berücksichtigt den zukünftigen Wert von Y nur in Bezug auf seine vergangenen Werte. Durch die Einführung von X in das Modell werden die zukünftigen Werte in Form von Vergangenheitswerten von X und Y ausgedrückt.
Wenn die Einbeziehung der Vergangenheitswerte von X die Vorhersage von Y im Vergleich zu einem Modell, das nur die Vergangenheitswerte von Y verwendet, signifikant verbessert, dann wird gesagt, dass X eine Granger-Ursache für Y ist. Dies wird in der Regel durch Testen der Nullhypothese, dass die Koeffizienten gemeinsam Null sind, beurteilt. Wenn diese Nullhypothese abgelehnt wird, bedeutet dies, dass X signifikante Vorhersageinformationen über Y liefert, die über das hinausgehen, was allein in den Vergangenheitswerten von Y enthalten ist. Um zu prüfen, ob X eine Granger-Ursache für Y ist, vergleichen wir die beiden Modelle im Rahmen des Hypothesentests:
- Null-Hypothese: X hat keine Granger-Ursache für Y.
- Alternative Hypothese: X ist die Ursache von Y.
Ein F-Test wird verwendet, um die Anpassung des eingeschränkten Modells (ohne X) und des uneingeschränkten Modells (mit X) zu vergleichen, indem die Residuen der jeweiligen Modelle untersucht werden. Die eingeschränkte Summe der quadrierten Residuen sind die Residuen aus dem Modell ohne X, und die unbeschränkte Summe der quadrierten Residuen stammt aus dem Modell mit X. Die F-Statistik wird wie folgt berechnet:
Dabei ist n die Anzahl der Beobachtungen. Die berechnete F-Statistik wird mit dem kritischen Wert aus der F-Verteilung mit p und n - 2p - 1 Freiheitsgraden verglichen. Ist die F-Statistik größer als der kritische Wert, wird die Nullhypothese zurückgewiesen und die Schlussfolgerung gezogen, dass X die Ursache für Y ist. Alternativ kann die F-Statistik auch mit Hilfe einer einseitigen Varianzanalyse (ANOVA) berechnet werden. Deren Formel ist unten angegeben.
Übertragung der Entropie
In den Anfängen der Informationstheorie nutzten die Wissenschaftler die wechselseitige Information, um zu verstehen, wie gekoppelte Prozesse zusammenwirken. Dieses Konzept, das auf der Entropie von Claude Shannon beruht, gibt Aufschluss darüber, ob sich die Informationen in einer Zeitreihe mit denen einer anderen überschneiden. Einfacher ausgedrückt: Es zeigt, ob wir beide Reihen zusammen mit weniger Informationen kodieren können als wenn wir sie getrennt kodieren. Aus diesem Grund wird die wechselseitige Information manchmal auch als Redundanz bezeichnet. Ein Prozess teilt Informationen mit einem anderen, sodass der zweite Prozess effizient beschrieben werden kann, indem Informationen, die bereits vom ersten Prozess erfasst wurden, wiederverwendet werden.
Formal ist die wechselseitige Information zwischen zwei stochastischen Prozessen, X(t) und Y(t), gegeben, wenn die Summe ihrer Randentropien die gemeinsame Entropie des kombinierten Systems übersteigt. Diese mathematische Beziehung spiegelt die Verringerung der Unsicherheit des kombinierten Systems im Vergleich zu den einzelnen Prozessen wider. Mit anderen Worten: Sie gibt an, inwieweit Informationen über einen Prozess genutzt werden können, um die dem anderen Prozess innewohnende Entropie zu verringern. Da die Entropie ausschließlich durch die zugrunde liegende Wahrscheinlichkeitsverteilung bestimmt wird, kann jede solche Verteilung durch einen zugehörigen Entropiewert charakterisiert werden. Dieser Wert quantifiziert den Grad der Unerwartetheit, der mit einem bestimmten Ergebnis verbunden ist, angesichts der bekannten Wahrscheinlichkeitsverteilung.
Dieses Konzept ist insbesondere im Zusammenhang mit der Granger-Kausalität von Bedeutung. Bei der Untersuchung potenzieller kausaler Beziehungen zwischen Zeitreihen besteht das Ziel darin, die mit einem Zielprozess verbundene Unsicherheit durch Einbeziehung von Informationen aus einem potenziellen Quellprozess zu verringern. Wenn die Einbeziehung einer sekundären Zeitreihe nachweislich die Entropie der Verteilung des Zielprozesses verringert, deutet dies auf das Vorhandensein eines statistischen kausalen Einflusses von der Quellreihe auf die Zielreihe hin. Diese Verringerung wird als Transferentropie bezeichnet.
Die Transferentropie (TE) baut auf dem Konzept der Kullback-Leibler-Divergenz auf und misst die Richtung der Informationsübertragung zwischen zwei Zeitreihen. Die TE basiert auf der Idee der bedingten wechselseitigen Information und kann durch den Kullback-Leibler (KL)-Abstand, auch bekannt als Kullback-Leibler-Divergenz oder relative Entropie, ausgedrückt werden. Die KL-Divergenz misst die Differenz zwischen zwei Wahrscheinlichkeitsverteilungen. In TE misst der KL-Abstand die Differenz zwischen der gemeinsamen Wahrscheinlichkeitsverteilung des aktuellen Zustands von Y und der vergangenen Zustände von X und Y und dem Produkt der Randverteilungen dieser Zustände. Mathematisch lässt sich die Übertragung von Informationen von einer Zeitreihe X auf eine Zeitreihe Y wie folgt ausdrücken:
wobei y(t+1) der zukünftige Zustand von Y ist, y(t) der vergangene Zustand von Y und x(t) der vergangene Zustand von X ist. Diese Formulierung macht deutlich, dass die Transferentropie misst, wie stark die Wahrscheinlichkeitsverteilung von y(t+1) sich ändert, wenn zusätzlich zu y(t) auch die Informationen von x(t) berücksichtigt werden.
Im Jahr 2009 haben Lionel Barnett, Adam Barrett und Anil Seth gemeinsam die Publikation: "Granger Causality and Transfer Entropy Are Equivalent for Gaussian Variables" verfasst, in der gezeigt wird, dass bei Zeitreihen, die einer Gauß-Verteilung folgen, die Transferentropie der Hälfte der F-Statistik für Granger-Kausalität entspricht.
Dieses Ergebnis liefert die Definition der linearen Transferentropie, die wir später in Code umsetzen werden. Um die nichtlineare Kausalität zu berücksichtigen, erweitern wir das Konzept der Unsicherheitsreduktion in Anlehnung an die Arbeit von Thomas Schreiber, der die Zeitreihen als Markov-Prozess mit unterschiedlichen Übergangswahrscheinlichkeitsverteilungen behandelt.
Schreibers Ansatz zur Modellierung der Unsicherheitsreduktion nutzt die Informationstheorie, indem er die Zeitreihen X(t) und Y(t) als Markov-Prozesse mit bekannten Übergangswahrscheinlichkeiten p(x) und q(x) behandelt. Im Gegensatz zum autoregressiven Modell von Granger, das sich auf lineare Modelle stützt, verwendet dieser Ansatz die bedingte wechselseitige Information, um die Informationsübertragung zu beschreiben. Da die wechselseitige Information aus der Differenz der Entropien abgeleitet wird, erhält man die bedingte wechselseitige Information, indem man jeden Entropieterm auf zusätzliche Informationen konditioniert. Die Transferentropie wird dann berechnet, indem die verzögerten Variablen in die Gleichung der bedingten wechselseitigen Information eingesetzt werden, sodass der Informationstransfer von X(t) nach Y(t) zu einer bestimmten Verzögerung k unter Verwendung der bedingten wechselseitigen Entropie analysiert werden kann.
Rechnerisch ist diese Methode attraktiv, weil die gemeinsame Entropie nur eine Wahrscheinlichkeitsverteilung erfordert. Die Transferentropie für eine einzelne Verzögerung k kann als vier getrennte gemeinsame Entropieterme ausgedrückt werden, die sich leicht mit einer genauen Wahrscheinlichkeitsverteilung aus den Daten berechnen lassen. Der Vorteil dieser Formel ist, dass sie mehr verzögerte Dimensionen verarbeiten kann. Jede zusätzliche Verzögerung erhöht jedoch die Dimensionalität des Zustandsraums um zwei, was die Fähigkeit zur genauen Quantifizierung der Transferentropie aufgrund des exponentiellen Wachstums der endlichen Daten, die mit der Schätzung der Wahrscheinlichkeitsdichten verbunden sind, erheblich beeinträchtigt.
Eine wesentliche Stärke dieses Ansatzes liegt in seiner nicht-parametrischen Natur. Im Gegensatz zu anderen Methoden werden keine über die Stationarität hinausgehenden Annahmen über die zugrundeliegende Datenverteilung getroffen, sodass eine Anwendung ohne vorherige Kenntnis der datenerzeugenden Prozesse möglich ist. Dieser Vorteil ist jedoch mit einer Einschränkung verbunden: Die Ergebnisse hängen in hohem Maße von einer genauen Schätzung der zugrunde liegenden Verteilung ab. Die Transferentropie erfordert eine Annäherung an die tatsächliche Wahrscheinlichkeitsverteilung der beteiligten stochastischen Prozesse, wobei begrenzte Daten zur Berechnung der vier Entropieterme verwendet werden. Die Genauigkeit dieser Schätzung hat erhebliche Auswirkungen auf die Zuverlässigkeit der Ergebnisse der Transferentropie. Vor diesem Hintergrund muss man die Möglichkeit in Betracht ziehen, dass die berechneten Entropiewerte verfälscht sein könnten. Daher müssen wir irgendwie die Robustheit der Ergebnisse ermitteln.
Unser Beharren auf der Verwendung eines nicht-parametrischen Ansatzes zur Schätzung der Transferentropie ist mit der beträchtlichen Herausforderung verbunden, sicherzustellen, dass die Ergebnisse einen gewissen Wahrheitsgehalt haben und nicht nur Müll sind. Daher ist es sinnvoll, einen aussagekräftigeren Ansatz für die Interpretation der Transferentropie in Betracht zu ziehen, der die Bewertung der statistischen Signifikanz des geschätzten Wertes beinhaltet. Bei den üblichen Signifikanztests werden die Zeitreihendaten eine vordefinierte Anzahl von Malen gemischt. Die Transferentropie wird dann für jede gemischte (shuffled) Version berechnet. Der p-Wert wird anschließend als der Anteil der gemischten Daten berechnet, deren Übertragungsentropie niedriger ist als der ursprüngliche Wert.
Bei einem anderen Ansatz muss man die Anzahl der Standardabweichungen berechnen, um die ein Ergebnis vom Mittelwert der gemischten Daten abweicht. Da das Mischen die zeitliche Struktur unterbricht, wird erwartet, dass der Mittelwert der Werte für die gemischte Transferentropie nahe bei Null liegt. Die Streuung der Daten um diesen Mittelwert spiegelt die Bedeutung des ursprünglichen Ergebnisses wider. Der berechnete Wert wird als z-Score bezeichnet. z-Scores erfordern im Vergleich zu p-Werten in der Regel weniger Mischungen, was sie rechnerisch effizienter macht.
Im Falle des p-Wertes ist es das Ziel, eine Wahrscheinlichkeit zu erhalten, die so nahe wie möglich bei Null liegt. Ein z-Score, der eine statistische Signifikanz anzeigt, sollte über 3,0 liegen.
MQL5-Implementierung
Der Code, der die Instrumente zur Quantifizierung der Transferentropie und zur Bestimmung ihrer Bedeutung implementiert, ist in transfer_entropy.mqh enthalten. Die Datei enthält die Definition der Klasse CTransEntropy sowie weitere Hilfsklassen und Funktionen. Dieser Kurs bietet einen Rahmen für die statistische Analyse von Zeitreihendaten, der speziell auf die Bewertung von Kausalbeziehungen zwischen Variablen ausgerichtet ist. Es werden zwei unterschiedliche Methoden zur Quantifizierung der linearen Granger-Kausalität (lineare Transferentropie) und der nichtlinearen Transferentropie vorgestellt. Sie wird in beide Richtungen berechnet und vermittelt ein vollständigeres Bild des Informationsflusses zwischen den Variablen.
Um einer möglichen Nicht-Stationarität in den Daten entgegenzuwirken, wird in der Klasse ein Fensterverfahren eingesetzt. Der Nutzer kann die Fenstergröße und die Schrittweite festlegen, sodass die Daten in kleineren, sich überschneidenden Segmenten analysiert werden können. Dieser Ansatz liefert für jedes Fenster spezifische Ergebnisse und erleichtert die Identifizierung zeitlicher Schwankungen der Kausalitätsstärke. Darüber hinaus werden die mit der Analyse von nicht-stationären Daten verbundenen Herausforderungen gemildert. Die Klasse bietet auch einen integrierten Mechanismus für Signifikanztests. Die Nutzer können die Anzahl der durchzuführenden Datenmischungen angeben, wobei die Randverteilungen erhalten bleiben. Auf der Grundlage dieser gemischten Datensätze berechnet die Klasse p-Werte und z-Scores für die Transferentropie in jeder Richtung. Diese statistischen Werte geben Aufschluss über die Wahrscheinlichkeit, dass die beobachteten kausalen Beziehungen oder der Informationstransfer auf Zufall beruhen, und erhöhen so die Robustheit der Analyse.
Eine Instanz der Klasse wird mit dem parameterlosen Standardkonstruktor instanziiert.
public: CTransEntropy(void) { if(!m_transfer_entropies.Resize(2)) Print(__FUNCTION__, " error ", GetLastError()); }
Die Nutzer sollten dann die Methode Initialize() aufrufen, die das Objekt mit einem bestimmten Datensatz initialisiert und verschiedene Parameter für die Analyse einrichtet.
bool Initialize(matrix &in, ulong endog_index, ulong exog_index, ulong lag, bool maxLagOnly=true, ulong winsize=0,ulong winstride=0) { if(!lag || lag>in.Rows()/2) { Print(__FUNCTION__, " Invalid parameter(s) : lag must be > 0 and < rows/2"); return false; } if(endog_index==exog_index) { Print(__FUNCTION__, " Invalid parameter(s) : endog cannot be = exog "); return false; } if(!m_dataset.Resize(in.Rows(),2)) { Print(__FUNCTION__, " error ", GetLastError()); return false; } if(!m_dataset.Col(in.Col(endog_index),0) || !m_dataset.Col(in.Col(exog_index),1)) { Print(__FUNCTION__, " error ", GetLastError()); return false; } if(!m_wins.Initialize(m_dataset,lag,maxLagOnly,winsize,winstride)) return false; m_tlag = lag; m_endog = endog_index; m_exog = exog_index; m_maxlagonly = maxLagOnly; return true; }
Der erste erforderliche Parameter ist eine Matrix mit mindestens zwei Spalten, wobei die zu analysierenden Zeitreihen in den Spalten der Eingabematrix platziert werden sollten. Bei nicht-stationären Daten empfiehlt es sich, die Daten vorher zu differenzieren. Der zweite und dritte Parameter sind die Spaltenindizes der Eingabedatenmatrix, die die endogenen (abhängigen) Zeitreihen bzw. die exogenen (unabhängigen) Zeitreihen angeben.
Der vierte Parameter, lag, definiert den in der Analyse berücksichtigten Lag-Parameter. Der nächste boolesche Parameter, maxLagOnly, bestimmt, ob lag einen einzelnen Term definiert (wenn true) oder alle verzögerten Werte bis einschließlich lag (wenn false). Der vorletzte Parameter, winsize, gibt die Länge des Fensters an. Ist dieser Wert auf 0 gesetzt, wird keine Fensterung auf die Daten angewendet. Schließlich legt winstride optional die Schrittweite des Fensters für Fensteroperationen fest, d. h. den Schritt zwischen aufeinanderfolgenden Fenstern, wenn sie über die Zeitreihendaten laufen.
Die Methode beginnt damit, dass sichergestellt wird, dass die endogenen und exogenen Indizes nicht identisch sind. Ist dies der Fall, wird eine Fehlermeldung ausgegeben und false zurückgegeben. Die interne Matrix m_dataset wird in ihrer Größe angepasst, um den zu analysierenden bivariaten Datensatz zu speichern. Anschließend werden die durch endog_index und exog_index angegebenen Spalten aus der Eingabematrix in die erste bzw. zweite Spalte von m_dataset kopiert. Wenn Fensterung gewünscht ist, wird die Hilfsklasse CDataWindows verwendet, um die m_dataset-Matrix zu fenstern. Sobald dies geschehen ist, setzt die Methode interne Variablen mit den angegebenen Parametern zur späteren Verwendung.
//+------------------------------------------------------------------+ //|class that generates windows of the dataset to be analyzed | //+------------------------------------------------------------------+ class CDataWindows { private: matrix m_dwins[], m_data; ulong m_lag, m_win_size, m_stride_size; bool m_max_lag_only, m_has_windows; matrix applylags(void) { matrix out=np::sliceMatrixRows(m_data,m_lag); if(m_max_lag_only) { if(!out.Resize(out.Rows(),m_data.Cols()+2)) { Print(__FUNCTION__, " error ", GetLastError()); return matrix::Zeros(1,1); } for(ulong i = 2; i<4; i++) { vector col = m_data.Col(i-2); col = np::sliceVector(col,0,col.Size()-m_lag); if(!out.Col(col,i)) { Print(__FUNCTION__, " error ", GetLastError()); return matrix::Zeros(1,1); } } } else { if(!out.Resize(out.Rows(),m_data.Cols()+(m_lag*2))) { Print(__FUNCTION__, " error ", GetLastError()); return matrix::Zeros(1,1); } for(ulong i = 0,k = 2; i<2; i++) { for(ulong t = 1; t<(m_lag+1); t++,k++) { vector col = m_data.Col(i); col = np::sliceVector(col,m_lag-t,col.Size()-t); if(!out.Col(col,k)) { Print(__FUNCTION__, " error ", GetLastError()); return matrix::Zeros(1,1); } } } } return out; } bool applywindows(void) { if(m_dwins.Size()) ArrayFree(m_dwins); for(ulong i = (m_stride_size+m_win_size); i<m_data.Rows(); i+=ulong(MathMax(m_stride_size,1))) { if(ArrayResize(m_dwins,int(m_dwins.Size()+1),100)<0) { Print(__FUNCTION__," error ", GetLastError()); return false; } m_dwins[m_dwins.Size()-1] = np::sliceMatrixRows(m_data,i-m_win_size,(i-m_win_size)+m_win_size); } return true; } public: CDataWindows(void) { } ~CDataWindows(void) { } bool Initialize(matrix &data, ulong lag, bool max_lag_only=true, ulong window_size=0, ulong window_stride =0) { if(data.Cols()<2) { Print(__FUNCTION__, " matrix should contain at least 2 columns "); return false; } m_data = data; m_max_lag_only = max_lag_only; if(lag) { m_lag = lag; m_data = applylags(); } if(window_size) { m_win_size = window_size; m_stride_size = window_stride; m_has_windows = true; if(!applywindows()) return false; } else { m_has_windows = false; if(m_dwins.Size()) ArrayFree(m_dwins); if(ArrayResize(m_dwins,1)<0) { Print(__FUNCTION__," error ", GetLastError()); return false; } m_dwins[0]=m_data; } return true; } matrix getWindowAt(ulong ind) { if(ind < ulong(m_dwins.Size())) return m_dwins[ind]; else { Print(__FUNCTION__, " Index out of bounds "); return matrix::Zeros(1,1); } } ulong numWindows(void) { return ulong(m_dwins.Size()); } bool hasWindows(void) { return m_has_windows; } };
Wenn die Methode Initialize() erfolgreich abgeschlossen wurde, kann der Nutzer entweder Calculate_Linear_TE() oder Calculate_NonLinear_TE() aufrufen, um die lineare bzw. nichtlineare Transferentropie zu testen. Beide Methoden geben nach Abschluss einen booleschen Wert zurück. Die Methode Calculate_Linear_TE() kann einen einzigen optionalen Parameter, n_shuffles, annehmen. Wenn n_shuffles gleich Null ist (Standardeinstellung), werden keine Signifikanztests durchgeführt.
bool Calculate_Linear_TE(ulong n_shuffles=0) { ulong c = m_wins.numWindows(); matrix TE(c,2); matrix sTE(c,2); matrix pvals(c,2); matrix zscores(c,2); for(ulong i=0; i<m_wins.numWindows(); i++) { matrix df = m_wins.getWindowAt(i); m_transfer_entropies[0] = linear_transfer(df,0,1); m_transfer_entropies[1] = linear_transfer(df,1,0); if(!TE.Row(m_transfer_entropies,i)) { Print(__FUNCTION__, " error ", GetLastError()); return false; } SigResult rlts; if(n_shuffles) { significance(df,m_transfer_entropies,m_endog,m_exog,m_tlag,m_maxlagonly,n_shuffles,rlts); if(!sTE.Row(rlts.mean,i) || !pvals.Row(rlts.pvalue,i) || !zscores.Row(rlts.zscore,i)) { Print(__FUNCTION__, " error ", GetLastError()); return false; } } } m_results.TE_XY = TE.Col(0); m_results.TE_YX = TE.Col(1); m_results.p_value_XY = pvals.Col(0); m_results.p_value_YX = pvals.Col(1); m_results.z_score_XY = zscores.Col(0); m_results.z_score_YX = zscores.Col(1); m_results.Ave_TE_XY = sTE.Col(0); m_results.Ave_TE_YX = sTE.Col(1); return true; }
Die Methode berechnet die lineare Transferentropie nach der Grangers-Methode. Dies ist in der privaten Methode linear_transfer() implementiert. Die letzten beiden Parameter dieser Routine identifizieren die abhängige und unabhängige Variable (Spalte) in der Eingabematrix. Durch zweimaligen Aufruf der Methode mit vertauschten Spaltenindizes erhalten wir die Transferentropie in beide Richtungen.
double linear_transfer(matrix &testdata,long dep_index, long indep_index) { vector joint_residuals,independent_residuals; double entropy=0.0; OLS ols; double gc; vector y; matrix x,xx; matrix joint; if(m_maxlagonly) joint = np::sliceMatrixCols(testdata,2); else { if(!joint.Resize(testdata.Rows(), testdata.Cols()-1)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } matrix sliced = np::sliceMatrixCols(testdata,2); if(!np::matrixCopyCols(joint,sliced,1) || !joint.Col(testdata.Col(indep_index),0)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } } matrix indep = (m_maxlagonly)?np::sliceMatrixCols(testdata,dep_index+2,dep_index+3):np::sliceMatrixCols(testdata,(dep_index==0)?2:dep_index+m_tlag+1,(dep_index==0)?2+m_tlag:END); y = testdata.Col(dep_index); if(dep_index>indep_index) { if(m_maxlagonly) { if(!joint.SwapCols(0,1)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } } else { for(ulong i = 0; i<m_tlag; i++) { if(!joint.SwapCols(i,i+m_tlag)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } } } } if(!addtrend(joint,xx)) return entropy; if(!ols.Fit(y,xx)) return entropy; joint_residuals = ols.Residuals(); if(!addtrend(indep,x)) return entropy; if(!ols.Fit(y,x)) return entropy; independent_residuals = ols.Residuals(); gc = log(independent_residuals.Var()/joint_residuals.Var()); entropy = gc/2.0; return entropy; }
Die Methode Calculate_NonLinear_TE() nimmt neben n_shuffles einen zusätzlichen Parameter, numBins, entgegen. Dieser Parameter legt die Anzahl der Bins fest, die bei der Schätzung der Wahrscheinlichkeitsdichte der Variablen verwendet werden.
bool Calculate_NonLinear_TE(ulong numBins, ulong n_shuffles=0) { ulong c = m_wins.numWindows(); matrix TE(c,2); matrix sTE(c,2); matrix pvals(c,2); matrix zscores(c,2); for(ulong i=0; i<m_wins.numWindows(); i++) { matrix df = m_wins.getWindowAt(i); m_transfer_entropies[0] = nonlinear_transfer(df,0,1,numBins); m_transfer_entropies[1] = nonlinear_transfer(df,1,0,numBins); if(!TE.Row(m_transfer_entropies,i)) { Print(__FUNCTION__, " error ", GetLastError()); return false; } SigResult rlts; if(n_shuffles) { significance(df,m_transfer_entropies,m_endog,m_exog,m_tlag,m_maxlagonly,n_shuffles,rlts,numBins,NONLINEAR_TE); if(!sTE.Row(rlts.mean,i) || !pvals.Row(rlts.pvalue,i) || !zscores.Row(rlts.zscore,i)) { Print(__FUNCTION__, " error ", GetLastError()); return false; } } } m_results.TE_XY = TE.Col(0); m_results.TE_YX = TE.Col(1); m_results.p_value_XY = pvals.Col(0); m_results.p_value_YX = pvals.Col(1); m_results.z_score_XY = zscores.Col(0); m_results.z_score_YX = zscores.Col(1); m_results.Ave_TE_XY = sTE.Col(0); m_results.Ave_TE_YX = sTE.Col(1); return true; }
Zur Schätzung der Wahrscheinlichkeitsdichte wird die Histogramm-Methode verwendet. Sie wurde gewählt, weil sie am einfachsten zu implementieren ist. Die Verantwortung für die Berechnung der verallgemeinerten Version der Transferentropie wird an die privaten Methoden nonlinear_entropy() und get_entropy() delegiert.
double get_entropy(matrix &testdata, ulong num_bins) { vector hist; vector bounds[]; hist=vector::Ones(10); if(!np::histogramdd(testdata,num_bins,hist,bounds)) { Print(__FUNCTION__, " error "); return EMPTY_VALUE; } vector pdf = hist/hist.Sum(); vector lpdf = pdf; for(ulong i = 0; i<pdf.Size(); i++) { if(lpdf[i]==0.0) lpdf[i] = 1.0; } vector ent = pdf*log(lpdf); return -1.0*ent.Sum(); }
Die vier Komponentenwerte, die zur Berechnung der gemeinsamen und unabhängigen bedingten Entropien verwendet werden, werden in nonlinear_transfer() kombiniert, um die endgültige Schätzung zu erhalten.
double nonlinear_transfer(matrix &testdata,long dep_index, long indep_index, ulong numbins) { double entropy=0.0; matrix one; matrix two; matrix three; matrix four; if(m_maxlagonly) { if(!one.Resize(testdata.Rows(),3) || !two.Resize(testdata.Rows(),2) || !three.Resize(testdata.Rows(),2) || !four.Resize(testdata.Rows(),1) || !one.Col(testdata.Col(dep_index),0) || !one.Col(testdata.Col(dep_index+2),1) || !one.Col(testdata.Col(indep_index+2),2) || !two.Col(testdata.Col(indep_index+2),0) || !two.Col(testdata.Col(dep_index+2),1) || !three.Col(testdata.Col(dep_index),0) || !three.Col(testdata.Col(dep_index+2),1) || !four.Col(testdata.Col(dep_index),0)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } } else { if(!one.Resize(testdata.Rows(), testdata.Cols()-1) || !two.Resize(testdata.Rows(), testdata.Cols()-2) || !three.Resize(testdata.Rows(), m_tlag+1)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } matrix deplag = np::sliceMatrixCols(testdata,dep_index?dep_index+m_tlag+1:2,dep_index?END:2+m_tlag); matrix indlag = np::sliceMatrixCols(testdata,indep_index?indep_index+m_tlag+1:2,indep_index?END:2+m_tlag); //one if(!np::matrixCopyCols(one,deplag,1,1+m_tlag) || !np::matrixCopyCols(one,indlag,1+m_tlag) || !one.Col(testdata.Col(dep_index),0)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } //two if(!np::matrixCopyCols(two,indlag,indlag.Cols()) || !np::matrixCopyCols(two,deplag,indlag.Cols())) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } //three if(!np::matrixCopyCols(three,deplag,1) || !three.Col(testdata.Col(dep_index),0)) { Print(__FUNCTION__, " error ", GetLastError()); return entropy; } //four four = deplag; } double h1=get_entropy(one,numbins); double h2=get_entropy(two,numbins); double h3=get_entropy(three,numbins); double h4=get_entropy(four,numbins); // entropy = independent conditional entropy (h3-h4) - joint conditional entropy (h1-h2) entropy = (h3-h4) - (h1-h2); return entropy; }
Umfassende Ergebnisse des Tests können mit der Methode get_results() abgerufen werden, die eine Struktur von Vektoren zurückgibt. Jedes Element dieser Struktur bezieht sich auf einen anderen Aspekt der Ergebnisse, wobei die Länge jedes Vektors von den Parametern abhängt, die mit der Methode Initialize() festgelegt wurden, sowie von der Art der durchgeführten Transferentropieanalyse.
//+------------------------------------------------------------------+ //| Transfer entropy results struct | //+------------------------------------------------------------------+ struct TEResult { vector TE_XY; vector TE_YX; vector p_value_XY; vector p_value_YX; vector z_score_XY; vector z_score_YX; vector Ave_TE_XY; vector Ave_TE_YX; };
Die Eigenschaften der Ergebnisstruktur sind im Folgenden aufgeführt.
Struktur Eigenschaft | Beschreibung |
---|---|
TE_XY | Übertragung von Entropie von der exogenen zur endogene Variable |
TE_YX | Übertragung von Entropie von endogener zu exogene Variable |
z_score_XY | Bedeutung der Transferentropie von der exogenen zur endogenen Variable |
z_score_YX | Bedeutung der Transferentropie von endogener zu exogener Variable |
p_wert_XY | p-value Signifikanz der Übertragung Entropie von exogener zu endogener Variable |
p_wert_YX | p-value Signifikanz der Übertragung Entropie von endogener zu exogener Variable |
Ave_TE_XY | Durchschnittliche Transferentropie von exogener zu endogene Variable |
Ave_TE_YX | Durchschnittliche Transferentropie von endogener zu exogene Variable |
Der Aufruf von get_transfer_entropies() liefert einen Vektor der geschätzten Übertragungsentropien für das letzte Fenster im Datensatz, gemessen in beide Richtungen. Die Reihenfolge der Ergebnisse folgt der Spaltenreihenfolge der an die Klasse übergebenen Originaldaten. Der erste Entropiewert im Vektor entspricht also der Reihe in der ersten Spalte.
Beispiele
Die Funktionalität der Klasse wird durch die Durchführung von Tests an zufällig generierten Zeitreihen mit vorgegebenen Merkmalen geprüft. Die Reihen werden mit den unten aufgeführten Funktionen erzeugt, die beide in generate_time_series.mqh definiert sind.
//+------------------------------------------------------------------+ //|Generate a random walk time series under Geometric Brownian Motion| //+------------------------------------------------------------------+ vector random_series(double initial_val, ulong steps, ulong len, double muu, double sgma) { vector out(len); out[0] = initial_val; int err=0; for(ulong i=1; i<len; i++) { out[i] = out[i-1]*(1.0+(muu*(double(steps)/double(len)))+(MathRandomNormal(muu,sgma,err)*sqrt(double(steps)/double(len)))); if(err) { Print(__FUNCTION__, " MathRandonNormal() ", GetLastError()); return vector::Zeros(1); } } return out; }
Die Funktion random_series() erzeugt eine für die geometrische Brownsche Bewegung charakteristische Zufallszeitreihe. Die Parameter sind:
- initial_val : Der Anfangswert der Zeitreihe.
- steps : Die Gesamtzahl der Schritte beim Random Walk.
- len : Die Länge der zu erstellenden Zeitreihe.
- muu : Der Driftterm (Mittelwert) des GBM.
- sgma : Die Volatilität (Standardabweichung) des GBM.
//+-----------------------------------------------------------------------------------------------+ //|Generate two time series under Geometric Brownian Motion with S2 dependent in part on S1-lagged| //+-----------------------------------------------------------------------------------------------+ matrix coupled_random_series(double init_1,double init_2,ulong steps, ulong len, double muu_1, double muu_2, double sgma_1, double sgma_2, double alpha, double epsilon, ulong lag) { vector gbm1 = random_series(init_1,steps,len,muu_1,sgma_1); vector gbm2 = random_series(init_2,steps,len,muu_2,sgma_2); if(gbm1.Size()!=gbm2.Size()) { return matrix::Zeros(1,1); } matrix out(gbm2.Size()-lag,2); for(ulong i = lag; i<gbm2.Size(); i++) { gbm2[i]=(1.0-alpha)*(epsilon*gbm2[i-lag] + (1.0-epsilon) * gbm2[i]) + (alpha) * gbm1[i-lag]; out[i-lag][0] = gbm2[i]; out[i-lag][1] = gbm1[i]; } return out; }
Die Funktion coupled_random_series() erzeugt zwei gekoppelte Random-Walk-Zeitreihen, wobei die zweite Reihe (gbm2) teilweise von den verzögerten Werten der ersten Reihe (gbm1) abhängig ist. Die Funktion gibt eine zweispaltige Matrix zurück, wobei die abhängige Reihe in der ersten Spalte steht. Die Parameter der Funktion sind wie folgt:
- init_1 : Der Anfangswert der ersten Zeitreihe.
- init_2 : Der Anfangswert der zweiten Zeitreihe.
- steps : Die Gesamtzahl der Schritte beim Random Walk.
- len : Die Länge der zu erstellenden Zeitreihe.
- muu_1 : Der Driftterm der ersten Reihe.
- muu_2 : Der Driftterm der zweiten Reihe.
- sgma_1 : Die Volatilität der ersten Serie.
- sgma_2 : Die Volatilität der zweiten Reihe.
- alpha : Ein Mischparameter für den Einfluss der unabhängigen Reihe auf die abhängige Reihe.
- epsilon : Ein Parameter, der den Einfluss von verzögerten abhängigen Reihenwerten anpasst.
- lag : Die Verzögerung für die Abhängigkeit der abhängigen Reihe von der unabhängigen Reihe.
Um die Fähigkeiten der CTransEntropy-Klasse zu demonstrieren, wurden zwei MetaTrader 5-Skripte vorbereitet. Beide Skripte veranschaulichen, wie die Klasse verwendet werden kann, um einen Datensatz zu analysieren und die Verzögerung der unabhängigen Variable (Zeitreihe) zu ermitteln, die die in der abhängigen Variable (Zeitreihe) beobachtete Abhängigkeit am besten charakterisiert. Die erste Methode beruht auf einer visuellen Inspektion, um den signifikantesten Wert der Richtungsentropie aus einer Reihe von Ergebnissen zu ermitteln, die durch die Analyse der Übertragungsentropie bei verschiedenen Verzögerungen gewonnen wurden. Diese Methode ist in dem Skript LagDetection.ex5 implementiert.
//+------------------------------------------------------------------+ //| LagDetection.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property script_show_inputs #include<transfer_entropy.mqh> #include<generate_time_series.mqh> //--- input parameters input double Init1=100.0; input double Init2=90.0; input ulong Steps=1; input ulong Len=500; input double Avg1=0; input double Avg2=0; input double Sigma1=1; input double Sigma2=1; input double Alph=0.5; input double Epsilon=0.3; input ulong Lag=3; input bool UseSeed = true; input ulong Bins=3; input ENUM_TE_TYPE testtype=NONLINEAR_TE; input ulong NumLagsToTest = 10; input int PlotViewTimeInSecs = 20; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { if(UseSeed) { MathSrand(256); } //--- if(!NumLagsToTest) { Print(" Invalid input parameter value for \'NumLagsToTest\'. It must be > 0 "); return; } matrix series = coupled_random_series(Init1,Init2,Steps,Len,Avg1,Avg2,Sigma1,Sigma2,Alph,Epsilon,Lag); series = log(series); series = np::diff(series,1,false); matrix entropies(NumLagsToTest,2); for(ulong k = 0; k<NumLagsToTest; k++) { CTransEntropy ote; if(!ote.Initialize(series,0,1,k+1)) return; if((testtype==NONLINEAR_TE && !ote.Calculate_NonLinear_TE(Bins)) || (testtype==LINEAR_TE && !ote.Calculate_Linear_TE())) return; vector res = ote.get_transfer_entropies(); entropies.Row(res,k); } Print(" entropies ", entropies); CGraphic* g = np::plotMatrix(entropies,"Transfer Entropies","Col 0,Col 1","Lag","TE"); if(g==NULL) return; else { Sleep(int(MathAbs(PlotViewTimeInSecs))*1000); g.Destroy(); delete g; } return; } //+------------------------------------------------------------------+
Die ersten 11 für den Nutzer zugänglichen Eingabeparameter des Skripts steuern die Eigenschaften der erzeugten Reihe. Die letzten 4 Eingabeparameter konfigurieren verschiedene Aspekte der Analyse:
- Bins : Legt die Anzahl der Bins für die Histogramm-Methode fest, die zur Schätzung der Wahrscheinlichkeitsdichte der Daten verwendet wird.
- testtype : Ermöglicht die Auswahl einer linearen oder nichtlinearen Transferentropieanalyse.
- NumLagsToTest : Legt die maximale Anzahl der Verzögerungen fest, mit denen die Tests durchgeführt werden, beginnend bei 1.
- PlotViewTimeInSecs : Bestimmt die Zeitspanne, die das Diagramm sichtbar bleibt, bevor das Programm beendet wird.
- UseSeed : Bei true wird der Seed für den Zufallszahlengenerator aktiviert, um die Reproduzierbarkeit der Testergebnisse zu gewährleisten.
Das Skript erzeugt zwei Zeitreihen mit einer vorgegebenen Abhängigkeit und schätzt die Transferentropie bei verschiedenen Verzögerungen. Beachten Sie, dass die Daten vor der Analyse differenziert wurden. In diesem Fall ist das wahrscheinlich nicht nötig, aber es ist eine gute Praxis. Die Ergebnisse (Transferentropien) werden dann in einem Diagramm dargestellt, in dem die Transferentropie auf der vertikalen Achse gegen die entsprechende Verzögerung auf der horizontalen Achse aufgetragen ist. Ein erfolgreiches Ergebnis des Tests sollte ein Diagramm mit einer deutlichen Spitze bei der Verzögerung ergeben, die für die Erzeugung der Zufallsreihe gewählt wurde.
Die Ausführung des Programms zeigt, dass der lineare Test erfolgreich die Verzögerungsabhängigkeit identifiziert hat, die zur Erstellung der Reihen verwendet wurde. Erinnern Sie sich, dass die abhängige Reihe in der ersten Spalte des zufällig generierten Datensatzes steht.
Eine erneute Durchführung des Tests mit der Option nichtlinearer Test führt zu ähnlichen Ergebnissen. In diesem Fall ist der Wert der Entropie deutlich geringer. Dies könnte auf die Einschränkungen bei der Verwendung der Histogramm-Methode zur Schätzung der Wahrscheinlichkeitsverteilung der Daten zurückzuführen sein. Es ist auch zu beachten, dass die Anzahl der gewählten Bins die geschätzte Transferentropie beeinflusst.
In der nächsten Demonstration testen wir die Signifikanz der Entropiewerte, die wir bei bestimmten Verzögerungen erhalten. Dies ist in dem Skript LagDetectionUsingSignificance.ex5 implementiert.
//+------------------------------------------------------------------+ //| LagDetectionUsingSignificance.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property script_show_inputs #include<transfer_entropy.mqh> #include<generate_time_series.mqh> //--- input parameters input double Init1=100.0; input double Init2=90.0; input ulong Steps=1; input ulong Len=500; input double Avg1=0; input double Avg2=0; input double Sigma1=1; input double Sigma2=1; input double Alph=0.5; input double Epsilon=0.3; input ulong Lag=3; input bool UseSeed = true; input ulong Bins=3; input ENUM_TE_TYPE testtype=LINEAR_TE; input ulong LagToTest = 3; input ulong NumIterations = 100; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { if(UseSeed) { MathSrand(256); } //--- if(!LagToTest) { Print(" Invalid input parameter value for \'LagToTest\'. It must be > 0 "); return; } matrix series = coupled_random_series(Init1,Init2,Steps,Len,Avg1,Avg2,Sigma1,Sigma2,Alph,Epsilon,Lag); series = log(series); series = np::diff(series,1,false); matrix entropies(1,2); CTransEntropy ote; if(!ote.Initialize(series,0,1,LagToTest)) return; if((testtype==NONLINEAR_TE && !ote.Calculate_NonLinear_TE(Bins,NumIterations)) || (testtype==LINEAR_TE && !ote.Calculate_Linear_TE(NumIterations))) return; vector res = ote.get_transfer_entropies(); entropies.Row(res,0); TEResult alres = ote.get_results(); Print(" significance: ", " pvalue 1->0 ",alres.p_value_XY, " pvalue 0->1 ",alres.p_value_YX); Print(" zscore 1->0 ",alres.z_score_XY, " zscore 0->1 ",alres.z_score_YX); return; } //+------------------------------------------------------------------+
Das Skript hat ähnliche, vom Nutzer einstellbare Eingabeparameter, mit Ausnahme der letzten beiden:
- LagToTest: Legt die spezifische Verzögerung fest, mit der der Test durchgeführt wird.
- NumIterations: Legt fest, wie oft die Daten für Signifikanztests gemischt werden.
Das Skript erzeugt ein Paar abhängiger Reihen und führt einen Test mit der gewählten Verzögerung durch. Die Transferentropie wird zusammen mit dem entsprechenden p-Wert und z-Score in die Registerkarte „Experten“ des Terminals geschrieben.
Beim ersten Durchlauf wird das Skript mit den Parametern LagToTest und Lag auf denselben Wert gesetzt. Die Ergebnisse werden unten angezeigt. Sie zeigen, dass die Reihe in der ersten Spalte von der Reihe in der zweiten Spalte der Matrix abhängig ist.
JS 0 21:33:43.464 LagDetectionUsingSignificance (Crash 1000 Index,M10) significance: pvalue 1->0 [0] pvalue 0->1 [0.66] LE 0 21:33:43.464 LagDetectionUsingSignificance (Crash 1000 Index,M10) zscore 1->0 [638.8518379295961] zscore 0->1 [-0.5746565128024472]
Im zweiten Durchlauf ändern wir nur den Wert des Parameters LagToTest und vergleichen diese Ergebnisse mit denen des vorherigen Durchlaufs.
Beachten Sie die Unterschiede bei den p-Werten und z-Scores. In diesem Fall sind sowohl die p-Werte als auch die z-Scores unbedeutend.
RQ 0 21:33:55.147 LagDetectionUsingSignificance (Crash 1000 Index,M10) significance: pvalue 1->0 [0.37] pvalue 0->1 [0.85] GS 0 21:33:55.147 LagDetectionUsingSignificance (Crash 1000 Index,M10) zscore 1->0 [-0.2224969673139822] zscore 0->1 [-0.6582062358345131]
Die Ergebnisse der Tests zeigen zwar, dass die Klasse CTransEntropy gut abschneidet, aber es gibt eine erhebliche Einschränkung bei der Durchführung von Analysen mit größeren Verzögerungen, insbesondere wenn die Option für mehrere Verzögerungsterme aktiviert ist (maxLagOnly ist falsch). Besonders problematisch ist dies bei dem nichtlinearen Test. Dies ergibt sich aus der Verwendung der Histogramm-Methode zur Schätzung der Verteilung der Daten. Die Verwendung der Histogramm-Methode zur Schätzung von Wahrscheinlichkeitsdichten hat erhebliche Nachteile. Die Wahl der Bin-Breite (oder Bin-Anzahl) wirkt sich erheblich auf das Aussehen und die Genauigkeit des Histogramms aus. Eine zu geringe Bin-Breite kann zu einem verrauschten und fragmentierten Histogramm führen, während eine zu große Bin-Breite wichtige Details verdecken und Merkmale überdecken kann. Das größte Problem ist die Tatsache, dass Histogramme in erster Linie für eindimensionale Daten geeignet sind. Bei höherdimensionalen Daten wächst die Anzahl der Bins exponentiell. Wenn zahlreiche Verzögerungen zu berücksichtigen sind, können die Anforderungen an die verfügbaren Rechenressourcen erheblich strapaziert werden. Es wird daher empfohlen, die maximale Anzahl der Lags gering zu halten, wenn die Analyse unter Berücksichtigung mehrerer Lags mit Hilfe der verallgemeinerten Transferentropie durchgeführt wird.
Schlussfolgerung
Zusammenfassend lässt sich sagen, dass die Klasse CTransEntropy die Analyse der Transferentropie sowohl in linearen als auch in nichtlinearen Zusammenhängen ermöglicht. Durch praktische Demonstrationen haben wir gezeigt, dass es in der Lage ist, den Einfluss einer Zeitreihe auf eine andere zu erkennen und zu quantifizieren, wobei die Ergebnisse durch visuelle Inspektion und Signifikanztests bestätigt wurden. Die Klasse behandelt effektiv verschiedene Szenarien und bietet wertvolle Einblicke in kausale Beziehungen innerhalb von Zeitreihenanwendungen. Allerdings sollten sich die Nutzer der rechnerischen Herausforderungen bewusst sein, die mit der Analyse mehrerer Verzögerungen verbunden sind, insbesondere bei der Anwendung nichtlinearer Methoden. Um eine effiziente Leistung und genaue Ergebnisse zu gewährleisten, ist es ratsam, die Anzahl der berücksichtigten Verzögerungen zu begrenzen. Insgesamt ist die Klasse CTransEntropy ein praktisches Werkzeug, um komplexe Abhängigkeiten aufzudecken und das Verständnis für dynamische Systeme zu verbessern.
Datei | Beschreibung |
---|---|
Mql5\include\generate_time_series.mqh | enthält Funktionen zur Erzeugung zufälliger Zeitreihen. |
Mql5\include\ np.mqh | eine Sammlung von Vektor- und Matrixnutzenfunktionen. |
Mql5\include\ OLS.mqh | enthält die Definition der OLS-Klasse, die die Regression der gewöhnlichen kleinsten Quadrate implementiert. |
Mql5\include\ TestUtilities.mqh | bietet eine Sammlung von Tools zur Vorbereitung von Datensätzen für die OLS-Auswertung. |
Mql5\include\ transfer_entropy | enthält die Definition der Klasse CTransEntropy, die die Transferentropieanalyse implementiert. |
Mql5\scripts\LagDetection.mq5 | ein Skript, das die Funktionalität der Klasse CTransEntropy demonstriert. |
Mql5\scripts\LagDetectionUsingSignificance.mq5 | ein zweites Skript, das einen anderen Ansatz für die Interpretation des Ergebnisses der Verwendung von CTransEntropy veranschaulicht. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/15393





- 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.