![Implementierung des Janus-Faktors in MQL5](https://c.mql5.com/2/53/Implementing_the_Janus_factor_in_MQL5_600x314__1.jpg)
Implementierung des Janus-Faktors in MQL5
Einführung
Jeder Händler weiß, dass die Marktpreise einem von zwei großen Mustern folgen. Die Preise bilden entweder Trends oder sie bewegen sich seitwärts. Infolgedessen lassen sich die Strategien der Marktteilnehmer weitgehend darauf beschränken, entweder dem Trend zu folgen oder gegen den Trend zu handeln. Der Janus-Faktor ist eine Theorie des Marktverhaltens, die diese Dualität aufgreift. In diesem Artikel werden wir die Grundlagen dieser Methode erläutern und auch die Anwendung von Indikatoren aufzeigen, die diese Analyse erleichtern.
Rückmeldung
Nach der Janus-Theorie werden die Märkte durch das Zusammenspiel von Preisen und der Reaktion der Händler auf diese Preise bestimmt. Anderson verglich dieses Zusammenspiel mit einem Feedback-System. Weitere Informationen über Feedback-Systeme finden Sie bei Wikipedia. Wenn sich die Märkte im Trend befinden, zeigen die Marktteilnehmer Vertrauen, indem sie ihre Gewinne laufen lassen. In einem Aufwärtstrend bestätigen höhere Kurse die Erwartungen der Marktteilnehmer an den Trend, was wiederum zu mehr Käufen führt. Dies hat zur Folge, dass die Preise noch weiter steigen.
Abb.1 zeigt die positive Rückkopplung in einem Aufwärtstrend.
In einem Abwärtstrend können fallende Kurse den Händlern Angst einflößen und sie dazu veranlassen, zu verkaufen, um Verluste zu minimieren. Weitere Verkäufe üben Druck auf die Preise aus und drücken sie nach unten. Die Entwicklung der Märkte ist daher ein Beispiel für eine positive Rückkopplung. Die Preise werden sich weiter beschleunigen, bis die Händler auf die Preisänderungen reagieren.
Abb. 2 zeigt eine positive Rückkopplung in einem Abwärtstrend.
Eine negative Rückkopplung liegt dann vor, wenn Händler wenig Vertrauen in den Markt haben und daher beschließen, nach jeder Kursbewegung frühzeitig Gewinne mitzunehmen. Frühzeitige Gewinnmitnahmen zerstören das Momentum und begrenzen die Größe der Kursbewegungen. In Verbindung mit dem ständigen Kampf zwischen Bullen und Bären führt dies zu einer Stabilisierung der Preise.
Abb. 3: Negative Rückkopplung auf dem Markt
Kapitalfluss
Ein wichtiges Element dieses Konzepts der Rückkopplung sind die Arten von Symbolen, die von den Händlern bevorzugt werden, wenn unterschiedliche Bedingungen vorherrschen. Andersons Analyse der Aktien legt nahe, dass die Händler in einem Aufwärtstrend Aktien bevorzugten, die eine relativ bessere Performance aufwiesen, während sie sich von ihren unterdurchschnittlichen Pendants trennten. In einem Abwärtstrend verloren unterdurchschnittlich abschneidende Aktien am meisten an Wert, da die Händler sie gezielt für Leerverkäufe nutzten.
In Ermangelung eines Trends gab es nicht viel, was stärkere und schwächere Aktien voneinander trennte, da die Händler bestimmte Kursniveaus zum Ein- und Ausstieg wählten. Vor diesem Hintergrund stellte er die Hypothese auf, dass es durch die Analyse der relativen Performance einer Reihe von Aktien möglich sein würde, Perioden negativer und positiver Rückkopplung zu erkennen.
Janus-Berechnungen
Um die Performance zu ermitteln, werden die periodischen Ergebnisse berechnet. Die Ergebnisse einer Reihe von untersuchten Aktien werden kombiniert, um einen Durchschnittswert zu erhalten, der als Basismaßnahme verwendet wird. Ruft die Benchmark-Ergebnisse auf. Die Kollektion der zu bewertenden Aktien wird als Index bezeichnet.
In seinem Buch The Janus Factor - Trend Follower's Guide to Market Dialectics beschreibt Anderson verschiedene Metriken von Aktien, die er auf der Grundlage von Ergebnissen berechnet, um einen Einblick in das Verhalten des Marktes zu erhalten.
Die Janus Bibliothek - janus.mqh
Die Daten und Routinen, die allen Janus-Berechnungen gemeinsam sind, sind in janus.mqh enthalten. Die Include-Datei enthält Deklarationen für drei nutzerdefinierte Typen:
Die Klasse CSymboldata behandelt Symboldaten und damit verbundene Operationen.
//+------------------------------------------------------------------+ //|Class which manage the single Symbol | //+------------------------------------------------------------------+ class CSymbolData { private: string m_name; // name of the symbol ENUM_TIMEFRAMES m_timeframe;// timeframe int m_length; // length for copy rates MqlRates m_rates[]; // store rates datetime m_first; // first date on server or local history datetime SetFirstDate(void) { datetime first_date=-1; if((datetime)SymbolInfoInteger(m_name,SYMBOL_TIME)>0) first_date=(datetime)SeriesInfoInteger(m_name,m_timeframe,SERIES_FIRSTDATE); //--- if(first_date==WRONG_VALUE || first_date==0) { if(TerminalInfoInteger(TERMINAL_CONNECTED)) { while(!SeriesInfoInteger(m_name,m_timeframe,SERIES_SERVER_FIRSTDATE,first_date) && !IsStopped()) Sleep(10); } } //--- #ifdef DEBUG Print(m_name," FirstDate ",first_date); #endif return first_date; } public: CSymbolData(string name,ENUM_TIMEFRAMES tf=PERIOD_CURRENT) { m_name = name; m_length = 0; m_timeframe = tf; SymbolSelect(m_name,true); } ~CSymbolData(void) { ArrayFree(m_rates); } datetime GetFirstDate(void) { m_first = SetFirstDate(); return m_first; } string GetName(void) { return m_name; } int GetLength(void) { return m_length; } void SetLength(const int set_length) { if(set_length>0) { m_length=set_length; ArrayResize(m_rates,m_length,m_length); ArraySetAsSeries(m_rates,true); } } bool Update(void) { int copied = CopyRates(m_name,m_timeframe,0,m_length,m_rates); #ifdef DEBUG Print("copied ", copied, " requested ", m_length); #endif //-- return copied == m_length; }; MqlRates GetRateAtPos(const int i) { if(i<0 || i>=m_length) { #ifdef DEBUG Print("Array out of range ",i,".Size of array is ",m_length); #endif return (i<0)?m_rates[0]:m_rates[m_length-1]; } return m_rates[i]; } };CSymbolCollection ist ein Container von CSymboldata-Objekten, der die Kollektion der zu analysierenden Symbole darstellt. Der Code für beide Klassen wurde einem Listing aus der Mql5-Codebasis entnommen. Es wurden Änderungen an der Indizierungsrichtung der zugrunde liegenden Puffer vorgenommen. Es ist zu beachten, dass alle Klassen ein Indexierungsformat von rechts nach links verwenden, wobei der Null-Index auf den letzten Balken verweist.
Um die Techniken des Janus-Faktors zu demonstrieren, werden wir ihn auf die Analyse von Devisenpaaren anwenden. Anderson hat die Methode ursprünglich für die Analyse von Aktien entwickelt, aber die Verfügbarkeit von Aktiensymbolen ist bei den meisten Brokern uneinheitlich.
//+------------------------------------------------------------------+ //| Class that mange the collection of symbols | //+------------------------------------------------------------------+ class CSymbolCollection { private: int m_calculation_length; // global length ENUM_TIMEFRAMES m_collection_timeframe; // timeframe of data string m_raw_symbols; // delimited symbol list datetime m_synced_first; // synced first bar opentime for all symbols bool m_synced; // flag of whether all symbols are synchronized CSymbolData *m_collection[]; // Collection of Symbol Pointer int m_collection_length; // Collection of Symbol Length //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckSymbolBars(const string __sym) { int bars=-1; bars=iBarShift(__sym,m_collection_timeframe,m_synced_first)+1;//SeriesInfoInteger(__sym,PERIOD_CURRENT,SERIES_BARS_COUNT); #ifdef DEBUG Print("Bars found in history for ",__sym," ",bars); #endif if(bars>=m_calculation_length) return(true); //--- return(SyncSymbol(__sym)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool SyncSymbol(const string __sym) { //--- load data step by step bool downloaded=false; datetime times[1]; int bars=-1; /* if(MQLInfoInteger(MQL_PROGRAM_TYPE)==PROGRAM_INDICATOR) { #ifdef DEBUG Print(" cannot download ",__sym," history from an indicator"); #endif return(downloaded); }*/ #ifdef DEBUG Print(" downloading ",__sym," history"); #endif while(!IsStopped() && !downloaded && TerminalInfoInteger(TERMINAL_CONNECTED)) { //--- while(!SeriesInfoInteger(__sym,m_collection_timeframe,SERIES_SYNCHRONIZED) && !IsStopped()) Sleep(5); //--- bars=Bars(__sym,PERIOD_CURRENT); if(bars>=m_calculation_length) { downloaded=true; break; } //--- copying of next part forces data loading if(CopyTime(__sym,m_collection_timeframe,m_calculation_length-1,1,times)==1) { downloaded=true; break; } //--- Sleep(5); } #ifdef DEBUG if(downloaded) Print(bars," ",__sym," bars downloaded "); else Print("Downloading ",__sym," bars failed"); #endif return(downloaded); } public: CSymbolCollection(const ENUM_TIMEFRAMES tf=PERIOD_CURRENT) { m_raw_symbols=""; m_collection_length = 0; m_calculation_length = -1; m_synced_first=0; m_synced=false; m_collection_timeframe=tf; } ~CSymbolCollection(void) { for(int i=0; i<m_collection_length; i++) { if(CheckPointer(m_collection[i])==POINTER_DYNAMIC) delete m_collection[i]; } } //+------------------------------------------------------------------+ //|return the set timeframe for bars stored in the collection | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES GetTimeFrame(void) { return(m_collection_timeframe); } //+------------------------------------------------------------------+ //|Checks the history available and syncs it across all symbols | //+------------------------------------------------------------------+ bool CheckHistory(const int size) { if(size<=0) return(false); int available=iBarShift(NULL,m_collection_timeframe,m_synced_first)+1; if(available<size) m_calculation_length=available; else m_calculation_length=size; #ifdef DEBUG Print("synced first date is ", m_synced_first); Print("Proposed size of history ",m_calculation_length); #endif if(m_calculation_length<=0) return(false); ResetLastError(); for(int i=0; i<m_collection_length; i++) { m_synced=CheckSymbolBars(m_collection[i].GetName()); if(!m_synced) { Print("Not Enough history data for ", m_collection[i].GetName(), " > ", GetLastError()); return(m_synced); } m_collection[i].SetLength(m_calculation_length); } return m_synced; } //+------------------------------------------------------------------+ //| Add a symbol by name to the collection | //+------------------------------------------------------------------+ int Add(string name) { CSymbolData *ref = new CSymbolData(name,m_collection_timeframe); datetime f=ref.GetFirstDate(); int found=GetIndex(name); if(f==WRONG_VALUE || found>-1) { #ifdef DEBUG if(f==WRONG_VALUE) Print("Failed to retrieve information for symbol ",name,". Symbol removed from collection"); if(found>-1) Print("Symbol ",name,"already part of collection"); #endif delete ref; return(m_collection_length); } ArrayResize(m_collection, m_collection_length + 1,1); m_collection[m_collection_length] = ref; //--- if(f>m_synced_first) m_synced_first=f; //--- return(++m_collection_length); } //+------------------------------------------------------------------+ //|Return symbol name | //+------------------------------------------------------------------+ string GetSymbolNameAtPos(int pos) { return m_collection[pos].GetName(); } //+------------------------------------------------------------------+ //|return index of symbol | //+------------------------------------------------------------------+ int GetIndex(const string symbol_name) { for(int i=0; i<m_collection_length; i++) { if(symbol_name==m_collection[i].GetName()) return(i); } //---fail return(-1); } //+------------------------------------------------------------------+ //| Return Collection length | //+------------------------------------------------------------------+ int GetCollectionLength(void) { return m_collection_length; } //+------------------------------------------------------------------+ //| Update every currency rates | //+------------------------------------------------------------------+ bool Update(void) { int i; for(i = 0; i < m_collection_length; i++) { bool res = m_collection[i].Update(); if(res==false) { Print("missing data on " + m_collection[i].GetName()); return false; } } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int GetHistoryBarsLength(void) { return m_calculation_length; } //+------------------------------------------------------------------+ //| Return MqlRates of currency at position | //+------------------------------------------------------------------+ MqlRates GetRateAtPos(int pos, int i) { return m_collection[pos].GetRateAtPos(i); } //+------------------------------------------------------------------+ //| Return Open price of currency at position | //+------------------------------------------------------------------+ double GetOpenAtPos(int pos, int i) { return m_collection[pos].GetRateAtPos(i).open; } //+------------------------------------------------------------------+ //| Return Close price of currency at position | //+------------------------------------------------------------------+ double GetCloseAtPos(int pos, int i) { return m_collection[pos].GetRateAtPos(i).close; } //+------------------------------------------------------------------+ //| Return High price of currency at position | //+------------------------------------------------------------------+ double GetHighAtPos(int pos, int i) { return m_collection[pos].GetRateAtPos(i).high; } //+------------------------------------------------------------------+ //| Return Low price of currency at position | //+------------------------------------------------------------------+ double GetLowAtPos(int pos, int i) { return m_collection[pos].GetRateAtPos(i).low; } //+------------------------------------------------------------------+ //| Return Median price of currency at position | //+------------------------------------------------------------------+ double GetMedianAtPos(int pos, int i) { return (GetHighAtPos(pos,i) + GetLowAtPos(pos, i))/2; } //+------------------------------------------------------------------+ //| Return Typical price of currency at position | //+------------------------------------------------------------------+ double GetTypicalAtPos(int pos, int i) { return (GetHighAtPos(pos,i) + GetLowAtPos(pos, i) + GetCloseAtPos(pos,i))/3; } //+------------------------------------------------------------------+ //| Return Weighted price of currency at position | //+------------------------------------------------------------------+ double GetWeightedAtPos(int pos, int i) { return (GetHighAtPos(pos,i) + GetLowAtPos(pos, i) + GetCloseAtPos(pos,i) * 2)/4; } }; //+------------------------------------------------------------------+
Der Code beginnt mit drei nutzerdefinierten Enumerationen, die im Folgenden dokumentiert werden.
#include<Math\Stat\Math.mqh> #include <Arrays\ArrayObj.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum ENUM_INDEX_TYPE { INDEX_FOREX_MAJORS=0,//forex majors only list INDEX_CUSTOM,//custom symbol list }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum ENUM_PRICE { CLOSE=0,//close price MEDIAN,//median price TYPICAL,//typical price WEIGHTED//weighted price }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum ENUM_DIFF_TYPE { DIFF_PERCENT=0,//percent difference DIFF_LOG//log difference };
Enumeration | Beschreibung | Optionen |
---|---|---|
ENUM_INDEX_TYPE | stellt die Art der Symbole dar, die in einer zu analysierenden Kollektion enthalten sind | INDEX_FOREX - diese Option erstellt eine Kollektion von Symbolen, die aus allen Forex-Majors besteht. Ein Satz von 28 Symbolen. INDEX_CUSTOM - mit dieser Option muss die Kollektion der Symbole angegeben werden. |
ENUM_PRICE | ermöglichen die Auswahl der Preisreihen, die für die Berechnungen verwendet werden sollen. Es ist zu beachten, dass die Preisinformationen als Zeitreihen gespeichert werden, sodass der letzte Preise bei Index 0 liegt. | CLOSE - Schlusskurs MEDIAN - der Medianpreis - (Hoch+Tief)/2 TYPICAL - der typische Preis - (Hoch+Tief+Schluss)/3 WEIGHTED - der gewichtete Preis - (Hoch+Tief+Schluss+Schluss)/4 |
ENUM_DIFF_TYPE | Dies sind verschiedene Methoden der Differenzierung, die auf die ausgewählten Preisreihen angewendet werden können. | DIFF_LOG - hier wird der Logarithmus des Quotienten verwendet DIFF_PERCENT - die prozentuale Differenz wird für diese Option verwendet |
Um die Klasse CJanus zu verwenden, müssen 5 Methoden verstanden werden. Nach der Erstellung eines CJanus-Objekts und bevor irgendeine Methode aufgerufen werden kann, sollte zunächst die Funktion Initialize aufgerufen werden. Die Methode erfüllt zwei wichtige Aufgaben: Zunächst initialisiert sie das Objekt CSymbolCollection und füllt es mit den ausgewählten Symbolen, die unseren Index bilden werden. Anschließend werden die historischen Balken der Symbole in der Kollektion überprüft und synchronisiert.
//+------------------------------------------------------------------+ //|Janus class for calculating janus family of indicators. | //+------------------------------------------------------------------+ class CJanus { private: CSymbolCollection* m_symbol_list; //object container of symbols ENUM_PRICE m_price_type; //applied price for calculations ENUM_DIFF_TYPE m_diff_type; //method of differencing applied ENUM_INDEX_TYPE m_index_type; //type of index int m_hist_size; // synchronized size of history across all selected symbols in collection ENUM_TIMEFRAMES m_list_timeframe; //timeframe for bars to be used in calculations //---private methods double market_return(const uint barshift, const uint symbolshift); void market_offense_defense(const uint barshift,const uint symbolshift,const uint rs_period,double& out_offense,double& out_defense); double rs(const uint barshift,const uint symbolshift,const uint rs_period,uint lag=0); double rs_off_def(const uint barshift, const uint symbolshift,const uint lag,const double median,const double index_offense, const double index_defense, double &array[]); //--- public: //constructor CJanus(void):m_symbol_list(NULL), m_price_type(WRONG_VALUE), m_diff_type(WRONG_VALUE), m_index_type(WRONG_VALUE), m_list_timeframe(WRONG_VALUE), m_hist_size(0) { } // destructor ~CJanus(void) { if(CheckPointer(m_symbol_list)==POINTER_DYNAMIC) delete m_symbol_list; } //public methods bool Initialize(const ENUM_PRICE set_price_type, const ENUM_DIFF_TYPE set_diff_type, const ENUM_INDEX_TYPE set_index_type, ENUM_TIMEFRAMES set_timeframe,const int history_size, const string symbol_list); bool Update(void); int HistorySize(void); string GetSymbolAt(const int sym_ind); int GetSymbolsTotal(void); double CalculateReturn(const uint barshift, const string symbol__); double CalculateBenchMarkReturn(const uint barshift); double CalculateSummedIndexReturn(const uint barshift); void CalculateBenchMarkOffenseDefense(const uint barshift,const uint rs_period,double& out_offense,double& out_defense); void CalculateMarketOffenseDefense(const uint barshift,const string symbol__,const uint rs_period,double& out_offense,double& out_defense); double CalculateRelativeStrength(const uint barshift,const string symbol__,const uint rs_period,uint lag=0); void CalculateRelativeStrengthLeaderLaggard(const uint barshift,const uint rs_period,const double rs_percent_top,double& leader,double& laggard); double CalculateRelativeStrengthSpread(const uint barshift,const uint rs_period,const double rs_percent_top); double CalculateRelativeStrengthSpreadChange(const uint barshift,const uint rs_period,const double rs_percent_top); };
Die Eingabeparameter der Methode Initialize() werden in der folgenden Tabelle erläutert.
Parameter | Beschreibung | Datentyp |
---|---|---|
set_price_type | eine Enumeration, die die zugrunde liegenden Preisreihen festlegt, die für alle Berechnungen verwendet werden | ENUM_PRICE |
set_diff_type | legt die auf die Preisreihen angewandte Differenzierungsmethode fest | ENUM_DIFF_TYPE |
set_index_type | legt den Typ der Symbolkollektion fest, entweder nutzerdefiniert oder nur Forex-Majors; wenn nutzerdefiniert ausgewählt wird, müssen die Symbole in den Parametern von symbol_list angegeben werden | ENUM_INDEX_TYPE |
set_timeframe | gibt den Zeitrahmen der für die Berechnungen zu verwendenden Balken an | ENUM_TIMEFRAME |
history_size | definiert die maximale Anzahl von Balken, die angefordert werden sollen. Da wir es mit mehreren Symbolen zu tun haben, können wir auf diese Weise sicherstellen, dass für alle Symbole in der Kollektion die gleiche Anzahl historischer Balkendaten verfügbar ist. | integer |
symbol_list | wenn set_index_type auf INDEX_CUSTOM gesetzt ist, muss der Nutzer eine durch Komma getrennte Liste von Symbolen angeben, die die zu analysierende Symbolkollektion bilden soll | string |
- Die Methode Update() aktualisiert die Symboldaten, um die neuesten Kurse abzurufen.
- Die Methode HistorySize() gibt die Anzahl der verfügbaren historischen Balken zurück. Beachten Sie, dass diese Zahl kleiner sein kann als die, die beim Aufruf der Methode Initialize angegeben wurde. Da es möglich ist, dass der Verlauf über alle Symbole hinweg variiert, gibt die Funktion die synchronisierte Verlaufsgröße zurück.
- GetSymbolsTotals() gibt die Anzahl der Symbole zurück, die hinzugefügt und als im Terminal verfügbar bestätigt wurden.
- GetSymbolAt() ermittelt den Symbolnamen nach Index.
Die übrigen Methoden, denen das Präfix Calculate vorangestellt ist, führen Berechnungen durch und geben entweder einen oder zwei Werte zurück. Sie alle haben als ersten Eingabeparameter barshift, die Balkenverschiebung für den Balken, für den eine Berechnung durchgeführt werden soll.
Die einzelnen Methoden werden bei der Umsetzung der verschiedenen Indikatoren erläutert.
Messung der Leistung
Wie bereits erwähnt, wird die Performance durch die Berechnung der Ergebnisse gemessen. Bei unserer Implementierung haben wir die Möglichkeit, den angewandten Preis und die Methode zur Berechnung der Ergebnisse zu wählen. Der Aufruf der Methode CalculateReturns() berechnet die Ergebnisse für den angegebenen barshift und das Symbol.
//+------------------------------------------------------------------+ //|private method that calculates the returns | //+------------------------------------------------------------------+ double CJanus::market_return(const uint barshift, const uint symbolshift) { double curr,prev; curr=0; prev=1.e-60; switch(m_price_type) { case CLOSE: curr=m_symbol_list.GetCloseAtPos(symbolshift,barshift); prev=m_symbol_list.GetCloseAtPos(symbolshift,barshift+1); break; case MEDIAN: curr=m_symbol_list.GetMedianAtPos(symbolshift,barshift); prev=m_symbol_list.GetMedianAtPos(symbolshift,barshift+1); break; case TYPICAL: curr=m_symbol_list.GetTypicalAtPos(symbolshift,barshift); prev=m_symbol_list.GetTypicalAtPos(symbolshift,barshift+1); break; case WEIGHTED: curr=m_symbol_list.GetWeightedAtPos(symbolshift,barshift); prev=m_symbol_list.GetWeightedAtPos(symbolshift,barshift+1); break; default: return WRONG_VALUE; } if(prev==0) return(WRONG_VALUE); switch(m_diff_type) { case DIFF_PERCENT: return(((curr-prev)/prev)*100); case DIFF_LOG: return(MathLog(curr/prev)); default: return(WRONG_VALUE); } } //+------------------------------------------------------------------+ //|public method to calculate returns for single bar | //+------------------------------------------------------------------+ double CJanus::CalculateReturn(const uint barshift, const string symbol_) { int sshift=m_symbol_list.GetIndex(symbol_); if(sshift>-1) return(market_return(barshift,sshift)); else return(WRONG_VALUE); }
Der nachstehende Code für den Indikator IndexReturns zeigt die Ergebnisse für das Chartsymbol und auch die Benchmark-Ergebnisse an.
//+------------------------------------------------------------------+ //| IndexReturns.mq5 | //| Copyright 2023, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 //--- plot IndexReturns #property indicator_label1 "IndexReturns" #property indicator_type1 DRAW_LINE #property indicator_color1 clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Returns #property indicator_label2 "Returns" #property indicator_type2 DRAW_LINE #property indicator_color2 clrBlue #property indicator_style2 STYLE_SOLID #property indicator_width2 1 #include<Janus.mqh> //inputs input ENUM_PRICE AppliedPrice=CLOSE; input ENUM_DIFF_TYPE AppliedDiffType=DIFF_LOG; input ENUM_INDEX_TYPE SelectIndexType=INDEX_FOREX_MAJORS; input string BenchMarkSymbols=""; input int MaxBars = 300; //--- indicator buffers double IndexReturnsBuffer[]; double ReturnsBuffer[]; CJanus *janus; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,IndexReturnsBuffer,INDICATOR_DATA); SetIndexBuffer(1,ReturnsBuffer,INDICATOR_DATA); ArraySetAsSeries(IndexReturnsBuffer,true); ArraySetAsSeries(ReturnsBuffer,true); //--- PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); PlotIndexSetString(1,PLOT_LABEL,_Symbol+" Returns"); //--- IndicatorSetInteger(INDICATOR_DIGITS,8); IndicatorSetString(INDICATOR_SHORTNAME,"IndexReturns("+_Symbol+")"); //--- janus=new CJanus(); //--- if(!janus.Initialize(AppliedPrice,AppliedDiffType,SelectIndexType,PERIOD_CURRENT,MaxBars,BenchMarkSymbols)) return(INIT_FAILED); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //|Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- switch(reason) { case REASON_INITFAILED: ChartIndicatorDelete(ChartID(),ChartWindowFind(),"IndexReturns("+_Symbol+")"); break; default: break; } //--- if(CheckPointer(janus)==POINTER_DYNAMIC) delete janus; } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- int limit; if(prev_calculated<=0) { limit=janus.HistorySize()-2; PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,rates_total-limit+1); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,rates_total-limit+1); } else limit=rates_total-prev_calculated; //--- if(!janus.Update()) return(prev_calculated); for(int bar=limit;bar>=1;bar--) { ReturnsBuffer[bar]=janus.CalculateReturn(bar,_Symbol); IndexReturnsBuffer[bar]=janus.CalculateBenchMarkReturn(bar); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Der Indikator IndexReturns
Die Benchmark
Zur Berechnung der Benchmark-Ergebnisse verwenden wir die individuellen Ergebnisse der Symbole für jeden entsprechenden Zeitpunkt, um den Medianwert zu ermitteln. Diese Berechnung wird mit der Methode CalculateBenchmarkReturns() durchgeführt.
//+------------------------------------------------------------------+ //|public method to calculate index returns | //+------------------------------------------------------------------+ double CJanus::CalculateBenchMarkReturn(const uint barshift) { double sorted[]; int size=m_symbol_list.GetCollectionLength(); if(size<=0) return(WRONG_VALUE); ArrayResize(sorted,size); for(int i=0; i<size; i++) { sorted[i]=market_return(barshift,i); } if(!ArraySort(sorted)) { Print("sorting error ",__LINE__," ",__FUNCTION__); return(0); } return(MathMedian(sorted)); }
Offensive und Defensive
Um ein besseres Gefühl für die relative Leistung zu bekommen, entwickelte Anderson das Konzept der offensiven und defensiven Scores für ein Symbol. Der Offensiv-Score ist die Performance, die erzielt wird, wenn die Benchmark-Ergebnisse über dem Durchschnitt liegen.
Der defensive Score wird in ähnlicher Weise anhand der Ergebnisse berechnet, die erzielt werden, wenn die Ergebnisse der Benchmark unter dem Durchschnitt liegen. Dieser Wert zeigt, wie gut sich ein Symbol bei schwankenden Marktpreisen hält.
Zur Berechnung dieser Werte werden die Benchmark-Ergebnisse in zwei Teile aufgeteilt: die offensiven und die defensiven Benchmark-Ergebnisse. Diese werden berechnet, indem eine geeignete Fensterlänge gewählt wird, aus der ein durchschnittlicher Benchmark berechnet wird.
In der Klasse CJanus wird der Medianwert als Mittelwert über das angegebene Fenster verwendet. Die offensive Benchmark-Ergebnisse ergibt sich aus der Differenz zwischen den erzielten Ergebnissen und den durchschnittlichen Benchmark-Ergebnissen für die Benchmarks, die größer oder gleich dem Durchschnitt sind.
Die defensiven Benchmark-Ergebnisse wird auf ähnliche Weise berechnet, indem Benchmark-Werte verwendet werden, die unter dem Durchschnitt des Fensters liegen.
//+------------------------------------------------------------------+ //|public method to calculate Index offense and defense scores | //+------------------------------------------------------------------+ void CJanus::CalculateBenchMarkOffenseDefense(const uint barshift,const uint rs_period,double& out_offense,double& out_defense) { out_defense=out_offense=WRONG_VALUE; double index[],sorted[],median,i_offense,i_defense; median=i_offense=i_defense=0; ArrayResize(index,rs_period); ArrayResize(sorted,rs_period); int begin=0; for(int i=0; i<(int)rs_period; i++) { index[i]=CalculateBenchMarkReturn(barshift+i); if(i>=begin) sorted[i-begin]=index[i]; } if(!ArraySort(sorted)) { Print("sorting error ",__LINE__," ",__FUNCTION__); return; } median=MathMedian(sorted); i_offense=1.e-30; i_defense=-1.e-30; for(int i=begin; i<(int)rs_period; i++) { if(index[i]>=median) i_offense+=index[i]-median; else i_defense+=index[i]-median; } if(i_offense<0 || i_defense>0) { #ifdef DEBUG Print("error invalid figures ","Offensive ",i_offense," Defensive ",i_defense); #endif return; } out_offense=i_offense; out_defense=i_defense; return; }
Nach der Berechnung der offensiven und defensiven Benchmark-Ergebnisse wird die Funktion verlassen. Sie werden verwendet, um die Offensiv- und Defensiv-Scores für ein Symbol zu berechnen. Über dasselbe Zeitfenster, das für die Benchmarks verwendet wird, werden die erzielten Ergebnisse zu jedem Zeitpunkt, an dem die Benchmark-Ergebnisse größer oder gleich dem Fensterdurchschnitt ist, addiert. Diese Summe wird dann als ein Bruchteil des entsprechenden offensiven Benchmarks ausgedrückt und mit 100 multipliziert.
Eine ähnliche Berechnung wird mit der defensiven Benchmark-Ergebnisse durchgeführt. Die Methode CalculateSymbolOffenseDefense() implementiert die Berechnung die Offensiv- und Defensiv-Scores.
//+------------------------------------------------------------------+ //|public method to calculate market offense and defense | //+------------------------------------------------------------------+ void CJanus::CalculateSymbolOffenseDefense(const uint barshift,const string symbol__,const uint rs_period,double &out_offense,double &out_defense) { out_defense=out_offense=0.0; int sshift=m_symbol_list.GetIndex(symbol__); if(sshift>-1) market_offense_defense(barshift,sshift,rs_period,out_offense,out_defense); else return; }
//+------------------------------------------------------------------+ //|private method that calculates market defense and offense values | //+------------------------------------------------------------------+ void CJanus::market_offense_defense(const uint barshift,const uint symbolshift,const uint rs_period,double& out_offense,double& out_defense) { out_defense=out_offense=0.0; double index[],sorted[],median,i_offense,i_defense; median=i_offense=i_defense=0; ArrayResize(index,rs_period); ArrayResize(sorted,rs_period); int begin=0; for(int i=0; i<(int)rs_period; i++) { index[i]=CalculateBenchMarkReturn(barshift+i); if(i>=begin) sorted[i-begin]=index[i]; } if(!ArraySort(sorted)) { Print("sorting error ",__LINE__," ",__FUNCTION__); return; } median=MathMedian(sorted); i_offense=1.e-30; i_defense=-1.e-30; for(int i=begin; i<(int)rs_period; i++) { if(index[i]>=median) i_offense+=index[i]-median; else i_defense+=index[i]-median; } if(i_offense<0 || i_defense>0) { #ifdef DEBUG Print("error invalid figures ","Offensive ",i_offense," Defensive ",i_defense); #endif return; } double m_offense,m_defense; m_offense=m_defense=0; for(int i=0; i<(int)rs_period; i++) { if(index[i]>=median) m_offense+=market_return(barshift+i,symbolshift); else m_defense+=market_return(barshift+i,symbolshift); } out_defense= (m_defense/i_defense) * 100; out_offense= (m_offense/i_offense) * 100; }
Indem er die offensiven und defensiven Scores aufzeichnete, bemerkte Anderson die Muster, die sich je nach den vorherrschenden Marktbedingungen ergeben würden. In den Zeiten des positiven Feedbacks waren die Scores weit gestreut und es gab einen signifikanten Unterschied zwischen den Symbolen mit der besten und der schlechtesten Leistung. Im Gegensatz zu Zeiten des negativen Feedbacks, in denen sich der Unterschied zwischen den besten und den schlechtesten Leistungen verringert hat. Anderson bezeichnete dies als Expansion und Kontraktion des Indexes.
Der folgende Code beschreibt das Skript OffensiveDefensiveScatterPlot. Es hat ähnliche Eingaben wie der obige Indikator und zeichnet Diagramme von offensiven und defensiven Scores als Animation.
//+------------------------------------------------------------------+ //| OffensiveDefensiveScatterPlot.mq5 | //| Copyright 2023, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property script_show_inputs #include <Graphics\Graphic.mqh> #include<Janus.mqh> input ENUM_PRICE AppliedPrice=CLOSE; input ENUM_DIFF_TYPE AppliedDiffType=DIFF_LOG; input ENUM_INDEX_TYPE SelectIndexType=INDEX_FOREX_MAJORS; input uint AppliedPeriod = 25; input string BenchMarkSymbols=""; input int MaxBars = 50; CJanus janus; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- if(!janus.Initialize(AppliedPrice,AppliedDiffType,SelectIndexType,PERIOD_CURRENT,MaxBars,BenchMarkSymbols)) { Print("error with janus object"); return; } //--- janus.Update(); //--- double y[]; double x[]; int size=janus.GetSymbolsTotal(); ArrayResize(x,size); ArrayResize(y,size); long chart=0; string name="OffenseDefense"; for(int k=MaxBars-(int)AppliedPeriod-1; k>=0; k--) { for(int i=0; i<size; i++) { string ssy=janus.GetSymbolAt(i); janus.CalculateSymbolOffenseDefense(k,ssy,AppliedPeriod,y[i],x[i]); } CGraphic graphic; if(ObjectFind(chart,name)<0) graphic.Create(chart,name,0,0,0,780,380); else graphic.Attach(chart,name); //--- graphic.CurveAdd(x,y,ColorToARGB(clrBlue),CURVE_POINTS,"DefensiveOffensive "); //--- graphic.CurvePlotAll(); //--- graphic.Update(); Sleep(1*1000); graphic.Destroy(); ChartRedraw(); } ChartSetInteger(0,CHART_SHOW,true); } //+------------------------------------------------------------------+
Das Skript erzeugt die folgende Grafik:
Relative Stärke
Wenn die Offensiv- und Defensivwerte eines Symbols mit der nachstehenden Formel verknüpft werden, erhält man die relative Stärke eines Symbols.
Die Herleitung dieser Formel ist im Buch von Anderson dokumentiert. Die relative Stärke wird mit der Methode CalculateRelativeStrength() berechnet.
//+------------------------------------------------------------------+ //|public method to calculate relative strength | //+------------------------------------------------------------------+ double CJanus::CalculateRelativeStrength(const uint barshift,const string symbol__,const uint rs_period,uint lag=0) { int sshift=m_symbol_list.GetIndex(symbol__); if(sshift>-1) return(rs(barshift,sshift,rs_period,lag)); else return(WRONG_VALUE); }
//+------------------------------------------------------------------+ //|private method that calculates the relative strength | //+------------------------------------------------------------------+ double CJanus::rs(const uint barshift,const uint symbolshift,const uint rs_period,uint lag=0) { if(lag>=rs_period) return(WRONG_VALUE); double index[],sorted[],median,i_offense,i_defense; median=i_offense=i_defense=0; ArrayResize(index,rs_period); ArrayResize(sorted,rs_period); int begin=(int)lag; for(int i=0; i<(int)rs_period; i++) { index[i]=CalculateBenchMarkReturn(barshift+i); if(i>=begin) sorted[i-begin]=index[i]; } if(!ArraySort(sorted)) { Print("sorting error ",__LINE__," ",__FUNCTION__); return(EMPTY_VALUE); } median=MathMedian(sorted); i_offense=1.e-30; i_defense=-1.e-30; for(int i=begin; i<(int)rs_period; i++) { if(index[i]>=median) i_offense+=index[i]-median; else i_defense+=index[i]-median; } if(i_offense<0 || i_defense>0) { #ifdef DEBUG Print("error invalid figures ","Offensive ",i_offense," Defensive ",i_defense); #endif return(WRONG_VALUE); } return(rs_off_def(barshift,symbolshift,lag,median,i_offense,i_defense,index)); }
Der nachstehende Indikatorcode stellt die relative Stärke für ein Chartsymbol dar:
//+------------------------------------------------------------------+ //| RelativeStrength.mq5 | //| Copyright 2023, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 1 #property indicator_plots 1 //--- plot RelativeStrength #property indicator_label1 "RelativeStrength" #property indicator_type1 DRAW_LINE #property indicator_color1 clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 #include<Janus.mqh> //inputs input ENUM_PRICE AppliedPrice=CLOSE; input ENUM_DIFF_TYPE AppliedDiffType=DIFF_LOG; input ENUM_INDEX_TYPE SelectIndexType=INDEX_FOREX_MAJORS; input uint AppliedPeriod = 7; input string BenchMarkSymbols=""; input int MaxBars = 300; //--- indicator buffers double RelativeStrengthBuffer[]; //--- CJanus *janus; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,RelativeStrengthBuffer,INDICATOR_DATA); //--- ArraySetAsSeries(RelativeStrengthBuffer,true); //--- PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); IndicatorSetString(INDICATOR_SHORTNAME,"RS("+_Symbol+")("+string(AppliedPeriod)+")"); //--- janus=new CJanus(); //--- if(!janus.Initialize(AppliedPrice,AppliedDiffType,SelectIndexType,PERIOD_CURRENT,MaxBars,BenchMarkSymbols)) return(INIT_FAILED); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //|Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- switch(reason) { case REASON_INITFAILED: ChartIndicatorDelete(ChartID(),ChartWindowFind(),"RS("+_Symbol+")("+string(AppliedPeriod)+")"); break; default: break; } //--- if(CheckPointer(janus)==POINTER_DYNAMIC) delete janus; } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[],p const long &tick_volume[], const long &volume[], const int &spread[]) { //--- int limit; if(prev_calculated<=0) { limit=janus.HistorySize()-int(AppliedPeriod+2); PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,rates_total-limit+1); } else limit=rates_total-prev_calculated; //--- if(!janus.Update()) return(prev_calculated); for(int i=limit;i>=1;i--) { RelativeStrengthBuffer[i]=janus.CalculateRelativeStrength(i,_Symbol,AppliedPeriod); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Der Relative-Stärke-Indikator:
Anhand der Werte für die relative Stärke erhalten wir ein klareres Bild von Expansion und Kontraktion im Zeitverlauf. Dies wird im Folgenden durch den Indikatorplot der höchsten und niedrigsten Werte der relativen Stärke dargestellt.
Der Code für diesen Indikator ist unten dargestellt.
//+------------------------------------------------------------------+ //| RelativeStrenghtBestWorst.mq5 | //| Copyright 2023, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 //--- plot Upper #property indicator_label1 "Upper" #property indicator_type1 DRAW_LINE #property indicator_color1 clrBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Lower #property indicator_label2 "Lower" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 #include<Janus.mqh> //inputs input ENUM_PRICE AppliedPrice=CLOSE; input ENUM_DIFF_TYPE AppliedDiffType=DIFF_LOG; input ENUM_INDEX_TYPE SelectIndexType=INDEX_FOREX_MAJORS; input uint AppliedPeriod = 25; input string BenchMarkSymbols=""; input int MaxBars = 300; //--- indicator buffers double UpperBuffer[]; double LowerBuffer[]; double rsv[]; CJanus *janus; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,UpperBuffer,INDICATOR_DATA); SetIndexBuffer(1,LowerBuffer,INDICATOR_DATA); //--- PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); //--- ArraySetAsSeries(UpperBuffer,true); ArraySetAsSeries(LowerBuffer,true); //--- IndicatorSetString(INDICATOR_SHORTNAME,"RS_Upperlower("+_Symbol+")("+string(AppliedPeriod)+")"); //--- janus=new CJanus(); //--- if(!janus.Initialize(AppliedPrice,AppliedDiffType,SelectIndexType,PERIOD_CURRENT,MaxBars,BenchMarkSymbols)) return(INIT_FAILED); ArrayResize(rsv,janus.GetSymbolsTotal()); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //|Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- switch(reason) { case REASON_INITFAILED: ChartIndicatorDelete(ChartID(),ChartWindowFind(),"RS_Upperlower("+_Symbol+")("+string(AppliedPeriod)+")"); break; default: break; } //--- if(CheckPointer(janus)==POINTER_DYNAMIC) delete janus; } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- int limit; if(prev_calculated<=0) { limit=janus.HistorySize()-int(AppliedPeriod+2); PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,rates_total-limit+1); } else limit=rates_total-prev_calculated; //--- if(!janus.Update()) return(prev_calculated); for(int i=limit;i>=1;i--) { for(int k=0;k<ArraySize(rsv);k++) { string sym=janus.GetSymbolAt(k); rsv[k]= janus.CalculateRelativeStrength(i,sym,AppliedPeriod); } ArraySort(rsv); UpperBuffer[i]=rsv[ArraySize(rsv)-1]; LowerBuffer[i]=rsv[0]; } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Vorreiter und Nachzügler bei der relativen Stärke
Wenn die relative Performance, die durch die Ergebnisse der besten und der schlechtesten Performer angegeben wird, gemittelt wird, erhält man die Vorreiter (leaders) bzw. die Nachzügler (laggards) der relativen Stärke. Diese Werte geben einen Hinweis auf die besten Zeitpunkte für den Handel in Abhängigkeit vom Stand der Rückmeldungen. Die relative Stärke (rs) der Vorreiter und Nachzügler wird berechnet, indem die Anzahl der besten und schlechtesten Performer angegeben wird, um einen Durchschnitt zu ermitteln.
//+------------------------------------------------------------------+ //|public method to calculate relative strength leaders and laggards | //+------------------------------------------------------------------+ void CJanus::CalculateRelativeStrengthLeaderLaggard(const uint barshift,const uint rs_period,const double rs_percent_top,double& leader,double& laggard) { leader=laggard=0; uint lag=rs_period; double sorted[]; int iwork[],k,n,isub; k=isub=-1; int size=m_symbol_list.GetCollectionLength(); ArrayResize(sorted,size); ArrayResize(iwork,size); for(int i=0; i<size; i++) { sorted[i]=rs(barshift,uint(i),rs_period,lag); iwork[i]=i; } MathQuickSortAscending(sorted,iwork,0,size-1); k=(int)(rs_percent_top*(size+1))-1; if(k<0) k=0; n=k+1; while(k>=0) { isub=iwork[k]; for(uint i=0; i<lag; i++) { laggard+=market_return(barshift+i,isub); } isub=iwork[size-1-k]; for(uint i=0; i<lag; i++) { leader+=market_return(barshift+i,isub); } --k; } leader/=n*lag; laggard/=n*lag; return; }
Der Eingabeparameter rs_percent_top für die Methode CalculateRelativeStrengthLeadersLaggards() gibt den Anteil der Symbole an, die zur Berechnung der gemittelten relativen Stärke verwendet werden. Wenn Sie z. B. rs_percent_top auf 0,1 setzen, werden die obersten und untersten 10 % der Symbole für die Berechnung der Vorreiter und Nachzügler verwendet.
Unten sehen Sie einen Screenshot des Indikators der Vorreiter und Nachzügler:
Die Spanne
Wenn die Märkte von einer positiven Rückkopplung erfasst werden, weichen die schwächsten und stärksten Wertpapiere je nach Trendrichtung voneinander ab. In einem Aufwärtstrend bevorzugen die Händler die stärkeren Wertpapiere und in einem Abwärtstrend werden die schwächeren Wertpapiere (leer-) verkauft.
Wenn die Kurse in einer Bereich feststecken, ist der Unterschied zwischen dem schwächsten und dem stärksten Wertpapier relativ gering, es liegt eine Konvergenz vor. Um diese Entwicklungen zu erkennen, berechnen wir die durchschnittliche Differenz der relativen Stärke zwischen dem schwächsten und dem stärksten Wertpapier. Dies misst die Spanne (spread) der relativen Stärke.
Die Spanne der relativen Stärke ist in der Methode CalculateRelativeStrengthSpread() implementiert.
//+------------------------------------------------------------------+ //|public method to calculate the relative strength spread. | //+------------------------------------------------------------------+ double CJanus::CalculateRelativeStrengthSpread(const uint barshift,const uint rs_period,const double rs_percent_top) { double sorted[],width,div; int k=0; int size=m_symbol_list.GetCollectionLength(); width=div=0; ArrayResize(sorted,size); for(int i=0; i<size; i++) { sorted[i]=rs(barshift,uint(i),rs_period); } if(!ArraySort(sorted)) { Print("sorting error ",__LINE__," ",__FUNCTION__); return(WRONG_VALUE); } k=(int)(rs_percent_top*(size+1))-1; if(k<0) k=0; double n=double(k+1); while(k>=0) { width+=sorted[size-1-k]-sorted[k]; --k; } return(width/=n); }
Der Indikator für die Spanne der relativen Stärke:
Die Kombination der Indikatoren von Spanne und rs-Vorreiter und -Nachzügler kann zur Entwicklung konkreter Handelsregeln verwendet werden. Nach Anderson ergeben sich die besten Chancen, wenn man mit Symbolen handelt, die sich an der oberen oder unteren Grenze der relativen Stärke des untersuchten Index befinden.
//+------------------------------------------------------------------+ //|public method to calculate relative strength leaders and laggards | //+------------------------------------------------------------------+ void CJanus::CalculateRelativeStrengthLeaderLaggard(const uint barshift,const uint rs_period,const double rs_percent_top,double& leader,double& laggard) { leader=laggard=0; uint lag=1; double sorted[]; int iwork[],k,n,isub; k=isub=-1; int size=m_symbol_list.GetCollectionLength(); ArrayResize(sorted,size); ArrayResize(iwork,size); for(int i=0; i<size; i++) { sorted[i]=rs(barshift,uint(i),rs_period,lag); iwork[i]=i; } MathQuickSortAscending(sorted,iwork,0,size-1); k=(int)(rs_percent_top*(size+1))-1; if(k<0) k=0; n=k+1; while(k>=0) { isub=iwork[k]; for(uint i=0; i<lag; i++) { laggard+=market_return(barshift+i,isub); } isub=iwork[size-1-k]; for(uint i=0; i<lag; i++) { leader+=market_return(barshift+i,isub); } --k; } leader/=n*lag; laggard/=n*lag; return; }
Wenn der Trend der Spanne in Kombination mit den rs-Vorreiter ansteigt, ist dies ein Anzeichen für eine positive Rückkopplung in Verbindung mit den Nettokäufen der starken Hände. Ein günstiger Zeitpunkt, um Symbole zu kaufen, die die höchste relative Stärke aufweisen. Wenn stattdessen die rs-Nachzügler steigen, sollten Sie die schwächeren Symbole für eine Verkaufsposition ins Visier nehmen. In jeder dieser Situationen kann es ratsam sein, diese Regeln mit einer effektiven Eingabemethode zu kombinieren, die auf das/die gewählte(n) Symbol(e) angewendet wird.
Eine weitere Möglichkeit ist die Verwendung des Spread-Indikators als Risikofilter. Bei einer positiven Rückkopplung ist der Markt weniger riskant, während eine negative Rückkopplung ein Indikator für mögliche unruhige Bedingungen ist. Eine Zeit, in der man sich wahrscheinlich vom Markt fernhalten sollte.
Schlussfolgerung
Obwohl die Analyse von Devisensymbolen vielleicht nicht die beste Anwendung des Janus-Faktors ist, besteht der Sinn dieses Artikels darin, die Leser mit der Methode vertraut zu machen. Weitere Informationen dazu finden Sie in dem unten erwähnten Buch von Anderson.Die angehängte Zip-Datei enthält den gesamten Code für die im Artikel erwähnten Tools. In der nachstehenden Tabelle sind diese aufgeführt.
Damit die Indikatoren funktionieren, sollten die Nutzer zunächst sicherstellen, dass historische Daten für alle Symbole, die den Index bilden, verfügbar sind.
Dateiname | Typ | Beschreibung |
---|---|---|
Mql5/include/Janus.mqh | Include | Include-Datei mit Definition der Klassen CSymbolData, CSymbolCollection und CJanus |
Mql5/scripts/OffensiveDefensiveScatterPlot.mq5 | Skript | Skript, das ein animiertes Streudiagramm von Offensiv- und Defensivwerten zeichnet |
Mql5/indicators/IndexReturns.mq5 | Indikator | Code für Indikator zur Anzeige von Symbolen und Benchmark-Ergebnisse |
Mql5/indicators/RelativeStrengthBestWorst.mq5 | Indikator | Indikator für die Darstellung der höchsten und niedrigsten Werte der relativen Stärke. |
Mql5/indicators/RelativeStrength.mq5 | Indikator | Indikator der relativen Stärke für ein Symbol |
Mql5/indicators/RelativeStrengthSpread.mq5 | Indikator | Indikator, der die Spanne (spread) der relativen Stärke anzeigt |
Mql5/indicatorr/RssLeaderlaggards.mq5 | Indikator | Indikator, der die RS-Vorreiter und -Nachzügler aufzeigt |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/12328
![Multibot in MetaTrader: Starten mehrerer Roboter von einem einzigen Chart aus](https://c.mql5.com/2/53/launching_multiple_robots_avatar.png)
![Kategorientheorie in MQL5 (Teil 6): Monomorphe Pullbacks und epimorphe Pushouts](https://c.mql5.com/2/53/Category-Theory-p6-avatar.png)
![Wie man MetaTrader 5 mit PostgreSQL verbindet](https://c.mql5.com/2/53/avatar_How_to_connect_MetaTrader_5_to_PostgreSQL.png)
![Algorithmen zur Optimierung mit Populationen: Ein dem Elektro-Magnetismus ähnlicher Algorithmus (ЕМ)](https://c.mql5.com/2/52/Avatar_ElectroMagnetism-like_algorithm_jj.png)
![MQL5 - Sprache von Handelsstrategien, eingebaut ins Kundenterminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- 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.