Bivariate Copulas in MQL5 (Teil 3): Implementierung und Optimierung von Mixed-Copula-Modellen in MQL5
Einführung
In den ersten beiden Artikeln unserer Reihe über Copula-Funktionen wurden die beiden gängigsten Klassen behandelt: elliptische und archimedische Copulas. Diese Analyse zeigte, dass verschiedene Copulas unterschiedliche Arten von Datenabhängigkeiten erfassen. Da Finanzdaten jedoch von Natur aus komplex sind, reicht eine einzige Copula-Familie möglicherweise nicht aus, um das gesamte Spektrum der Abhängigkeitsstrukturen innerhalb eines Datensatzes angemessen abzubilden. In dieser Hinsicht könnten gemischte Copulas diese Einschränkung möglicherweise überwinden, indem sie die Stärken einzelner Copula-Familien kombinieren, um ein breiteres Spektrum an Abhängigkeiten zu modellieren. In diesem Artikel beschreiben wir die Implementierung von gemischten Copula-Modellen unter Verwendung der in unseren vorherigen Beiträgen vorgestellten Familien.
Was ist eine gemischte Copula?
Einfach ausgedrückt ist eine gemischte Copula eine multivariate Funktion, die aus mehreren Copula-Familien zusammengesetzt ist. Formal gesehen ist eine gemischte Copula-Funktion eine Linearkombination verschiedener Copulas, mit der komplexe Abhängigkeitsstrukturen zwischen den Daten erfasst werden.
Die mathematische Definition einer gemischten Copula lautet wie folgt:

In dieser Formel steht w_i für die Gewichte, die den einzelnen Copulas zugewiesen werden, wobei die Summe aller Gewichte gleich eins sein muss. Die Variable s bezeichnet die Gesamtzahl der in der Mischung enthaltenen einzelnen Copulas. Die Parameter der gemischten Copula umfassen die einzelnen Parameter (θi) jeder einzelnen Copula. Diese Struktur bietet gemischten Copulas die Flexibilität, ein breites Spektrum an Abhängigkeitsstrukturen zu modellieren, die eine einzelne Copula nicht erfassen könnte. Das Ziel besteht darin, aus einer hinreichenden Menge von Kandidaten-Copulas ein Modell zu konstruieren, das die Abhängigkeitsstrukturen eines Datensatzes vollständig beschreibt.
Die Ermittlung der optimalen Anzahl und der spezifischen Copula-Familien für einen bestimmten Datensatz würde den Rahmen dieses Artikels sprengen; wir werden jedoch die Implementierung einer gemischten Copula demonstrieren, die sich aus drei unterschiedlichen Familien zusammensetzt. Dieser Ansatz folgt der Methodik, die Fernando Sabino da Silva, Flavio Ziegelmann und João Caldeira in ihrer Arbeit „Mixed Copula Pairs Trading Strategy on the S&P 500“ entwickelt haben. Die Autoren schlagen eine Pairs-Trading-Strategie vor, bei der Clayton-Frank-Gumbel- und Clayton-Student-t-Gumbel-Mixed-Copula zum Einsatz kommen. Diese Kombinationen sind darauf ausgelegt, sowohl die asymmetrische Tail-Abhängigkeit als auch ein mögliches Regimewechselverhalten in den Daten zu erfassen. Die Wirksamkeit dieser Mischungen beruht auf den einzigartigen Stärken der einzelnen Bestandteile, wie aus der nachstehenden Tabelle hervorgeht.
| Copula | Charakteristik | Relevanz |
|---|---|---|
| Clayton | Untere Tail-Abhängigkeit | Erfasst gemeinsame extreme Abwärtsbewegungen. |
| Gumbel | Obere Tail-Abhängigkeit | Erfasst gemeinsame extreme Aufwärtsbewegungen. |
| Frank | Symmetrie ohne Tail-Abhängigkeit | Erfasst die typische Abhängigkeit in der Mitte der Verteilung, ohne davon auszugehen, dass Extreme gemeinsam auftreten. |
| Student-t | Symmetrisch mit einer Tail-Abhängigkeit | Erfasst Fat-Tails in beide Richtungen. In diesem Fall geht man davon aus, dass sich die Kurse bei einem Extremereignis (nach oben oder unten) wahrscheinlich gemeinsam bewegen werden. |
Die Mischungsgewichte geben derjenigen Copula den Vorrang, die die Abhängigkeiten in den Daten am besten beschreibt. Beispielsweise ist die Frank-Copula am effektivsten, wenn die Daten eine geringe bis mäßige Korrelation ohne ausgeprägtes Tail-Verhalten aufweisen. Umgekehrt ist die Student-t-Komponente darauf ausgelegt, extreme Schwankungen zu erfassen, die nicht unbedingt asymmetrisch sind. Die Clayton-Frank-Gumbel-Mischung ist rein archimedisch, wodurch sie sich hervorragend eignet, zwischen Lower-Tail-, Upper-Tail- und annähernd unabhängigen Verhaltensweisen im Zentrum der Verteilung zu unterscheiden. Diese Kombination bietet den doppelten Vorteil von Recheneffizienz und hoher Interpretierbarkeit. Im Gegensatz dazu fungiert die Clayton-Student-t-Gumbel-Mischung als Hybrid; die Student-t-Copula bietet ein Maß an Flexibilität, das der Frank-Copula fehlt, indem sie die Tail-Abhängigkeit in beide Richtungen gleichzeitig erfasst. Dies gilt insbesondere für Daten mit niedrigerem Zeitrahmen, bei denen Volatilitätscluster besonders ausgeprägt sind.
Zwar wird in der zuvor erwähnten Arbeit das Konzept beschrieben, das wir nachbilden möchten, doch fehlen darin konkrete Details zur Umsetzung für gemischte Copulas. Um diese Lücke zu schließen, greifen wir auf eine zweite wissenschaftliche Quelle zurück: „Selection of Mixed Copula Models via Penalized Likelihood“ von Zongwu Cai und Xian Wang, veröffentlicht im Journal of the American Statistical Association (ASA).
Schätzung der Parameter einer gemischten Copula
Der ASA-Artikel stellt einen datengestützten Rahmen für die Auswahl und Schätzung gemischter Copula-Modelle vor, bei dem ein Ansatz auf Basis der penalisierten Likelihood in Kombination mit einem Schrumpfungsoperator zum Einsatz kommt. Die Autoren gehen die Herausforderung an, komplexe Abhängigkeitsstrukturen in Finanzdaten zu erfassen, indem sie die gleichzeitige Kombination und Verfeinerung mehrerer Copula-Familien ermöglichen.
Ihre Methode filtert redundante oder unbedeutende Copula-Komponenten heraus, indem sie beim Verfahren zur Likelihood-Maximierung eine SCAD-Straffunktion (Smoothly Clipped Absolute Deviation) anwendet. Dieser Ansatz ist darauf ausgelegt, die Modellauswahl und die Parameterschätzung gleichzeitig durchzuführen. Mithilfe eines Ansatzes, bei dem die Gewichte mit einem Strafterm versehen werden, reduziert die Methode die Koeffizienten weniger relevanter Copulas auf Null. Der Prozess beginnt mit einer anfänglichen Auswahl geeigneter Copulas für die Mischung, gefolgt von einem Kreuzvalidierungsverfahren zur Bestimmung der optimalen SCAD-Abstimmungsparameter.

SCAD ist ein Regularisierungsverfahren, das eingeführt wurde, um die Variablenselektion und die Parameterschätzung gleichzeitig durchzuführen. Es wurde entwickelt, um die Einschränkungen der Lasso- (L1) und Ridge-Regularisierung (L2) zu überwinden. Insbesondere die Verzerrung, die Lasso durch eine übermäßige Verringerung großer Koeffizienten verursacht. Im Allgemeinen sollte eine ideale Straffunktion drei Eigenschaften aufweisen, die als Oracle-Eigenschaften bezeichnet werden.
- Erstens ist da die Eigenschaft der Sparsität: Die Straffunktion muss in der Lage sein, kleine, irrelevante Koeffizienten auf Null zu setzen.
- Die zweite sogenannte Oracle-Eigenschaft ist die Unverzerrtheit. Das bedeutet, dass große, signifikante Koeffizienten nicht übermäßig reduziert werden dürfen.
- Die letzte Eigenschaft des Oracles ist die Kontinuität. Die Funktion muss stabil bleiben und darf bei geringfügigen Änderungen der Daten nicht unvorhersehbar schwanken.
SCAD wird häufig eingesetzt, da es eine der wenigen Funktionen ist, die alle drei Anforderungen erfüllt. Die SCAD-Strafe wird nicht durch eine einzelne einfache Formel, sondern durch ihre Ableitung definiert. Ihr Verhalten ändert sich je nach Größe des Parameters, auf den sie angewendet wird – in diesem Zusammenhang sind das die Gewichte. Die Methode umfasst drei Schritte.
- Bei kleinen Koeffizienten hat die Straffunktion denselben Effekt wie die Lasso-Regularisierung, nämlich die Koeffizienten in Richtung Null zu drängen.

- Bei Koeffizienten mittlerer Größe nimmt der Lasso-Effekt der Straffunktion quadratisch ab.

- Für große Koeffizienten wird der Strafterm konstant. Sobald ein Koeffizient ausreichend groß ist, unterlässt SCAD dessen Unterdrückung, wodurch der bei der Lasso-Regularisierung auftretende Schätzfehler beseitigt wird.

In den obigen formalen Darstellungen ist λ der Abstimmungsparameter für den Sparsitätsschwellenwert, während a bestimmt, wie schnell sich die Straffung abflacht, und θ der Parameter ist, auf den die Strafe angewendet wird. Der größte Nachteil der SCAD-Straffunktion besteht darin, dass sie die Zielfunktion nichtkonvex macht. Im Gegensatz zur Schalenform von Ridge oder Lasso kann die SCAD-Zielfunktion mehrere lokale Minima aufweisen, was ausgefeilte Optimierungsroutinen erfordert.
Um die optimalen Abstimmungsparameter zu ermitteln, wird ein Kreuzvalidierungsverfahren verwendet. Die Daten werden in Trainings- und Testdatensätze aufgeteilt, und es wird eine Rastersuche über mögliche λ- und a-Werte durchgeführt. Für jedes Paar wird das gemischte Copula-Modell an die Trainingsdaten angepasst, und seine penalisierte Likelihood wird anhand der Testdaten berechnet. Ziel ist es, die Likelihood in Abhängigkeit von den Parametern der Einzelcopulas abzüglich des auf die Gewichte angewandten SCAD-Strafterms zu maximieren.
Sobald die optimalen SCAD-Parameter ermittelt sind, werden die endgültigen Modellparameter anhand des gesamten Datensatzes geschätzt. Da die gleichzeitige Schätzung mehrerer Copulas rechenintensiv ist, kommt bei diesem Verfahren der Expectation-Maximization-Algorithmus (EM-Algorithmus) zum Einsatz.
- Der Prozess beginnt mit einer zweistufigen Schätzung zur Ermittlung der Startwerte. Die Gewichte werden in der Regel gleichmäßig verteilt, und die anfänglichen Copula-Parameter werden entsprechend ihrer jeweiligen Einschränkungen auf gültige Werte festgelegt.
- Der nächste Schritt ist der Erwartungsschritt. In dieser Phase werden die Gewichte verfeinert. Dabei wird berechnet, mit welcher Wahrscheinlichkeit bzw. welchem Anteil jeder Datenpunkt einer bestimmten Copula-Komponente zugeordnet wird.
- Der letzte Schritt des EM-Algorithmus ist der Maximierungsschritt. In dieser Phase werden die einzelnen Copula-Parameter mit einer Likelihood-Maximierung, gewichtet mit den im vorherigen Schritt berechneten Werten, aktualisiert.
Diese Schritte werden so lange wiederholt, bis eine Konvergenz erreicht ist, wodurch sichergestellt wird, dass die gemischte Copula die beobachteten Abhängigkeiten widerspiegelt. Im nächsten Abschnitt wird der Code erläutert, mit dem die soeben beschriebenen Prozeduren umgesetzt werden.
MQL5-Implementierung gemischter Copula-Modelle
Die hier beschriebene Implementierung ist eine Adaption eines ursprünglich in Python geschriebenen Hudson- und Thames-Repositorys. Die Kernlogik für die native MQL5-Implementierung gemischter Copulas ist in der Header-Datei mixed.mqh enthalten. In dieser Datei bildet die abstrakte Klasse CMixedCopula die Grundlage für alle Implementierungen gemischter Copulas. Diese Klasse definiert mehrere geschützte Eigenschaften zur Verwaltung der Mischung.
Die Klasse definiert das Array m_copulas, das die einzelnen Copula-Familien darstellt. Die jeder Copula zugewiesenen Mischungsverhältnisse werden im Vektor m_weights gespeichert. Die spezifischen Parameter für jede einzelne Copula-Komponente sind alle in einem Vektor, m_cop_params, gespeichert. Durch die Verwendung einer abstrakten Basisklasse bleibt die Architektur modular. Dies ermöglicht die Erstellung verschiedener Copula-Kombinationen unter Beibehaltung einer einheitlichen Schnittstelle.
//+------------------------------------------------------------------+ //|base class for mixed copula | //+------------------------------------------------------------------+ class CMixedCopula:public CObject { protected: uint m_num_cops; CBivariateCopula* m_copulas[]; vector m_weights; vector m_cop_params; ENUM_COPULA_MIX m_mixture; public: CMixedCopula(void):m_weights(vector::Zeros(0)), m_cop_params(vector::Zeros(0)), m_num_cops(0), m_mixture(WRONG_VALUE) { } ~CMixedCopula(void) { for(uint i = 0; i<m_copulas.Size(); ++i) if(CheckPointer(m_copulas[i]) == POINTER_DYNAMIC) delete m_copulas[i]; }
Die Klasse CMixedCopula bietet außerdem Methoden für die statistische Analyse, die Generierung von Stichproben und die Modellverwaltung. Zur Auswertung der statistischen Eigenschaften gemischter Copula-Modelle definiert die Klasse die Methode Copula_PDF(), die die gemeinsame Dichte der Copula berechnet.
double Copula_PDF(double u, double v, double _eps = 1.e-5) { u = fmin(fmax(_eps,u),1. - _eps); v = fmin(fmax(_eps,v),1. - _eps); vector pdf_ = vector::Zeros(m_weights.Size()); for(uint i = 0; i<m_copulas.Size(); ++i) pdf_[i] = m_copulas[i]?m_weights[i]*m_copulas[i].Copula_PDF(u,v,false):0.0; return pdf_.Sum(); } vector Copula_PDF(vector& u, vector& v, double _eps = 1.e-5) { vector pdf_ = vector::Zeros(u.Size()); for(uint i = 0; i<m_copulas.Size(); ++i) { if(!m_copulas[i]) continue; m_copulas[i].Set_eps(_eps); pdf_ += m_weights[i]*m_copulas[i].Copula_PDF(u,v); } return pdf_; }
Die Methode Copula_CDF() berechnet die gemeinsame kumulative Verteilungsfunktion der Copula, und die Methode Conditional_Probability() ermittelt die bedingte kumulative Wahrscheinlichkeit.
double Copula_CDF(double u, double v, double _eps = 1.e-5) { u = fmin(fmax(_eps,u),1. - _eps); v = fmin(fmax(_eps,v),1. - _eps); vector cdf_ = vector::Zeros(m_weights.Size()); for(uint i = 0; i<m_copulas.Size(); ++i) cdf_[i] = m_copulas[i]?m_weights[i]*m_copulas[i].Copula_CDF(u,v,false):0.0; return cdf_.Sum(); } vector Copula_CDF(vector& u, vector& v, double _eps = 1.e-5) { vector cdf_ = vector::Zeros(u.Size()); for(uint i = 0; i<m_copulas.Size(); ++i) { if(!m_copulas[i]) continue; m_copulas[i].Set_eps(_eps); cdf_+=m_weights[i]*m_copulas[i].Copula_CDF(u,v); } return cdf_; }
double Conditional_Probability(double u, double v, double _eps = 1.e-5) { u = fmin(fmax(_eps,u),1. - _eps); v = fmin(fmax(_eps,v),1. - _eps); vector result_ = vector::Zeros(m_weights.Size()); for(uint i = 0; i<m_copulas.Size(); ++i) result_[i] = m_copulas[i]?m_weights[i]*m_copulas[i].Conditional_Probability(u,v,false):0.0; return result_.Sum(); } vector Conditional_Probability(vector& u, vector& v, double _eps = 1.e-5) { vector result_ = vector::Zeros(u.Size()); for(uint i = 0; i<m_copulas.Size(); ++i) { if(!m_copulas[i]) continue; m_copulas[i].Set_eps(_eps); result_+=m_weights[i]*m_copulas[i].Conditional_Probability(u,v); } return result_; }
Die Methode Sample() dient dazu, synthetische Datenpunkte aus einem angepassten gemischten Copula-Modell zu generieren.
matrix Sample(ulong num) { vector r = np::arange(m_weights.Size()); vector cop_identities = np::choice(r,m_weights,num); matrix sample_pairs = matrix::Zeros(num,2); matrix temp; for(ulong i = 0; i<cop_identities.Size(); ++i) { temp = m_copulas[uint(cop_identities[i])].Sample(1); sample_pairs.Row(temp.Row(0),i); } return sample_pairs; }
Die Methoden Save() und Load() ermöglichen die Persistenz von Modellen, sodass der Zustand eines trainierten Modells gespeichert und wiederhergestellt werden kann, ohne dass ein erneutes Training erforderlich ist.
virtual bool Save(const int file_handle) { if(file_handle!=INVALID_HANDLE) { if(FileWriteLong(file_handle,-1)==sizeof(long)) { if(FileWriteInteger(file_handle,int(m_copulas.Size()),INT_VALUE)!=INT_VALUE) return(false); if(FileWriteInteger(file_handle,int(m_mixture),INT_VALUE)!=INT_VALUE) return(false); if(FileWriteLong(file_handle,long(m_weights.Size()))!=sizeof(long)) return(false); if(m_weights.Size()) { for(ulong i = 0; i<m_weights.Size(); ++i) if(FileWriteDouble(file_handle,m_weights[i])!=sizeof(double)) return(false); } } } else return false; for(ulong i = 0; i<m_copulas.Size(); ++i) { if(CheckPointer(m_copulas[i])!=POINTER_INVALID) { if(!m_copulas[i].Save(file_handle)) return false; } } return true; } virtual bool Load(const int file_handle) { if(file_handle!=INVALID_HANDLE) { long ff = FileReadLong(file_handle); if(ff == -1) { int size = FileReadInteger(file_handle,INT_VALUE); ENUM_COPULA_MIX mixture = ENUM_COPULA_MIX(FileReadInteger(file_handle,INT_VALUE)); if(ArraySize(m_copulas)!=size || mixture!=m_mixture) { Print(__FUNCTION__, " You are attempting to load a model incompatible with this class "); return false; } ulong size_weights = (ulong)FileReadLong(file_handle); if(size_weights) { m_weights = vector::Zeros(size_weights); switch(m_mixture) { case CFG_MIX: m_cop_params = vector::Zeros(size_weights); break; case CTG_MIX: m_cop_params = vector::Zeros(size_weights+1); break; } for(ulong i = 0; i<size_weights; ++i) m_weights[i] = FileReadDouble(file_handle); } } else return false; } else return false; //--- for(ulong i = 0,k = 0; i<m_copulas.Size(); ++i) { m_copulas[i] = bivariate_copula(file_handle); if(m_copulas[i]==NULL) { Print(__FUNCTION__, " failed to load a bivariate copula from file ", GetLastError()); return false; } if(m_weights.Size()) { switch(ENUM_COPULA_TYPE(m_copulas[i].Type())) { case CLAYTON_COPULA: case GUMBEL_COPULA: case JOE_COPULA: case N13_COPULA: case N14_COPULA: case FRANK_COPULA: m_cop_params[k++] = m_copulas[i].Get_theta(); break; case STUDENT_COPULA: m_cop_params[k++] = m_copulas[i].Get_nu(); m_cop_params[k++] = m_copulas[i].Get_rho(); break; } } } return true; }
Abschließend definiert die Klasse zwei virtuelle Methoden, die zum Überschreiben vorgesehen sind. Die Methode Fit() sollte die Logik implementieren, mit der die Parameter der Copula anhand einer Stichprobe von Pseudo-Beobachtungen geschätzt werden, indem die als Methode Penalized_Log_Likelihood() definierte Likelihood-Funktion unter Einbeziehung der SCAD-Straffunktion minimiert wird.
virtual double Fit(matrix& qdata, ulong maxiter = 25, double gamma_scad = 0.0, double a_scad = 0.0,double weight_margin=1.e-2) { return EMPTY_VALUE; } virtual double Penalized_Log_Likelihood(matrix &data,double g_scad, double a_scad) { return EMPTY_VALUE; }
In mixed.mqh ist außerdem die Aufzählung ENUM_COPULA_MIX definiert, die eine Liste der implementierten gemischten Copula-Typen bereitstellt, um die Auswahl zu erleichtern.
//+------------------------------------------------------------------+ //| mixed copula type | //+------------------------------------------------------------------+ enum ENUM_COPULA_MIX { CFG_MIX=0,//Clayton-Frank-Gumbel CFJ_MIX,//Clayton-Frank-Joe CTG_MIX,//Clayton-Student-Gumbel JFG_MIX//Joe-Frank-Gumbel };
Die Klasse CFGMixCop repräsentiert die gemischte Clayton-Frank-Gumbel-Copula. Sie verfügt über einen parametrischen Konstruktor für Fälle, in denen der Benutzer die Modellparameter lieber explizit definieren möchte, anstatt sie anhand von Daten anzupassen.
public: CFGMixCop(void) { m_mixture = CFG_MIX; m_num_cops = 3; ArrayResize(m_copulas,int(m_num_cops)); for(uint i = 0; i<m_num_cops; ++i) m_copulas[i] = NULL; } CFGMixCop(vector ¶ms, vector& weights) { m_mixture = CFG_MIX; m_num_cops = 3; ArrayResize(m_copulas,int(m_num_cops)); if(params.Size()<3 || weights.Size()<3) Print(__FUNCTION__, " invalid parameters "); else { m_weights = weights; m_cop_params = params; for(ulong i = 0; i<3; ++i) { if(!i) m_copulas[i] = new CClayton(); else if(i==1) m_copulas[i] = new CFrank(); else m_copulas[i] = new CGumbel(); m_copulas[i].Set_theta(m_cop_params[i]); } } }
Bei Verwendung des parametrischen Konstruktors müssen die Parameter in Vektor-Containern angegeben werden. Sowohl die Copula-Parameter als auch die ihnen zugeordneten Gewichte müssen einer bestimmten Reihenfolge folgen:
- Clayton-Parameter
- Frank-Parameter
- Gumbel-Parameter
Ebenso geben alle aufgerufenen Getter-Methoden Werte in dieser einheitlichen Reihenfolge zurück, wodurch eine vorhersehbare Datenverarbeitung im gesamten Modell gewährleistet wird. Die Methode Fit() übernimmt die Schätzung des Modells anhand der Daten.
virtual double Fit(matrix& qdata, ulong maxiter = 50, double gamma_scad = 0.0,double a_scad = 0.0, double weight_margin = 1.e-2) override { if(CheckPointer(m_copulas[0])==POINTER_INVALID) m_copulas[0] = new CClayton(); if(CheckPointer(m_copulas[1])==POINTER_INVALID) m_copulas[1] = new CFrank(); if(CheckPointer(m_copulas[2])==POINTER_INVALID) m_copulas[2] = new CGumbel(); matrix wc = _fit_quantile_em(qdata,maxiter,gamma_scad,a_scad); if(!wc.Rows()) return EMPTY_VALUE; wc.Row(adjust_weights(wc.Row(0),weight_margin),0); m_weights = wc.Row(0); m_cop_params = wc.Row(1); m_copulas[0].Set_theta(m_cop_params[0]); m_copulas[1].Set_theta(m_cop_params[1]); m_copulas[2].Set_theta(m_cop_params[2]); vector u1 = qdata.Col(0); vector u2 = qdata.Col(1); return _ml_qfunction(u1,u2,wc.Row(1),wc.Row(0),gamma_scad,a_scad,false); }
- Die Eingabevariable ist eine Matrix (mindestens 2 Spalten) mit Pseudo-Beobachtungen (Rohwerte, die auf das Intervall [0,1] transformiert wurden).
- Die Eingabe der Funktion maxiter ist eine ganze Zahl, die die maximale Anzahl der Iterationen für den EM-Algorithmus festlegt.
- Die Eingabewerte gamma_scad und a_scad sind vom Typ double und stellen die SCAD-Hyperparameter dar.
- Der Eingabewert weight_margin ist ein Schwellenwert, sodass Gewichte, die unter diesen Grenzwert fallen, auf Null gekürzt werden, um die Sparsität zu gewährleisten.
Bei erfolgreicher Ausführung gibt Fit() den Wert der nicht penalisierten Log-Likelihood zurück; andernfalls wird EMPTY_VALUE zurückgegeben. Die zentrale Schätzlogik ist in der geschützten Methode _fit_quantile_em() gekapselt, die den iterativen Prozess steuert.
matrix _fit_quantile_em(matrix &qd, ulong max_iter,double gamma_scad, double a_scad)
{
vector init_weights = {0.33, 0.33, 1. - 0.33 - 0.33};
vector init_cop_params = {3,4,5};
vector weights = _expectation_step(qd,gamma_scad,a_scad,init_cop_params,init_weights);
if(!weights.Size())
return matrix::Zeros(0,0);
vector cop_params = _maximization_step(qd,gamma_scad,a_scad,init_cop_params,weights);
if(!cop_params.Size())
return matrix::Zeros(0,0);
vector oldparams,newparams;
oldparams = newparams = vector::Zeros(6);
np::vectorCopy(oldparams,init_weights,0,3);
np::vectorCopy(oldparams,init_cop_params,3);
np::vectorCopy(newparams,weights,0,3);
np::vectorCopy(newparams,cop_params,3);
double ll_diff = MathAbs(oldparams-newparams).Sum();
ulong i = 1;
while(i<max_iter && ll_diff>(5.*1.e-2))
{
np::vectorCopy(oldparams,weights,0,3);
np::vectorCopy(oldparams,cop_params,3);
weights = _expectation_step(qd,gamma_scad,a_scad,cop_params,weights);
if(!weights.Size())
{
Print(__FUNCTION__, " invalid weights ", i);
return matrix::Zeros(0,0);
}
cop_params = _maximization_step(qd,gamma_scad,a_scad,cop_params,weights);
if(!cop_params.Size())
{
Print(__FUNCTION__, " failed convergence at iteration ", i);
return matrix::Zeros(0,0);
}
np::vectorCopy(newparams,weights,0,3);
np::vectorCopy(newparams,cop_params,3);
ll_diff = MathAbs(oldparams-newparams).Sum();
i+=1;
}
matrix out = matrix::Zeros(3,3);
out.Row(weights,0);
out.Row(cop_params,1);
return out;
}Die geschützte Methode _expectation_step() implementiert die Erwartungsphase des EM-Algorithmus. Diese Methode arbeitet je nach den Werten der angegebenen SCAD-Parameter in zwei unterschiedlichen Modi. Sind beide SCAD-Parameter gültig (Sparsitätsparameter > 0,0 und Bias-Parameter > 2,0), wird die penalisierte Likelihood herangezogen, wodurch das Modell eine automatische Variablenselektion durchführen kann, indem es insignifikante Gewichte gegen Null drückt. Ist hingegen einer der beiden SCAD-Parameter ungültig, wird die SCAD-Strafe deaktiviert, und die Methode greift standardmäßig auf eine gewöhnliche Maximum-Likelihood-Schätzung (MLE) zurück. vector _expectation_step(matrix &qd,double gamma_scad, double a_scad,vector& cop_params,vector &weights) { //--- ulong num = qd.Rows(); vector u1 = qd.Col(0); vector u2 = qd.Col(1); //--- double dif = 1; double tol_weight = 1.e-2; long iteration = 0; //--- for(ulong i = 0; i<3; ++i) m_copulas[i].Set_theta(cop_params[i]); //--- vector nweights; //--- if(gamma_scad>0.0 && a_scad>2.0) { while(dif>tol_weight && iteration<10) { nweights = vector::Zeros(3); nweights.Fill(double("nan")); iteration+=1; for(ulong i = 0; i<3; ++i) { vector sum_ml_1st = vector::Zeros(u1.Size()); double sum,sum_ml,numerator,denominator; sum = sum_ml = numerator = denominator = 1.e-12; for(ulong t = 0; t<num; ++t) { sum = 1.e-12; for(ulong j = 0; j<3; ++j) sum+=weights[j]*m_copulas[j].Copula_PDF(u1[t],u2[t],true,true); sum_ml_1st[t] = weights[i]*m_copulas[i].Copula_PDF(u1[t],u2[t],true,true)/sum; } sum_ml = sum_ml_1st.Sum(); numerator = weights[i]*scad_derivative(weights[i],gamma_scad,a_scad)-sum_ml/double(num); for(ulong j = 0; j<3; ++j) denominator+=weights[j]*scad_derivative(weights[j],gamma_scad,a_scad); denominator-=1.; nweights[i] = fabs(numerator/denominator); } dif = MathAbs(weights-nweights).Sum(); weights = nweights; } } else { matrix wd = matrix::Zeros(weights.Size(),num); vector td, temp; while(dif>tol_weight && iteration<10) { nweights = vector::Zeros(weights.Size()); iteration+=1; for(ulong i = 0; i<wd.Rows(); ++i) if(!wd.Row(weights[i]*m_copulas[i].Copula_PDF(u1,u2,true,true),i)) { Print(__FUNCTION__, " row insertion error ", GetLastError()); return vector::Zeros(0); } td = wd.Sum(0); td.Clip(1.e-12,DBL_MAX); for(ulong i = 0; i<weights.Size(); ++i) { temp = (wd.Row(i)/td); nweights[i] = fabs(temp.Sum()/double(num)); } dif = MathAbs(weights-nweights).Sum(); weights = nweights; } } //--- return weights; }
Der Maximierungsschritt ist als Methode _maximization_step() definiert.
vector _maximization_step(matrix&qd, double gamma_scad, double a_scad, vector& cop_params, vector& weights) { vector u1 = qd.Col(0); vector u2 = qd.Col(1); double eps = 1.e-3; double _x_[3]; for(uint i = 0; i<_x_.Size(); _x_[i] = cop_params[i], ++i); double bndl[3] = {-1.,-50.,1.}; double bndu[3] = {100.,50.,100.}; CObject obj; CNDimensional_Func1 ffunc; CNDimensional_Rep frep; ffunc.set_params(this,u1,u2,weights,gamma_scad,a_scad,bool(gamma_scad>0.0&&a_scad>2.0),-1); CMinBLEICStateShell state; CMinBLEICReportShell rep; double epsg=eps; double epsf=0; double epsx=0; double epso=eps; double epsi=eps; double diffstep=1.0e-6; CAlglib::MinBLEICCreateF(_x_,diffstep,state); CAlglib::MinBLEICSetBC(state,bndl,bndu); CAlglib::MinBLEICSetInnerCond(state,epsg,epsf,epsx); CAlglib::MinBLEICSetOuterCond(state,epso,epsi); CAlglib::MinBLEICOptimize(state,ffunc,frep,false,obj); CAlglib::MinBLEICResults(state,_x_,rep); vector out = vector::Zeros(0); int termination_reason = rep.GetTerminationType(); if(termination_reason<0) { Print(__FUNCTION__, " termination reason ", termination_reason); return out; } out.Assign(_x_); return out; }
Dieser Schritt nutzt den BLEIC-Minimierungsalgorithmus (Boundary, Linear Equality-Inequality Constraints) von ALGLIB. Der Minimierer optimiert die in mlqfunc() definierte penalisiertе Log-Likelihood, die über die öffentliche Methode objective() an ALGLIB übergeben wird. Dies wird über die öffentliche Methode objective() bereitgestellt, wodurch die ALGLIB-Optimierer-Instanz während ihrer Ausführung auf die Funktion zugreifen kann.
double objective(vector& x,vector& u1, vector& u2,vector& weights, double gamma_scad, double a_scad, bool if_penalty = true, double multiplier= 1.) { return _ml_qfunction(u1,u2,x,weights,gamma_scad,a_scad,if_penalty,multiplier); }
Die Methode Fit() löst den Minimierungsprozess aus. Die Art der zu minimierenden Zielfunktion hängt von den an die Methode übergebenen SCAD-Parametern ab. Ist einer der beiden Parameter ungültig (gamma_scad <= 0,0 oder a_scad <= 2,0), wird als Zielfunktion standardmäßig auf die gewöhnliche Maximum-Likelihood-Schätzung (MLE) ohne Strafterm verwendet. Ansonsten ist die Zielfunktion der penalisierte MLE.
Die Klasse CTGMixCop, die die gemischte Clayton-Student-t-Gumbel-Copula implementiert, folgt einem Aufbau, der nahezu identisch mit dem der Klasse CFGMixCop ist. Der wesentliche Unterschied besteht darin, dass die Frank-Copula durch die Student-t-Copula ersetzt wird.
public:
CTGMixCop(void)
{
m_mixture = CTG_MIX;
m_num_cops = 3;
ArrayResize(m_copulas,int(m_num_cops));
for(uint i = 0; i<m_num_cops; ++i)
m_copulas[i] = NULL;
}
CTGMixCop(vector& params, vector& weights)
{
m_mixture = CTG_MIX;
m_num_cops = 3;
ArrayResize(m_copulas,int(m_num_cops));
if(params.Size()<4 || weights.Size()<3)
Print(__FUNCTION__, " invalid parameters ");
else
{
m_weights = weights;
m_cop_params = params;
for(ulong i = 0; i<3; ++i)
{
if(i == 0 || i == 2)
{
if(!i)
{
m_copulas[i] = new CClayton();
m_copulas[i].Set_theta(m_cop_params[0]);
}
else
{
m_copulas[i] = new CGumbel();
m_copulas[i].Set_theta(m_cop_params[3]);
}
}
else
{
m_copulas[i] = new CStudent();
matrix corr = {{1.,m_cop_params[1]},{m_cop_params[1],1.}};
m_copulas[i].Set_covariance(corr);
m_copulas[i].Set_nu(m_cop_params[2]);
}
}
}
} In der Header-Datei mixed.mqh ist außerdem eine spezielle Routine zur Optimierung der SCAD-Hyperparameter definiert. Die Funktion tune_scad_parameters() führt eine Rastersuche durch, um die Regularisierungsparameter zu optimieren.
//+------------------------------------------------------------------+ //|Implements the 5-fold cross-validation tuning process of the SCAD | //|parameters | //+------------------------------------------------------------------+ bool tune_scad_parameters(matrix &data, double gama_start, double gama_stop, ulong gamma_count, double a_start, double a_stop,ulong a_count, ENUM_COPULA_MIX mix, bool shuffle, int seed, bool show_details, double& out_gamma, double& out_a) { np::Folds folds[]; if(!np::kfold(data.Rows(),folds,5,shuffle,seed)) return false; CMixedCopula* mixedcop = NULL; switch(mix) { case CFG_MIX: mixedcop = new CFGMixCop(); break; case CTG_MIX: mixedcop = new CTGMixCop(); break; case CFJ_MIX: mixedcop = new CFJMixCop(); break; case JFG_MIX: mixedcop = new JFGMixCop(); break; } if(CheckPointer(mixedcop) == POINTER_INVALID) { Print(__FUNCTION__, " failed to initialize ", EnumToString(mix), " copula "); return false; } matrix traindata,testdata; double ll, best_score; vector scores = vector::Zeros(folds.Size()); vector gamma_grid = np::linspace(gama_start,gama_stop,gamma_count); vector a_grid = np::linspace(a_start,a_stop,a_count); best_score = -DBL_MAX; bool use_mle = false; double mle = 0; double p_mle = 0; for(ulong i = 0; i<gamma_grid.Size(); ++i) { for(ulong j = 0; j<a_grid.Size(); ++j) { for(uint k = 0; k<folds.Size() && !IsStopped(); ++k) { traindata = np::selectMatrixRows(data,folds[k].train_indices); testdata = np::selectMatrixRows(data,folds[k].test_indices); ll = mixedcop.Fit(traindata,25,gamma_grid[i],a_grid[j]); if(ll == EMPTY_VALUE) { Print(__FUNCTION__, " error fitting data ", "| sparcity ", gamma_grid[i], " bias ", a_grid[j]); continue; } scores[k] = mixedcop.Penalized_Log_Likelihood(testdata,gamma_grid[i],a_grid[j]); } ll = scores.Sum(); if(show_details) Print(__FUNCTION__, "| sparcity: ", gamma_grid[i], "| bias: ", a_grid[j], "| likelihood ", ll, " \nweights ", mixedcop.Weights(), "| params ", mixedcop.Params()); if(ll>best_score) { best_score = ll; out_a = a_grid[j]; out_gamma = gamma_grid[i]; } } } delete mixedcop; return true; }
Es akzeptiert die folgenden Eingaben.
- Die Eingabedaten bestehen aus einer Matrix von Pseudo-Beobachtungen, wobei jede Spalte eine Zeitreihe darstellt.
- Die Funktion definiert dann sechs Eingabevariablen: Den ersten drei ist das Präfix gamma vorangestellt, den letzten drei das Präfix a. Diese legen die Grenzen und die Granularität der Rastersuche nach dem optimalen SCAD-Hyperparameterpaar fest.
- Argumente mit dem Suffix count geben die Anzahl der zu prüfenden Werte an, die innerhalb der durch die Argumente mit den Suffixen start bzw. stop definierten Bereiche ausgewertet werden sollen.
- Der Mix-Eingabewert ist eine Aufzählung, die angibt, welches gemischte Copula-Modell während der Suche ausgewertet werden soll.
- Der Parameter shuffle ist ein boolescher Wert, der festlegt, ob die Daten vor der Aufteilung zufällig angeordnet werden sollen, und der Parameter seed ist ein Startwert für den Pseudozufallszahlengenerator, um reproduzierbare Ergebnisse zu gewährleisten.
- Das boolesche Flag show_details legt fest, ob die Ausführungsdetails jeder Iteration im Protokoll des Terminals ausgegeben werden sollen.
- Die Referenzeingaben out_a und out_gamma sind die Ausgabeparameter, in denen die von der Prozedur ermittelten optimalen SCAD-Parameter gespeichert werden.
Die SCAD-Straffunktion und ihre Ableitung sind in utils.mqh definiert. Diese implementieren den Schrumpfungsmechanismus, wodurch das Modell zwischen signifikanten und vernachlässigbaren Copula-Gewichten unterscheiden kann.
//+------------------------------------------------------------------+ //|SCAD (smoothly clipped absolute deviation) penalty function. | //+------------------------------------------------------------------+ double scad_penalty(double x, double gamma, double a) { bool is_linear = (fabs(x)<=gamma); bool is_quadratic = (gamma<fabs(x)) & (fabs(x)<=a*gamma); bool is_constant = ((a*gamma)<fabs(x)); double linear_part = gamma * fabs(x) * double(is_linear); double quadratic_part = (2.*a*gamma*fabs(x) - pow(x,2.)- pow(gamma,2.))/(2.*(a-1.))*double(is_quadratic); double constant_part = (pow(gamma,2.)*(a+1.))/2.*(double(is_constant)); //Print(__FUNCTION__, " linear part ", linear_part,"\n quadratic part ", quadratic_part, "\n constant part ", constant_part); return linear_part+quadratic_part+constant_part; } //+------------------------------------------------------------------+ //|The derivative of SCAD penalty function w.r.t x. | //+------------------------------------------------------------------+ double scad_derivative(double x, double gamma, double a) { double p1 = gamma*double(x<=gamma); double p2 = gamma *(a*gamma-x)*double((a*gamma-x)>0.)/((a - 1.)*gamma)*double(x>gamma); return p1+p2; }
Im nächsten Abschnitt befassen wir uns mit der Auswahl geeigneter Hyperparameter für die SCAD-Straffung. Nutzer sollten sich bestimmter Feinheiten bewusst sein, die über die bloße Durchführung des Kreuzvalidierungsverfahrens hinausgehen.
Optimierung der SCAD-Hyperparameter
Im Zusammenhang mit der SCAD-Straffunktion bestimmen die Abstimmungsparameter λ (Sparsität) und a (Bias-Reduktion) den Schwellenwert für die Sparsität bzw. die Rate der Bias-Reduktion. Zwar richten sich die optimalen Werte letztendlich nach den Daten, doch gibt es in der wissenschaftlichen Literatur und in der Praxis etablierte Bereiche. Der Parameter zur Verringerung der Verzerrung steuert, wie schnell sich die Strafe abflacht. Bei der Anpassung des Bias-Parameters sollten nur Werte größer als zwei berücksichtigt werden; der Parameter muss strikt größer als zwei sein, damit die Funktion Schwellenwerteigenschaften beibehält, die sich vom Hard-Thresholding unterscheiden.
Der Sparsitätsparameter hingegen reagiert empfindlich auf den Umfang der Trainingsdaten und die Stichprobengröße. Er legt den Schwellenwert fest, unterhalb dessen Koeffizienten auf Null gesetzt werden. Der Wertebereich, der bei der Anpassung dieses Parameters berücksichtigt wird, reicht in der Regel von 0 bis 1. Die Untergrenze sollte klein genug sein, damit sich das Modell dem unbestraften Maximum-Likelihood-Schätzer (MLE) annähern kann – zum Beispiel 0,001. Umgekehrt sollte die Obergrenze groß genug sein, um alle Koeffizienten (die Gewichte, die auf die einzelnen Copulas in der Mischung angewendet werden) potenziell auf Null zu setzen. Im Allgemeinen erfordert eine größere Stichprobengröße einen kleineren Sparsitätsparameter.
Ist der Sparsitätsparameter hoch, wird das Modell sparsamer, was dazu führt, dass viele Mischungsgewichte den Wert Null annehmen. Ist der Parameter zur Verringerung der Verzerrung hoch, bleibt die Strafe länger in Kraft, wodurch der Übergang vom verzerrten zum unverzerrten Zustand deutlich langsamer verläuft. Je näher der Parameter zur Bias-Reduktion an 2 liegt, desto schneller fällt die Strafe ab.
Um diese Konzepte in der Praxis zu testen, veranschaulicht das Skript Scad_CV.mq5 die Funktionsweise der Funktion tune_scad_parameters().
//+------------------------------------------------------------------+ //| Scad_CV.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property script_show_inputs #include<Copulas\Bivariate\mixed.mqh> #include<ECDF\linear_cdf.mqh> input string FirstSymbol="XAUUSD"; input string SecondSymbol="XAUEUR"; input datetime TrainingDataStart=D'2025.01.01'; input ENUM_TIMEFRAMES TimeFrame = PERIOD_D1; input ENUM_COPULA_MIX CopulaType = CTG_MIX; input ulong HistorySize=1200; input bool Show_details = true; input bool Shuffle_Data = false; input int Random_Seed = 0; input double g_from = 0.001; input double g_to = 1.0; input ulong g_count = 5; input double a_from = 2.0; input double a_to = 10.0; input ulong a_count_ = 5; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- //--- vector p_1,p_2,p_3,p_n; matrix pdata,pobs; if(!p_1.CopyRates(FirstSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) || !p_2.CopyRates(SecondSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) || p_1.Size()!=p_2.Size() || !pdata.Resize(p_1.Size(),2) || !pdata.Col(p_1,0) || !pdata.Col(p_2,1)) { Print(" failed to collect and initialize rates matrix ", GetLastError()); return; } //--- CLinearCDF qt(); if(!qt.fit(pdata)) return; //--- pobs = qt.to_quantile(pdata); double gamma_scad,a_scad; if(!tune_scad_parameters(pobs,g_from,g_to,g_count,a_from,a_to,a_count_,CopulaType,Shuffle_Data,Random_Seed,Show_details,gamma_scad,a_scad)) { Print(" failed "); return; } Print(EnumToString(CopulaType)," sparcity -> ", gamma_scad, " || bias -> ", a_scad); } //+------------------------------------------------------------------+
Die standardmäßig vom Benutzer anpassbaren Eingabewerte des Skripts Scad_CV.ex5 legen ein relativ enges Raster an Werten für die Sparsität und den Bias fest. Diese Konfiguration gewährleistet, dass das Skript bei Stichprobengrößen von etwas mehr als tausend Beobachtungen effizient ausgeführt wird. Beachten Sie, dass das Testraster einen Wert von 2,0 für den Bias-Parameter enthält; da dies ein ungültiger Wert für den Bias-Parameter ist, deaktiviert dies die SCAD-Strafe vollständig. Auf diese Weise können wir feststellen, ob die Minimierung der nicht penalisierten Likelihood zu besseren Ergebnissen führt. Wird das Skript mit der ausgewählten Clayton-Frank-Gumbel-Mischung ausgeführt, ergibt sich folgende Ausgabe.
PE 0 07:19:59.780 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 2.0| likelihood 584.3449797418596 NH 0 07:19:59.780 Scad_CV (XAUUSD,D1) weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503] JG 0 07:20:04.549 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 4.0| likelihood 584.3388831186738 GI 0 07:20:04.549 Scad_CV (XAUUSD,D1) weights [0,0.2503330189828707,0.7496669810161294]| params [0.07783293123073377,4.987168638354295,2.938531600897639] NJ 0 07:20:09.278 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 6.0| likelihood 584.5057912775926 LF 0 07:20:09.278 Scad_CV (XAUUSD,D1) weights [0,0.2475903622229043,0.7524096377760957]| params [0.08186119438950079,4.982135308682525,2.934272675707406] OL 0 07:20:13.997 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 8.0| likelihood 584.5035349829863 ED 0 07:20:13.997 Scad_CV (XAUUSD,D1) weights [0,0.2475907179493826,0.7524092820496174]| params [0.08234560301866138,4.982135272704732,2.934273169230999] JL 0 07:20:18.700 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 10.0| likelihood 584.5011307062207 ER 0 07:20:18.700 Scad_CV (XAUUSD,D1) weights [0,0.2475914144776672,0.7524085855213327]| params [0.08233571375095404,4.98213630991471,2.934274176680373] FQ 0 07:20:23.187 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 2.0| likelihood 584.3449797418596 PL 0 07:20:23.187 Scad_CV (XAUUSD,D1) weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503] ES 0 07:20:27.501 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 4.0| likelihood 283.7391184805832 RM 0 07:20:27.501 Scad_CV (XAUUSD,D1) weights [0,0.9999999999989904,0]| params [0.1511818127315188,7.344139133115162,20.25573962738841] ID 0 07:20:31.999 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 6.0| likelihood 5659.479627674678 JO 0 07:20:31.999 Scad_CV (XAUUSD,D1) weights [0,0.5844120297582153,0.4155879702407769]| params [0.1376209847408496,5.640552910020598,3.811839085505817] JF 0 07:20:38.263 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 8.0| likelihood 334.8224130043968 KJ 0 07:20:38.263 Scad_CV (XAUUSD,D1) weights [0,0.02895916433928,0.97104083565972]| params [0.1037932306526668,4.669895137807593,2.641209026360089] OK 0 07:20:42.346 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 10.0| likelihood 6420.623549439398 ND 0 07:20:42.346 Scad_CV (XAUUSD,D1) weights [0,0.04002009450317316,0.9599799054958269]| params [0.1193049328638911,4.63258676700795,2.654870180909923] DH 0 07:20:46.831 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 2.0| likelihood 584.3449797418596 KF 0 07:20:46.831 Scad_CV (XAUUSD,D1) weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503] FN 0 07:20:49.490 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 4.0| likelihood 34.55576102335817 KR 0 07:20:49.490 Scad_CV (XAUUSD,D1) weights [0,0,0.9999999999989903]| params [0.1197956723049384,4.584548412565545,2.619284560176268] NN 0 07:20:52.885 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 6.0| likelihood 15.363216317653269 HR 0 07:20:52.885 Scad_CV (XAUUSD,D1) weights [0,0.01784571505390212,0.9821542849450979]| params [0.1043980264613316,4.628446940510745,2.628580283819081] QS 0 07:20:56.830 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 8.0| likelihood 6102.473148256049 RP 0 07:20:56.830 Scad_CV (XAUUSD,D1) weights [0,0.02673340177232474,0.9732665982266753]| params [0.1037622447823746,4.698345592025231,2.638332966096248] IS 0 07:21:00.708 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 10.0| likelihood 3.301592693093255 RM 0 07:21:00.708 Scad_CV (XAUUSD,D1) weights [0,0.0300952343044497,0.9699047656945503]| params [0.1029115313643473,4.61667495323261,2.643127744938425] KE 0 07:21:05.196 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 2.0| likelihood 584.3449797418596 QH 0 07:21:05.196 Scad_CV (XAUUSD,D1) weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503] JI 0 07:21:08.606 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 4.0| likelihood -297.39396856892415 GH 0 07:21:08.606 Scad_CV (XAUUSD,D1) weights [0,0.01107956745287137,0.9889204325461286]| params [2.9984906563128,4.76765198814707,2.620207254516393] KH 0 07:21:12.649 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 6.0| likelihood -303.8281831341336 CE 0 07:21:12.649 Scad_CV (XAUUSD,D1) weights [0,0.01742743973978789,0.9825725602592119]| params [2.9984906563128,4.637005162809593,2.628040342667032] FO 0 07:21:18.050 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 8.0| likelihood 5512.03076596105 DG 0 07:21:18.050 Scad_CV (XAUUSD,D1) weights [0,0.02364115960349121,0.9763588403955088]| params [2.9984906563128,4.667363798628771,2.635026851516195] PM 0 07:21:23.276 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 10.0| likelihood 5953.875750743017 OR 0 07:21:23.276 Scad_CV (XAUUSD,D1) weights [0,0.03021524144755516,0.9697847585514447]| params [2.9984906563128,4.626181869637053,2.643168795782705] KQ 0 07:21:27.767 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 2.0| likelihood 584.3449797418596 ML 0 07:21:27.767 Scad_CV (XAUUSD,D1) weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503] FQ 0 07:21:31.781 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 4.0| likelihood -727.4266957539727 GN 0 07:21:31.781 Scad_CV (XAUUSD,D1) weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704] JG 0 07:21:35.806 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 6.0| likelihood -727.4266957539727 IH 0 07:21:35.806 Scad_CV (XAUUSD,D1) weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704] JE 0 07:21:39.839 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 8.0| likelihood -727.4266957539727 GJ 0 07:21:39.839 Scad_CV (XAUUSD,D1) weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704] MH 0 07:21:43.911 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 10.0| likelihood -727.4266957539727 QD 0 07:21:43.911 Scad_CV (XAUUSD,D1) weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704] DK 0 07:21:43.911 Scad_CV (XAUUSD,D1) CFG_MIX sparcity -> 0.25075 || bias -> 10.0
Die Ergebnisse zeigen, dass die optimalen SCAD-Parameter für die Clayton-Frank-Gumbel-Mischung eine Sparsität von 0,25075 und ein Bias von 10 sind. Die nächsten Ergebnisse, die sich auf die Clayton-Student-Gumbel-Mischung beziehen, sind besonders aufschlussreich.
JF 0 07:23:09.254 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 2.0| likelihood 599.6351926572415 HK 0 07:23:09.254 Scad_CV (XAUUSD,D1) weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769] NH 0 07:23:31.432 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 4.0| likelihood 599.6274718728072 FI 0 07:23:31.433 Scad_CV (XAUUSD,D1) weights [0,0.03267798343975953,0.96732201655924]| params [0.02669592147577486,0.5822648258079013,7,2.6352494228926] FK 0 07:23:53.828 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 6.0| likelihood 599.6244749857701 GD 0 07:23:53.828 Scad_CV (XAUUSD,D1) weights [0,0.03267834828227598,0.9673216517167235]| params [0.02669671670147136,0.5822637634505266,7,2.635245690184943] CN 0 07:24:16.075 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 8.0| likelihood 599.6215815910193 ES 0 07:24:16.075 Scad_CV (XAUUSD,D1) weights [0,0.03267864853568959,0.9673213514633099]| params [0.02669727070086427,0.5822626295795441,7,2.635242405736884] ER 0 07:24:38.223 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.001| bias: 10.0| likelihood 599.61866242213 MQ 0 07:24:38.223 Scad_CV (XAUUSD,D1) weights [0,0.03267912346489563,0.9673208765341038]| params [0.02669711773038876,0.5822617798491028,7,2.635240094669517] ES 0 07:24:59.495 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 2.0| likelihood 599.6351926572415 KM 0 07:24:59.495 Scad_CV (XAUUSD,D1) weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769] EE 0 07:25:12.505 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 4.0| likelihood 468.644205273507 GK 0 07:25:12.505 Scad_CV (XAUUSD,D1) weights [0,0.01620981928802398,0.983790180710976]| params [2.862242105331717,0.9975906244136006,7,2.566020598217] PH 0 07:26:18.429 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 6.0| likelihood 359.9685977593964 JD 0 07:26:18.429 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [0.02596060043458071,0.5877560061777306,7,2.60814677938215] GJ 0 07:26:35.438 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 8.0| likelihood 341.04401153470667 EE 0 07:26:35.438 Scad_CV (XAUUSD,D1) weights [0,0.0101303301858873,0.9898696698131126]| params [0.03276229272869093,0.5873194208156135,7,2.6159294869276] PL 0 07:26:50.782 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.25075| bias: 10.0| likelihood 331.81315199928497 OE 0 07:26:50.782 Scad_CV (XAUUSD,D1) weights [0,0.01344107163199763,0.9865589283670023]| params [0.01828802392046799,0.5853696555031691,7,2.618615230362836] DL 0 07:27:12.118 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 2.0| likelihood 599.6351926572415 OP 0 07:27:12.118 Scad_CV (XAUUSD,D1) weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769] NR 0 07:28:58.374 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 4.0| likelihood 39.715438762939925 NM 0 07:28:58.374 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.885268158668136,0.5815643981885116,7,2.60814677938215] MR 0 07:29:14.021 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 6.0| likelihood 15.766736485645538 PM 0 07:29:14.021 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.886114952573396,0.5885681475003665,7,2.60814677938215] FR 0 07:31:20.013 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 8.0| likelihood 12.582743928163211 KN 0 07:31:20.013 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.886068065102342,0.588279448169273,7,2.60814677938215] GR 0 07:33:38.602 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.5005| bias: 10.0| likelihood 9.373323825700936 HM 0 07:33:38.602 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.885905528406098,0.5876282323959312,7,2.60814677938215] LR 0 07:33:59.933 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 2.0| likelihood 599.6351926572415 NO 0 07:33:59.933 Scad_CV (XAUUSD,D1) weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769] PF 0 07:34:12.979 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 4.0| likelihood -342.3070420888405 GK 0 07:34:12.979 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.999235107389794,0.5744384247930826,7,2.608146780258969] MG 0 07:34:25.802 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 6.0| likelihood -313.5880991228416 NK 0 07:34:25.802 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.999235107389794,0.5712426547670767,7,2.608146780258969] JG 0 07:34:38.627 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 8.0| likelihood -315.3277234364691 GK 0 07:34:38.627 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.999235107389794,0.5700039115725434,7,2.608146780258969] PG 0 07:34:51.411 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 0.75025| bias: 10.0| likelihood -316.34493893784384 OJ 0 07:34:51.411 Scad_CV (XAUUSD,D1) weights [0,0,0.999999999999]| params [2.999235107389794,0.5700489107543522,7,2.608146780258969] RF 0 07:35:12.660 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 2.0| likelihood 599.6351926572415 DJ 0 07:35:12.660 Scad_CV (XAUUSD,D1) weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769] CH 0 07:35:14.020 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 4.0| likelihood 689.1665208571073 DH 0 07:35:14.020 Scad_CV (XAUUSD,D1) weights [0,0,0]| params [3,0.5,4,2.608146566441139] DR 0 07:35:15.389 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 6.0| likelihood 689.1665208571073 EN 0 07:35:15.389 Scad_CV (XAUUSD,D1) weights [0,0,0]| params [3,0.5,4,2.608146566441139] KL 0 07:35:16.734 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 8.0| likelihood 689.1665208571073 PD 0 07:35:16.734 Scad_CV (XAUUSD,D1) weights [0,0,0]| params [3,0.5,4,2.608146566441139] CE 0 07:35:18.094 Scad_CV (XAUUSD,D1) tune_scad_parameters| sparcity: 1.0| bias: 10.0| likelihood 689.1665208571073 MJ 0 07:35:18.094 Scad_CV (XAUUSD,D1) weights [0,0,0]| params [3,0.5,4,2.608146566441139] DS 0 07:35:18.094 Scad_CV (XAUUSD,D1) CTG_MIX sparcity -> 1.0 || bias -> 4.0
In diesem Fall liegen die optimalen SCAD-Parameter bei 1,0 und 4,0. Ein Sparsitätswert von 1,0 ist recht hoch und hat dazu geführt, dass alle Gewichte auf Null gesetzt wurden – ein unsinniges Ergebnis für ein Mischmodell. Ein solches Ergebnis deutet oft darauf hin, dass das jeweilige Mischmodell möglicherweise nicht für die Daten geeignet ist oder dass die Straffunktion zu streng ist.
In diesem Fall ist es ratsam, zunächst zu versuchen, das Modell mithilfe des MLE-Ansatzes ohne die SCAD-Straffunktion anzupassen. Wenn der MLE-Ansatz sinnvolle Gewichte liefert, bestätigt sich, dass das Problem in einem zu großen Sparsitätsparameter liegt. In solchen Fällen sollte man entweder die MLE-Methode anwenden oder die Obergrenze der während des Kreuzvalidierungsverfahrens getesteten Sparsitätsparameter senken.
Daher lassen wir die Versuche außer Acht, bei denen ausschließlich Nullwerte ermittelt wurden. Dabei stellen wir fest, dass der MLE-Ansatz ohne Penalisation das Likelihood-Maximum erzielt. Zum jetzigen Zeitpunkt haben wir die optimalen SCAD-Parameter für die Clayton-Frank-Gumbel-Mischung (0,25075, 10) und die Clayton-Student-Gumbel-Mischung (0,001, 2,0) ermittelt. Diese Informationen können nun genutzt werden, um gemischte Copula-Modelle unter Verwendung des vollständigen Trainingsdatensatzes zu erstellen und zu vergleichen.
Modellauswahl und -vergleich
Das Skript MixedCopulaSelection.mq5 dient dazu, die gemischte Copula zu ermitteln, die am besten zu einer bestimmten Datenstichprobe passt.
//+------------------------------------------------------------------+ //| MixedCopulaSelection.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property script_show_inputs #include<Copulas\Bivariate\mixed.mqh> #include<ECDF\linear_cdf.mqh> #include<Files\FileBin.mqh> //--- input parameters input string FirstSymbol="XAUUSD"; input string SecondSymbol="XAUEUR"; input datetime TrainingDataStart=D'2025.01.01'; input ENUM_TIMEFRAMES TimeFrame = PERIOD_D1; input ulong HistorySize=1200; input double CTG_Scad_Gamma = 0.0; input double CTG_Scad_A = 2.0; input double CFG_Scad_Gamma = 0.25075; input double CFG_Scad_A = 10.0; input uint Max_Iterations = 25; input bool SaveModel = true; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- vector p_1,p_2,p_3,p_n; matrix pdata,pobs; if(!p_1.CopyRates(FirstSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) || !p_2.CopyRates(SecondSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) || p_1.Size()!=p_2.Size() || !pdata.Resize(p_1.Size(),2) || !pdata.Col(p_1,0) || !pdata.Col(p_2,1)) { Print(" failed to collect and initialize rates matrix ", GetLastError()); return; } //--- CLinearCDF qt(); if(!qt.fit(pdata)) return; //--- pobs = qt.to_quantile(pdata); //--- if(SaveModel) { CFileBin file; string filename = FirstSymbol+"_"+SecondSymbol+".ecdf"; file.Open(filename,FILE_WRITE|FILE_COMMON); if(!qt.save(file.Handle())) Print(" Failed to save ", filename); else Print("Ecdf model save to ", filename); file.Close(); } //--- vector lowest = vector::Zeros(4); lowest.Fill(DBL_MAX); //--- Print("[[ Clayton - Student - Gumbel ]]"); //--- CTGMixCop ctg; double fit; //--- fit = ctg.Fit(pobs,Max_Iterations,CTG_Scad_Gamma,CTG_Scad_A); //--- Print(" CTG loglikelihood ", fit); Print(" CTG weights ", ctg.Weights()); Print(" CTG Params ", ctg.Params()); //--- lowest[2] = aic(fit,int(pobs.Rows())); Print(" CTG sic ", sic(fit,int(pobs.Rows()))); Print(" CTG aic ", lowest[2]); Print(" CTG hqic ", hqic(fit,int(pobs.Rows()))); //--- Print("[[ Clayton - Frank - Gumbel ]]"); //--- CFGMixCop cfg; //--- fit = cfg.Fit(pobs,Max_Iterations,CFG_Scad_Gamma,CFG_Scad_A); //--- Print(" CFG loglikelihood ", fit); Print(" CFG weights ", cfg.Weights()); Print(" CFG Params ", cfg.Params()); //--- lowest[0] = aic(fit,int(pobs.Rows())); Print(" CFG sic ", sic(fit,int(pobs.Rows()))); Print(" CFG aic ", lowest[0]); Print(" CFG hqic ", hqic(fit,int(pobs.Rows()))); //--- if(SaveModel) { CFileBin file; string filename,extension; ulong shift = lowest.ArgMin(); CMixedCopula* mcop = NULL; ENUM_COPULA_MIX mixtype = (ENUM_COPULA_MIX)shift; switch(mixtype) { case CFG_MIX: mcop = GetPointer(cfg); extension = ".cfgcopula"; break; case CTG_MIX: mcop = GetPointer(ctg); extension = ".ctgcopula"; break; } filename = FirstSymbol+"_"+SecondSymbol+extension; file.Open(filename,FILE_WRITE|FILE_COMMON); if(!mcop.Save(file.Handle())) Print("Failed to save ", filename); else Print("MixedCopula saved to ", filename, " in common folder."); file.Close(); mcop = NULL; } //--- } //+------------------------------------------------------------------+
Dabei handelt es sich um ein Vergleichsverfahren, bei dem die gemischten Copula-Modelle nach Clayton-Frank-Gumbel und Clayton-Student-Gumbel anhand desselben Trainingsdatensatzes angepasst werden, wobei je nach den zugewiesenen SCAD-Parametern entweder ein penalisiertes oder ein nicht penalisiertes Likelihood-Verfahren zum Einsatz kommt. Das Skript ermittelt, welche Mischung die beste statistische Anpassung liefert, indem es die jeweiligen Informationskriterien vergleicht. Das besser passende Modell wird anschließend serialisiert und in einer Datei gespeichert. Nach erfolgreicher Ausführung gibt das Terminal ein Protokoll aus, in dem die Log-Likelihood-Werte und der Dateiname des gespeicherten Modells bestätigt werden. Nachfolgend finden Sie die Ausgabe des Skripts unter Verwendung der SCAD-Parameter, die im Rahmen des Kreuzvalidierungsverfahrens ermittelt wurden.
JQ 0 11:26:22.119 MixedCopulaSelection (XAUUSD,D1) Ecdf model save to XAUUSD_XAUEUR.ecdf CO 0 11:26:22.119 MixedCopulaSelection (XAUUSD,D1) [[ Clayton - Student - Gumbel ]] IJ 0 11:26:30.566 MixedCopulaSelection (XAUUSD,D1) CTG loglikelihood 821.3707128783087 NR 0 11:26:30.566 MixedCopulaSelection (XAUUSD,D1) CTG weights [0,0.03552603447650678,0.9644739655224931] NL 0 11:26:30.566 MixedCopulaSelection (XAUUSD,D1) CTG Params [-0.006169340694795771,0.4543309925241095,7,3.054494819573707] ER 0 11:26:30.566 MixedCopulaSelection (XAUUSD,D1) CTG sic -1635.6513489208414 QI 0 11:26:30.566 MixedCopulaSelection (XAUUSD,D1) CTG aic -1640.7414257566174 HJ 0 11:26:30.566 MixedCopulaSelection (XAUUSD,D1) CTG hqic -1638.824033401239 QL 0 11:26:30.566 MixedCopulaSelection (XAUUSD,D1) [[ Clayton - Frank - Gumbel ]] QJ 0 11:26:32.184 MixedCopulaSelection (XAUUSD,D1) CFG loglikelihood 821.5620161629782 JD 0 11:26:32.184 MixedCopulaSelection (XAUUSD,D1) CFG weights [0,0.03875313891414744,0.9612468610848526] HO 0 11:26:32.184 MixedCopulaSelection (XAUUSD,D1) CFG Params [0.002088006991783055,4.242903358363938,3.061932796342449] MR 0 11:26:32.184 MixedCopulaSelection (XAUUSD,D1) CFG sic -1636.0339554901805 RI 0 11:26:32.184 MixedCopulaSelection (XAUUSD,D1) CFG aic -1641.1240323259565 RK 0 11:26:32.184 MixedCopulaSelection (XAUUSD,D1) CFG hqic -1639.206639970578 PL 0 11:26:32.185 MixedCopulaSelection (XAUUSD,D1) MixedCopula saved to XAUUSD_XAUEUR.cfgcopula in common folder.
Als am besten passendes gemischtes Copula-Modell hat sich die Clayton-Frank-Gumbel-Mischung erwiesen. Ein Vergleich dieser Ergebnisse mit angepassten Einzel-Copula-Modellen zeigt, dass die am besten angepasste gemischte Copula eine schlechtere Anpassung liefert als das am besten angepasste Einzel-Copula-Modell.
QS 0 18:48:06.788 CopulaSelection (XAUUSD,D1) CLAYTON_COPULA RD 0 18:48:06.788 CopulaSelection (XAUUSD,D1) sic 1009.0424155712477 HL 0 18:48:06.788 CopulaSelection (XAUUSD,D1) aic 1003.9523387354716 DK 0 18:48:06.788 CopulaSelection (XAUUSD,D1) hqic 1005.8697310908501 KL 0 18:48:06.795 CopulaSelection (XAUUSD,D1) FRANK_COPULA OH 0 18:48:06.795 CopulaSelection (XAUUSD,D1) sic -1282.6359542297741 RP 0 18:48:06.795 CopulaSelection (XAUUSD,D1) aic -1287.7260310655502 RD 0 18:48:06.795 CopulaSelection (XAUUSD,D1) hqic -1285.8086387101716 NS 0 18:48:06.802 CopulaSelection (XAUUSD,D1) GUMBEL_COPULA PK 0 18:48:06.802 CopulaSelection (XAUUSD,D1) sic -1620.5768024034212 FE 0 18:48:06.802 CopulaSelection (XAUUSD,D1) aic -1625.6668792391972 PS 0 18:48:06.802 CopulaSelection (XAUUSD,D1) hqic -1623.7494868838187 GK 0 18:48:11.931 CopulaSelection (XAUUSD,D1) JOE_COPULA NM 0 18:48:11.931 CopulaSelection (XAUUSD,D1) sic -1917.6641571237963 DG 0 18:48:11.931 CopulaSelection (XAUUSD,D1) aic -1922.7542339595723 NQ 0 18:48:11.932 CopulaSelection (XAUUSD,D1) hqic -1920.8368416041938 LE 0 18:48:12.337 CopulaSelection (XAUUSD,D1) N13_COPULA CL 0 18:48:12.337 CopulaSelection (XAUUSD,D1) sic -560.6680141126138 MJ 0 18:48:12.337 CopulaSelection (XAUUSD,D1) aic -565.75809094839 EL 0 18:48:12.337 CopulaSelection (XAUUSD,D1) hqic -563.8406985930114 JG 0 18:48:12.345 CopulaSelection (XAUUSD,D1) N14_COPULA MR 0 18:48:12.345 CopulaSelection (XAUUSD,D1) sic -757.9453503106477 MH 0 18:48:12.345 CopulaSelection (XAUUSD,D1) aic -763.0354271464238 HN 0 18:48:12.345 CopulaSelection (XAUUSD,D1) hqic -761.1180347910453 QL 0 18:48:12.353 CopulaSelection (XAUUSD,D1) GAUSSIAN_COPULA ID 0 18:48:12.353 CopulaSelection (XAUUSD,D1) sic -1189.1571905959859 ML 0 18:48:12.353 CopulaSelection (XAUUSD,D1) aic -1194.2472674317619 IH 0 18:48:12.353 CopulaSelection (XAUUSD,D1) hqic -1192.3298750763834 OR 0 18:48:12.830 CopulaSelection (XAUUSD,D1) STUDENT_COPULA PG 0 18:48:12.830 CopulaSelection (XAUUSD,D1) sic -1233.3072453920256 OQ 0 18:48:12.830 CopulaSelection (XAUUSD,D1) aic -1238.3973222278016 OD 0 18:48:12.830 CopulaSelection (XAUUSD,D1) hqic -1236.479929872423
Ungeachtet dessen können wir das gemischte Copula-Modell weiterhin anstelle des Einzel-Copula-Modells im Expert Advisor SimpleCopulaStrategy.ex5 verwenden, der in Teil 2 der Artikelserie Bivariate Copulas vorgestellt wurde. Der Indikator GoldMixedCopulaSignals.mq5 wurde so angepasst, dass er das Mixed-Copula-Modell nutzt, und SimpleMixedCopulaStrategy.mq5 dient als auf dem Mixed-Copula-Modell basierender EA.

Schlussfolgerung
In diesem Artikel haben wir die Implementierung von Mixed-Copula-Modellen in MQL5 erfolgreich demonstriert. Indem wir über einkomponentige Copulas hinausgegangen sind, haben wir einen Rahmen geschaffen, mit dem sich die nuancierten Abhängigkeiten, die in finanziellen Zeitreihen häufig vorkommen, besser modellieren lassen. Zwar erfordert der Ansatz mit gemischten Copulas einen höheren Rechenaufwand und eine sorgfältige Abstimmung der Hyperparameter, doch das Potenzial zur Erstellung überlegener Copula-Modelle könnte den Aufwand lohnen.
Die Integration von ALGLIB für die nichtkonvexe Optimierung und die modulare Klassenstruktur von CMixedCopula bilden die Grundlage für die Untersuchung höherdimensionaler Mischungen. Letztendlich hängt der Erfolg der Anwendung von Copula-Modellen bei der Strategieentwicklung von der Repräsentativität der Trainingsdaten und der regelmäßigen Neukalibrierung der Modelle ab, um sicherzustellen, dass sie weiterhin mit der sich wandelnden Marktdynamik im Einklang stehen. Der gesamte im Artikel erwähnte Code ist im Anhang zu finden, zusammen mit Beschreibungen der in der Tabelle aufgeführten Dateien.
| Datei | Beschreibung |
|---|---|
| MQL5/include/Copulas/ | Dieser Ordner enthält die Header-Dateien aller bisher implementierten Copula-Modelle, einschließlich der in diesem Artikel beschriebenen. |
| MQL5/include/ECDF/ | Dieser Ordner enthält die Header-Dateien zur Implementierung der empirischen kumulativen Verteilungsfunktion. |
| MQL5/include/np.mqh | Eine Header-Datei mit verschiedenen Hilfsfunktionen für Vektoren und Matrizen. |
| MQL5/scripts/Scad_CV.mq5 | Dieses Skript veranschaulicht ein Kreuzvalidierungsverfahren, das zur Optimierung der SCAD-Hyperparameter verwendet wird. |
| MQL5/scripts/MixedCopulaSelection.mq5 | Das Skript passt gemischte Copula-Modelle an einen Beispieldatensatz an und vergleicht diese, um die am besten passende Copula auszuwählen. |
| MQL5/indicators/GoldMixedCopulaSignals.mq5 | Ein Indikator, der ein gemischtes Copula-Modell verwendet. |
| MQL5/experts/SimpleMixedCopulaStrategy.mq5 | Ein EA, der auf Signalen basiert, die aus einem gemischten Copula-Modell generiert werden. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/19930
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.
MetaTrader 5 – Blaupause für maschinelles Lernen (Teil 7): Von verstreuten Experimenten zu reproduzierbaren Ergebnissen
Workshop zu benutzerdefinierten Indikatoren (Teil 2): Entwicklung eines praxistauglichen Supertrend-Expert-Advisors in MQL5
Verwendung des MQL5-Wirtschaftskalenders zur Nachrichtenfilterung (Teil 1): Implementierung von Zeitfenstern vor und nach Nachrichtenereignissen in MQL5
Einführung in MQL5 (Teil 40): Einsteigerleitfaden zur Dateiverarbeitung in MQL5 (II)
- 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.
Ich habe die Dateien in die richtigen Ordner kopiert und außerdem die Algib-Dateien https://www.mql5.com/de/code/1146 heruntergeladen und in die richtigen Ordner kopiert, aber wenn ich den Indikator „GoldMixedCopula Signals“ kompiliere, erhalte ich 100 Fehlermeldungen. Was mache ich falsch?
Ich habe die Dateien in die entsprechenden Ordner verschoben und ich habe die Dateien „ Algib https://www.mql5.com/de/code/1146“ heruntergeladen und in die entsprechenden Ordner verschoben, aber wenn ich den Indikator „GoldMixedCopula Signals“ kompiliere, erhalte ich 100 Fehlermeldungen. Was mache ich falsch?
Du hast den Screenshot falsch gemacht :-)
Wenn du Hilfe bei der Analyse und Behebung der Fehler benötigst, muss der erste Fehler auf dem Screenshot zu sehen sein. Alle anderen Fehler sind in der Regel „sekundär“, d. h. sie sind die Folge davon.