
MQL5'te Gelişmiş Uyarlanabilir Göstergeler Teorisi ve Uygulaması
Tanıtım
Bu makale, John F. Ehlers'in iki mükemmel kitabına dayanmaktadır: "Satıcılar için Roket Bilimi" ve "Hisse Senedi ve Vadeli İşlemler için Sibernetik Analiz". Dijital sinyal işleme yöntemlerini kullanan ve piyasa döngüsü tanıma için karmaşık sayıları benimseyen alışılmışın dışında bir piyasa analizi yaklaşımı, bu konuyu daha da derinleştirmemi ve ardından J.F.Ehlers tarafından sunulan üç uyarlanabilir göstergeyi MQL5'te uygulamamı sağladı.
Bu makale, uyarlanabilir göstergelerin arkasındaki temel teoriyi ve bunların MQL5 uygulamasını açıklayacaktır. Uyarlanabilir göstergeler, uyarlanabilir olmayan emsalleriyle karşılaştırılacaktır.
Piyasa döngülerini ölçmek için karmaşık sayılar ve fazörler
Karmaşık sayılar teorisi kavramı, mühendislik geçmişi olmayan okuyucular için oldukça kafa karıştırıcı olabilir, bu nedenle wiki’de teoriyi araştırmanızı ve bu makaleyi okumadan önce karmaşık sayılarla ilgili işlemlerle ilgili eğiticiyi izlemenizi öneririm.
Fazör
Fazör veya Faz Vektörü, bir döngünün genliğini ve fazını gösteren bir vektördür. Euler formülüne göre bir sinüs dalgası iki karmaşık sayı bileşeninin toplamı olarak gösterilebilir. Lütfen aşağıda bir sinüs dalgası döngüsünü gösteren dönen fazörü gözlemleyin.
Bu animasyonu ilk kez gördüğünüzde, bir döngüyle fazör ilişkisini doğru bir şekilde nasıl okuyacağınız konusunda kafanız karışmış olabilir. Bunu anlamak için bir döngüyü animasyonun sol tarafında görünen normal bir dalga formu olarak değil, sağda dönen fazör olarak tanıyacak şekilde fikrinizi değiştirmeniz gerekir.
İlk başta bunu hayal etmek zor olabilir, ama bunu şu şekilde düşünmenin bir yolunu buldum: Bir fazörün tam dönüşü 360 derece veya radyandır, aynısı tam bir döngü içindir. Bir fazörün mevcut açısı, döngünün (fazın) hangi kısmında bulunduğumuzu gösterir. Y ekseni, belirli bir fazdaki bir döngünün genliğini temsil eder.
Fazör iki bileşene ayrılabilir: InPhase bileşeni (kosinüs) ve Dörtlü bileşen (sinüs). Bu bileşenlerin türetilmesiyle ilgili ayrıntılı açıklama, "Rocket Science for Traders" kitabının Bölüm 6 "Hilbert Transforms" bölümünde bulunabilir. İlgilenen varsa, lütfen bu bölümü dikkatlice takip etsin.
Şimdilik, uyarlanabilir gösterge hesaplaması için analitik sinyali (dalga biçimi) iki bileşenden oluşan karmaşık bir sinyale dönüştürmemiz gerektiği gerçeğine odaklanmanız yeterlidir. Bunu nasıl başaracağız? Hilbert Dönüşümünden bahsettim mi? Evet, kesinlikle. Hilbert Dönüşümü tam da bunu yapabilir.
Ölçüm döngüsü süresi
Hilbert Dönüşümü tüccarlar için pratik hale getirmek için John Ehlers, kitabında Hilbert Dönüşümü serisini dört elemente indirdi.
Dörtlü bileşen denklemi:
ve InPhase bileşeninin denklemi üç çubuk gecikmeli fiyattır:
InPhase ve Quadrature bileşenlerini hesaplayarak, mevcut çubuk için ölçülen faz açısından ve bir çubuk önce ölçülen faz açısından diferansiyel faz hesaplamasını türetmek mümkündür. Mevcut çubuğun fazı, ve önceki çubuğun fazı
. Trigonometrik özdeşliği kullanma:
DeltaPhase olarak adlandırılan diferansiyel faz denklemini elde ederiz.
Bay Ehlers, DeltaPhase değişkenine ek kısıtlamalar koydu: sonuç negatif olamaz ve DeltaPhase <0,1, 1,1> radyanla sınırlıdır (6 ile 63 bar arasında bir döngü anlamına gelir). Gerçek veriler üzerinde ölçülen DeltaPhase'de bozulmalar olduğu ortaya çıktı, bu nedenle düzeltilmesi gerekiyor.
Dikenli veriler üzerinde en iyi yumuşatma yöntemi medyan filtresidir, bu nedenle beş DeltaPhase örneğinin medyanı MedianDelta değişkenini oluşturur. MedianDelta bölü , aradığımız piyasa döngüsü olan Dominant Döngüyü hesaplamak için kullanılır.
Geliştirme testleri sırasında, ölçümde kaldırılması gereken yaklaşık 0,5'lik bir sapma olduğu ortaya çıktı ve bu sapmayı ortadan kaldırmak için tazminat terimi eklendi. Son olarak, Baskın Döngü, sırasıyla 0,33 ve 0,15'e eşit alfa değerleriyle EMA tarafından iki kez düzleştirilir. Döngü süresi kademeli olarak 6'dan 40'a yükselen bir sinüs dalgasına uygulanan algoritmanın sağlamlığını görmek için gerçekten kitabı okumanızı tavsiye ederim.
Teorik bilgi ile donatılmış olduğunuz için MQL5'te CyclePeriod göstergesini uygulamaya hazırız.
Döngü Periyodu göstergesi
Gösterge iki satırdan oluşur: döngü süresini gösteren döngü çizgisi ve temel olarak bir çubuk gecikmeli döngü çizgisi olan bir tetikleme çizgisi. "Çevrim periyodu ölçümü" bölümündeki açıklamayı ve OnCalculate() fonksiyonundaki kaynak kodu takip ederseniz, çevrim periyodu ölçümünden hangi hatların sorumlu olduğunu kolayca ilişkilendirebilirsiniz.
//+------------------------------------------------------------------+ //| CyclePeriod.mq5 | //| Copyright 2011, Investeo.pl | //| http://Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http://Investeo.pl" #property version "1.00" #property indicator_separate_window #property description "CyclePeriod indicator - described by John F. Ehlers" #property description "in \"Cybernetic Analysis for Stocks and Futures\"" #property indicator_buffers 2 #property indicator_plots 2 #property indicator_width1 1 #property indicator_width2 1 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 Green #property indicator_color2 Red #property indicator_label1 "Cycle" #property indicator_label2 "Trigger Line" #define Price(i) ((high[i]+low[i])/2.0) double Smooth[]; double Cycle[]; double Trigger[]; //double Price[]; double Q1[]; // Quadrature component double I1[]; // InPhase component double DeltaPhase[]; double InstPeriod[]; double CyclePeriod[]; input double InpAlpha=0.07; // alpha //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping ArraySetAsSeries(Cycle,true); ArraySetAsSeries(CyclePeriod,true); ArraySetAsSeries(Trigger,true); ArraySetAsSeries(Smooth,true); //ArraySetAsSeries(Price,true); SetIndexBuffer(0,CyclePeriod,INDICATOR_DATA); SetIndexBuffer(1,Trigger,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); return(0); } //+------------------------------------------------------------------+ //| 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[]) { //--- long tickCnt[1]; int i; int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt); if(ticks!=1) return(rates_total); double DC, MedianDelta; Comment(tickCnt[0]); if(prev_calculated==0 || tickCnt[0]==1) { //--- last counted bar will be recounted int nLimit=rates_total-prev_calculated-1; // start index for calculations ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArrayResize(Smooth,Bars(_Symbol,_Period)); ArrayResize(Cycle,Bars(_Symbol,_Period)); //ArrayResize(Price,Bars(_Symbol,_Period)); ArrayResize(CyclePeriod,Bars(_Symbol,_Period)); ArrayResize(InstPeriod,Bars(_Symbol,_Period)); ArrayResize(Q1,Bars(_Symbol,_Period)); ArrayResize(I1,Bars(_Symbol,_Period)); ArrayResize(DeltaPhase,Bars(_Symbol,_Period)); if (nLimit>rates_total-7) // adjust for last bars nLimit=rates_total-7; for(i=nLimit;i>=0 && !IsStopped();i--) { Smooth[i] = (Price(i)+2*Price(i+1)+2*Price(i+2)+Price(i+3))/6.0; if (i<rates_total-7) { Cycle[i] = (1.0-0.5*InpAlpha) * (1.0-0.5*InpAlpha) * (Smooth[i]-2.0*Smooth[i+1]+Smooth[i+2]) +2.0*(1.0-InpAlpha)*Cycle[i+1]-(1.0-InpAlpha)*(1.0-InpAlpha)*Cycle[i+2]; } else { Cycle[i]=(Price(i)-2.0*Price(i+1)+Price(i+2))/4.0; } Q1[i] = (0.0962*Cycle[i]+0.5769*Cycle[i+2]-0.5769*Cycle[i+4]-0.0962*Cycle[i+6])*(0.5+0.08*InstPeriod[i+1]); I1[i] = Cycle[i+3]; if (Q1[i]!=0.0 && Q1[i+1]!=0.0) DeltaPhase[i] = (I1[i]/Q1[i]-I1[i+1]/Q1[i+1])/(1.0+I1[i]*I1[i+1]/(Q1[i]*Q1[i+1])); if (DeltaPhase[i] < 0.1) DeltaPhase[i] = 0.1; if (DeltaPhase[i] > 0.9) DeltaPhase[i] = 0.9; MedianDelta = Median(DeltaPhase, i, 5); if (MedianDelta == 0.0) DC = 15.0; else DC = (6.28318/MedianDelta) + 0.5; InstPeriod[i] = 0.33 * DC + 0.67 * InstPeriod[i+1]; CyclePeriod[i] = 0.15 * InstPeriod[i] + 0.85 * CyclePeriod[i+1]; Trigger[i] = CyclePeriod[i+1]; } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ double Median(double& arr[], int idx, int m_len) { double MedianArr[]; int copied; double result = 0.0; ArraySetAsSeries(MedianArr, true); ArrayResize(MedianArr, m_len); copied = ArrayCopy(MedianArr, arr, 0, idx, m_len); if (copied == m_len) { ArraySort(MedianArr); if (m_len %2 == 0) result = (MedianArr[m_len/2] + MedianArr[(m_len/2)+1])/2.0; else result = MedianArr[m_len / 2]; } else Print(__FILE__+__FUNCTION__+"median error - wrong number of elements copied."); return result; }
Herhangi bir çizelgeye ekleyerek test edebiliriz - herhangi bir güvenlik ve herhangi bir zaman dilimi için çalışacaktır.
Lütfen aşağıdaki ekran görüntüsüne bakın.
Çalışma alanımızdaki bu gösterge ile, piyasanın mevcut bir döngü dönemine uyum sağlayan göstergeler olan yeni bir tür uyarlanabilir göstergeler uygulayabiliyoruz.
Siber Döngü göstergesi
Siber Döngü göstergesi, http://www.amazon.com/Cybernetic-Analysis-Stocks-Futures-Cutting-Edge/dp/0471463078 adresinden alınan yüksek geçişli bir filtredir. Bu filtre, zaman serilerinden yalnızca çevrim modu bileşenini bırakır.
Ek olarak iki çubuklu ve üç çubuklu döngü bileşenleri, sonuçtan bir sonlu dürtü yanıtı düşük geçiş filtresiyle yumuşatılarak çıkarılır.
Kitapta anlatılan EFL (Ticaret) dilinden uyarlanmış makaledeki gösterge MQL5 kodu ve diğer göstergeler.
//+------------------------------------------------------------------+ //| CyberCycle.mq5 | //| Copyright 2011, Investeo.pl | //| http://Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http://Investeo.pl" #property version "1.00" #property indicator_separate_window #property description "CyberCycle indicator - described by John F. Ehlers" #property description "in \"Cybernetic Analysis for Stocks and Futures\"" #property description "This indicator is available for free download." #property indicator_buffers 2 #property indicator_plots 2 #property indicator_width1 1 #property indicator_width2 1 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 Green #property indicator_color2 Red #property indicator_label1 "Cycle" #property indicator_label2 "Trigger Line" #define Price(i) ((high[i]+low[i])/2.0) double Smooth[]; double Cycle[]; double Trigger[]; input double InpAlpha=0.07; // alpha //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping ArraySetAsSeries(Cycle,true); ArraySetAsSeries(Trigger,true); ArraySetAsSeries(Smooth,true); SetIndexBuffer(0,Cycle,INDICATOR_DATA); SetIndexBuffer(1,Trigger,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); return(0); } //+------------------------------------------------------------------+ //| 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[]) { //--- long tickCnt[1]; int i; int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt); if(ticks!=1) return(rates_total); Comment(tickCnt[0]); if(prev_calculated==0 || tickCnt[0]==1) { //--- last counted bar will be recounted int nLimit=rates_total-prev_calculated-1; // start index for calculations ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArrayResize(Smooth,Bars(_Symbol,_Period)); ArrayResize(Cycle,Bars(_Symbol,_Period)); if(nLimit>rates_total-4) // adjust for last bars nLimit=rates_total-4; for(i=nLimit;i>=0 && !IsStopped();i--) { Smooth[i]=(Price(i)+2*Price(i+1)+2*Price(i+2)+Price(i+3))/6.0; if(i<rates_total-5) { Cycle[i]=(1.0-0.5*InpAlpha) *(1.0-0.5*InpAlpha) *(Smooth[i]-2.0*Smooth[i+1]+Smooth[i+2]) +2.0*(1.0-InpAlpha)*Cycle[i+1]-(1.0-InpAlpha)*(1.0-InpAlpha)*Cycle[i+2]; } else { Cycle[i]=(Price(i)-2.0*Price(i+1)+Price(i+2))/4.0; } //Print(__FILE__+__FUNCTION__+" received values: ",rCnt); Trigger[i]=Cycle[i+1]; } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Göstergenin bir ekran görüntüsü aşağıya yapıştırılmıştır.
Fark edebileceğiniz gibi, bu makaledeki tüm göstergeler benzer bir görünüme sahip olacak, ancak çok farklı algoritmalar uyguluyorlar.
Bu gösterge için orijinal ticaret yöntemi basittir: döngü çizgisi tetikleme çizgisinin üzerine çıktığında satın alın. Döngü çizgisi tetik çizgisinin altından geçtiğinde sat. Bu göstergeyi kullanarak kendi stratejinizi ve bir ticaret sinyalleri modülünü uygulamak isteyebilirsiniz ve teşvik edilirsiniz.
Uyarlanabilir Siber Döngü göstergesi
Bu makalenin özü, göstergeleri nasıl uyarlanabilir hale getirebiliriz, yani statik bir ayar yerine dinamik çevrim periyodu girdileri ile nasıl hesaplayabiliriz. Bunu başarmak için, mevcut dönemi okumak için CyclePeriod göstergesine bağlanmalı ve daha sonra bu okumayı OnCalculate() işlevinde kullanmalıyız.
İlk başta göstergenin işleyicisini almamız gerekiyor:
hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha); if(hCyclePeriod==INVALID_HANDLE) { Print("CyclePeriod indicator not available!"); return(-1); }
ve ardından OnCalculate() işlevinin içinde okuyun:
int copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } alpha1 = 2.0/(CyclePeriod[0]+1.0);
Üstel hareketli alfa, denklemi ile basit bir hareketli ortalamanın uzunluğu ile ilgilidir, Adaptif Siber Döngü göstergesinde Bay Ehlers, alfa1 katsayısının hesaplanmasında uzunluk olarak Baskın Döngü periyodunu kullandı.
Tam kaynak kodu aşağıda mevcuttur:
//+------------------------------------------------------------------+ //| AdaptiveCyberCycle.mq5 | //| Copyright 2011, Investeo.pl | //| http://Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http://Investeo.pl" #property version "1.00" #property indicator_separate_window #property description "Adaptive CyberCycle indicator - described by John F. Ehlers" #property description "in \"Cybernetic Analysis for Stocks and Futures\"" #property description "This indicator is available for free download." #property indicator_buffers 2 #property indicator_plots 2 #property indicator_width1 1 #property indicator_width2 1 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 Green #property indicator_color2 Red #property indicator_label1 "Cycle" #property indicator_label2 "Trigger Line" #define Price(i) ((high[i]+low[i])/2.0) double Smooth[]; double Cycle[]; double Trigger[]; int hCyclePeriod; input double InpAlpha=0.07; // alpha for Cycle Period //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping ArraySetAsSeries(Cycle,true); ArraySetAsSeries(Trigger,true); ArraySetAsSeries(Smooth,true); SetIndexBuffer(0,Cycle,INDICATOR_DATA); SetIndexBuffer(1,Trigger,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha); if(hCyclePeriod==INVALID_HANDLE) { Print("CyclePeriod indicator not available!"); return(-1); } return(0); } //+------------------------------------------------------------------+ //| 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[]) { //--- long tickCnt[1]; int i; int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt); if(ticks!=1) return(rates_total); double CyclePeriod[1],alpha1; Comment(tickCnt[0]); if(prev_calculated==0 || tickCnt[0]==1) { //--- last counted bar will be recounted int nLimit=rates_total-prev_calculated-1; // start index for calculations ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArrayResize(Smooth,Bars(_Symbol,_Period)); ArrayResize(Cycle,Bars(_Symbol,_Period)); if(nLimit>rates_total-4) // adjust for last bars nLimit=rates_total-4; for(i=nLimit;i>=0 && !IsStopped();i--) { Smooth[i]=(Price(i)+2*Price(i+1)+2*Price(i+2)+Price(i+3))/6.0; int copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } alpha1 = 2.0/(CyclePeriod[0]+1.0); //Print(alpha1); //Print(CyclePeriod[0]); if(i>=0) { Cycle[i]=(1.0-0.5*alpha1) *(1.0-0.5*alpha1) *(Smooth[i]-2.0*Smooth[i+1]+Smooth[i+2]) +2.0*(1.0-alpha1)*Cycle[i+1]-(1.0-alpha1)*(1.0-alpha1)*Cycle[i+2]; //Print("Smooth["+IntegerToString(i)+"]="+DoubleToString(Smooth[i])+" Cycle["+IntegerToString(i)+"]="+DoubleToString(Cycle[i])); } else { Cycle[i]=(Price(i)-2.0*Price(i+1)+Price(i+2))/4.0; } //Print(__FILE__+__FUNCTION__+" received values: ",rCnt); Trigger[i]=Cycle[i+1]; } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Lütfen ekteki ekran görüntüsündeki göstergeye bakın.
İlk uyarlanabilir göstergemiz hazır. Kitaba göre, uyarlanabilir olmayan sürümden daha duyarlı olmalıdır.
Alış ve satış sinyalleri, uyarlanabilir olmayan sürümden genellikle bir çubuk önce gerçekleşmelidir.
İki gösterge örneği daha ile devam edebiliriz, uyarlanabilir göstergeler oluşturma şemasını anlamanız yeterli olacaktır.
Ağırlık Merkezi göstergesi
Herhangi bir fiziksel nesnenin ağırlık merkezinden bahsederken, onun denge noktasını kastediyoruz. Bu kavramı ticarete sokma fikri, çeşitli filtrelerin gecikmelerinin filtrenin katsayılarıyla nasıl ilişkili olduğunu gözlemlemekten geldi.
SMA - Basit Hareketli Ortalama için tüm katsayılar eşittir, ağırlık merkezi ortadadır.
WMA - Ağırlıklı Hareketli Ortalama için son fiyatlar eskilerden daha önemlidir. Spesifik olmak gerekirse, WMA katsayıları üçgenin ana hatlarını tanımlar. Üçgenin ağırlık merkezi, üçgenin tabanının uzunluğunun üçte biri kadardır. Belirli bir gözlem penceresinde ağırlık merkezinin hesaplanması için türetilen daha genel denklem aşağıdaki gibidir:
Denge noktasının konumu, pencere içindeki konumun çarpımının bu konumdaki fiyatın toplamıdır (denklemde +1, çünkü 0'dan N'ye kadar ve 1'den N'ye kadar saydığımız için) toplamına bölünür. penceredeki fiyatlar.
CG'nin temel özelliği, fiyat dalgalanmaları ile birlikte azalır ve artar ve esasen sıfır gecikmeli bir osilatördür.
Lütfen aşağıdaki kaynak kodunu bulun:
//+------------------------------------------------------------------+ //| CenterOfGravity.mq5 | //| Copyright 2011, Investeo.pl | //| http://Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http://Investeo.pl" #property version "1.00" #property indicator_separate_window #property description "CG indicator - described by John F. Ehlers" #property description "in \"Cybernetic Analysis for Stocks and Futures\"" #property description "This indicator is available for free download." #property indicator_buffers 2 #property indicator_plots 2 #property indicator_width1 1 #property indicator_width2 1 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 Green #property indicator_color2 Red #property indicator_label1 "Cycle" #property indicator_label2 "Trigger Line" #define Price(i) ((high[i]+low[i])/2.0) double Smooth[]; double Cycle[]; double Trigger[]; input double InpAlpha=0.07; // alpha input int InpCGLength=10; //CG window size //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping ArraySetAsSeries(Cycle,true); ArraySetAsSeries(Trigger,true); ArraySetAsSeries(Smooth,true); SetIndexBuffer(0,Cycle,INDICATOR_DATA); SetIndexBuffer(1,Trigger,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); return(0); } //+------------------------------------------------------------------+ //| 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[]) { //--- long tickCnt[1]; int i; double Num, Denom; // Numerator and Denominator for CG int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt); if(ticks!=1) return(rates_total); Comment(tickCnt[0]); if(prev_calculated==0 || tickCnt[0]==1) { //--- last counted bar will be recounted int nLimit=rates_total-prev_calculated-1; // start index for calculations ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArrayResize(Smooth,Bars(_Symbol,_Period)); ArrayResize(Cycle,Bars(_Symbol,_Period)); if(nLimit>rates_total-InpCGLength) // adjust for last bars nLimit=rates_total-InpCGLength; for(i=nLimit;i>=0 && !IsStopped();i--) { Num = 0.0; Denom = 0.0; for (int count=0; count<InpCGLength; count++) { Num += (1.0+count)*Price(i+count); Denom += Price(i+count); } if (Denom != 0.0) Cycle[i] = -Num/Denom+(InpCGLength+1.0)/2.0; else Cycle[i] = 0.0; //Print(__FILE__+__FUNCTION__+" received values: ",rCnt); Trigger[i]=Cycle[i+1]; } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Aşağıda bir ekran görüntüsü. Lütfen küçük gecikmeye dikkat edin.
Uyarlanabilir Ağırlık Merkezi göstergesi
CG osilatörü, sabit uzunluklu bir zaman penceresinde ağırlık merkezini bulur. Adaptif CG osilatörü, dinamik pencere uzunluğu olarak ölçülen Baskın Döngü süresinin yarısını kullanır. Ölçülen Baskın Döngü süresinin yarısını çıkarmak için aşağıdaki kod kullanıldı.
copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } CG_len = floor(CyclePeriod[0]/2.0);
Lütfen aşağıda tam gösterge kaynak kodunu bulun ve uyarlamalı olmayan sürümüyle ve benzerlikler için Uyarlamalı Siber Döngü göstergesiyle karşılaştırın.
//+------------------------------------------------------------------+ //| AdaptiveCenterOfGravity.mq5 | //| Copyright 2011, Investeo.pl | //| http://Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http://Investeo.pl" #property version "1.00" #property indicator_separate_window #property description "Adaptive CG indicator - described by John F. Ehlers" #property description "in \"Cybernetic Analysis for Stocks and Futures\"" #property description "This indicator is available for free download." #property indicator_buffers 2 #property indicator_plots 2 #property indicator_width1 1 #property indicator_width2 1 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 Green #property indicator_color2 Red #property indicator_label1 "Cycle" #property indicator_label2 "Trigger Line" #define Price(i) ((high[i]+low[i])/2.0) double Smooth[]; double Cycle[]; double Trigger[]; int hCyclePeriod; input double InpAlpha=0.07; // alpha //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping ArraySetAsSeries(Cycle,true); ArraySetAsSeries(Trigger,true); ArraySetAsSeries(Smooth,true); SetIndexBuffer(0,Cycle,INDICATOR_DATA); SetIndexBuffer(1,Trigger,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha); if(hCyclePeriod==INVALID_HANDLE) { Print("CyclePeriod indicator not available!"); return(-1); } return(0); } //+------------------------------------------------------------------+ //| 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[]) { //--- long tickCnt[1]; int i, copied; double Num,Denom; // Numerator and Denominator for CG double CG_len; int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt); if(ticks!=1) return(rates_total); double CyclePeriod[1]; Comment(tickCnt[0]); if(prev_calculated==0 || tickCnt[0]==1) { //--- last counted bar will be recounted int nLimit=rates_total-prev_calculated-1; // start index for calculations ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArrayResize(Smooth,Bars(_Symbol,_Period)); ArrayResize(Cycle,Bars(_Symbol,_Period)); copied=CopyBuffer(hCyclePeriod,0,0,1,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } if(nLimit>rates_total-int(CyclePeriod[0])-2) // adjust for last bars nLimit=rates_total-int(CyclePeriod[0])-2; for(i=nLimit;i>=0 && !IsStopped();i--) { copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } CG_len = floor(CyclePeriod[0]/2.0); //Print("CG_len="+DoubleToString(CG_len)); Num=0.0; Denom=0.0; for(int count=0; count<int(CG_len); count++) { Num+=(1.0+count)*Price(i+count); Denom+=Price(i+count); } if(Denom!=0.0) Cycle[i]=-Num/Denom+(CG_len+1.0)/2.0; else Cycle[i]=0.0; //Print(__FILE__+__FUNCTION__+" received values: ",rCnt); Trigger[i]=Cycle[i+1]; } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Lütfen aşağıda yapıştırılan AdaptiveCG göstergesi ekran görüntüsünü inceleyin.
RVI göstergesi
RVI kısaltması, Relative Vigor Index anlamına gelir. Bu göstergenin arkasındaki temel teori, fiyatların boğa piyasalarında kapanış fiyatının açık fiyattan daha yüksek ve ayı piyasalarında kapanış fiyatının açık fiyattan daha düşük olma eğiliminde olmasıdır.
Hareketin gücü, günlük işlem aralığına göre kapanış fiyatı ile açılış fiyatı arasındaki farkla ölçülür.
Bu, artık MetaTrader 5 kurulumuna gömülü olduğu için birçok MetaTrader kullanıcısı için oldukça bilinen bir göstergedir.
Hala referans için kaynak kodunu yapıştırıyorum:
//+------------------------------------------------------------------+ //| RVI.mq5 | //| Copyright 2009, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2009, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property description "Relative Vigor Index" //--- indicator settings #property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 Green #property indicator_color2 Red #property indicator_label1 "RVI" #property indicator_label2 "Signal" //--- input parameters input int InpRVIPeriod=10; // Period //--- indicator buffers double ExtRVIBuffer[]; double ExtSignalBuffer[]; //--- #define TRIANGLE_PERIOD 3 #define AVERAGE_PERIOD (TRIANGLE_PERIOD*2) //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ void OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,ExtRVIBuffer,INDICATOR_DATA); SetIndexBuffer(1,ExtSignalBuffer,INDICATOR_DATA); IndicatorSetInteger(INDICATOR_DIGITS,3); //--- sets first bar from what index will be drawn PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+TRIANGLE_PERIOD); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+AVERAGE_PERIOD); //--- name for DataWindow and indicator subwindow label IndicatorSetString(INDICATOR_SHORTNAME,"RVI("+string(InpRVIPeriod)+")"); PlotIndexSetString(0,PLOT_LABEL,"RVI("+string(InpRVIPeriod)+")"); PlotIndexSetString(1,PLOT_LABEL,"Signal("+string(InpRVIPeriod)+")"); //--- initialization done } //+------------------------------------------------------------------+ //| Relative Vigor Index | //+------------------------------------------------------------------+ 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 &TickVolume[], const long &Volume[], const int &Spread[]) { int i,j,nLimit; double dValueUp,dValueDown,dNum,dDeNum; //--- check for bars count if(rates_total<=InpRVIPeriod+AVERAGE_PERIOD+2) return(0); // exit with zero result //--- check for possible errors if(prev_calculated<0) return(0); // exit with zero result //--- last counted bar will be recounted nLimit=InpRVIPeriod+2; if(prev_calculated>InpRVIPeriod+TRIANGLE_PERIOD+2) nLimit=prev_calculated-1; //--- set empty value for uncalculated bars if(prev_calculated==0) { for(i=0;i<InpRVIPeriod+TRIANGLE_PERIOD;i++) ExtRVIBuffer[i]=0.0; for(i=0;i<InpRVIPeriod+AVERAGE_PERIOD;i++) ExtSignalBuffer[i]=0.0; } //--- RVI counted in the 1-st buffer for(i=nLimit;i<rates_total && !IsStopped();i++) { dNum=0.0; dDeNum=0.0; for(j=i;j>i-InpRVIPeriod;j--) { dValueUp=Close[j]-Open[j]+2*(Close[j-1]-Open[j-1])+2*(Close[j-2]-Open[j-2])+Close[j-3]-Open[j-3]; dValueDown=High[j]-Low[j]+2*(High[j-1]-Low[j-1])+2*(High[j-2]-Low[j-2])+High[j-3]-Low[j-3]; dNum+=dValueUp; dDeNum+=dValueDown; } if(dDeNum!=0.0) ExtRVIBuffer[i]=dNum/dDeNum; else ExtRVIBuffer[i]=dNum; } //--- signal line counted in the 2-nd buffer nLimit=InpRVIPeriod+TRIANGLE_PERIOD+2; if(prev_calculated>InpRVIPeriod+AVERAGE_PERIOD+2) nLimit=prev_calculated-1; for(i=nLimit;i<rates_total && !IsStopped();i++) ExtSignalBuffer[i]=(ExtRVIBuffer[i]+2*ExtRVIBuffer[i-1]+2*ExtRVIBuffer[i-2]+ExtRVIBuffer[i-3])/AVERAGE_PERIOD; //--- OnCalculate done. Return new prev_calculated. return(rates_total); } //+------------------------------------------------------------------+
Varsayılan 10'a ayarlanmış süre ile standart RVI göstergesinin ekran görüntüsü aşağıya yapıştırılmıştır.
Uyarlanabilir RVI göstergesi
Önceki iki uyarlanabilir göstergede olduğu gibi, Dominant Döngü ölçümünü CyclePeriod göstergesinden çıkarmamız ve bunu RVI dönemine uygulamamız gerekiyor. "Uzunluk" değişkeni, dönemin dört çubuk ağırlıklı hareketli ortalaması olarak hesaplanır:
copied=CopyBuffer(hCyclePeriod,0,0,4,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } AdaptiveRVIPeriod = int(floor((4*CyclePeriod[0]+3*CyclePeriod[1]+2*CyclePeriod[2]+CyclePeriod[3])/20.0));
Lütfen aşağıda Uyarlanabilir RVI göstergesinin tam kaynak kodunu bulun.
//+------------------------------------------------------------------+ //| Adaptive RVI.mq5 | //| Based on RVI by MetaQuotes Software Corp. | //| Copyright 2009, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2009, MetaQuotes Software Corp." #property copyright "2011, Adaptive version Investeo.pl" #property link "https://www.mql5.com" #property description "Adaptive Relative Vigor Index" //--- indicator settings #property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 Green #property indicator_color2 Red #property indicator_label1 "AdaptiveRVI" #property indicator_label2 "Signal" #define Price(i) ((high[i]+low[i])/2.0) //--- input parameters input int InpRVIPeriod=10; // Initial RVI Period //--- indicator buffers double ExtRVIBuffer[]; double ExtSignalBuffer[]; //--- int hCyclePeriod; input double InpAlpha=0.07; // alpha for Cycle Period int AdaptiveRVIPeriod; #define TRIANGLE_PERIOD 3 #define AVERAGE_PERIOD (TRIANGLE_PERIOD*2) //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,ExtRVIBuffer,INDICATOR_DATA); SetIndexBuffer(1,ExtSignalBuffer,INDICATOR_DATA); IndicatorSetInteger(INDICATOR_DIGITS,3); hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha); if(hCyclePeriod==INVALID_HANDLE) { Print("CyclePeriod indicator not available!"); return(-1); } //--- sets first bar from what index will be drawn PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+TRIANGLE_PERIOD); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+AVERAGE_PERIOD); //--- name for DataWindow and indicator subwindow label IndicatorSetString(INDICATOR_SHORTNAME,"AdaptiveRVI"); PlotIndexSetString(0,PLOT_LABEL,"AdaptiveRVI"); PlotIndexSetString(1,PLOT_LABEL,"Signal"); //--- initialization done return 0; } //+------------------------------------------------------------------+ //| Relative Vigor Index | //+------------------------------------------------------------------+ 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 &TickVolume[], const long &Volume[], const int &Spread[]) { int i,j,nLimit; double dValueUp,dValueDown,dNum,dDeNum; double CyclePeriod[4]; int copied; copied=CopyBuffer(hCyclePeriod,0,0,4,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } AdaptiveRVIPeriod = int(floor((4*CyclePeriod[0]+3*CyclePeriod[1]+2*CyclePeriod[2]+CyclePeriod[3])/20.0)); //--- check for bars count if(rates_total<=AdaptiveRVIPeriod+AVERAGE_PERIOD+2) return(0); // exit with zero result //--- check for possible errors if(prev_calculated<0) return(0); // exit with zero result //--- last counted bar will be recounted nLimit=AdaptiveRVIPeriod+2; if(prev_calculated>AdaptiveRVIPeriod+TRIANGLE_PERIOD+2) nLimit=prev_calculated-1; //--- set empty value for uncalculated bars if(prev_calculated==0) { for(i=0;i<AdaptiveRVIPeriod+TRIANGLE_PERIOD;i++) ExtRVIBuffer[i]=0.0; for(i=0;i<AdaptiveRVIPeriod+AVERAGE_PERIOD;i++) ExtSignalBuffer[i]=0.0; } //--- RVI counted in the 1-st buffer for(i=nLimit;i<rates_total && !IsStopped();i++) { copied=CopyBuffer(hCyclePeriod,0,rates_total-i-1,4,CyclePeriod); if(copied<=0) { Print("FAILURE: Could not get values from CyclePeriod indicator."); return -1; } AdaptiveRVIPeriod = int(floor((4*CyclePeriod[0]+3*CyclePeriod[1]+2*CyclePeriod[2]+CyclePeriod[3])/20.0)); dNum=0.0; dDeNum=0.0; for(j=i;j>MathMax(i-AdaptiveRVIPeriod, 3);j--) { //Print("rates_total="+IntegerToString(rates_total)+" nLimit="+IntegerToString(nLimit)+ // " AdaptiveRVIPeriod="+IntegerToString(AdaptiveRVIPeriod)+" j="+IntegerToString(j)); dValueUp=Close[j]-Open[j]+2*(Close[j-1]-Open[j-1])+2*(Close[j-2]-Open[j-2])+Close[j-3]-Open[j-3]; dValueDown=High[j]-Low[j]+2*(High[j-1]-Low[j-1])+2*(High[j-2]-Low[j-2])+High[j-3]-Low[j-3]; dNum+=dValueUp; dDeNum+=dValueDown; } if(dDeNum!=0.0) ExtRVIBuffer[i]=dNum/dDeNum; else ExtRVIBuffer[i]=dNum; } //--- signal line counted in the 2-nd buffer nLimit=AdaptiveRVIPeriod+TRIANGLE_PERIOD+2; if(prev_calculated>AdaptiveRVIPeriod+AVERAGE_PERIOD+2) nLimit=prev_calculated-1; for(i=nLimit;i<rates_total && !IsStopped();i++) ExtSignalBuffer[i]=(ExtRVIBuffer[i]+2*ExtRVIBuffer[i-1]+2*ExtRVIBuffer[i-2]+ExtRVIBuffer[i-3])/AVERAGE_PERIOD; //--- OnCalculate done. Return new prev_calculated. return(rates_total); } //+------------------------------------------------------------------+
Dinamik pencere uzunluğuna sahip Uyarlanabilir RVI göstergesinin ekran görüntüsü:
Sonuç
Bu makale, üç uyarlanabilir teknik gösterge davranışını ve MQL5 uygulamasını sundu.
Uyarlanabilir göstergeleri uygulama mekanizması, makaleyi okuduktan sonra açıkça anlaşılabilir olmalıdır. Açıklanan tüm göstergeler eklerde mevcuttur.
Yazar, halihazırda mevcut olanlardan diğer uyarlanabilir göstergeleri denemeye ve oluşturmaya teşvik eder.
MetaQuotes Ltd tarafından İngilizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/en/articles/288





- Ücretsiz ticaret uygulamaları
- 24 saat boyunca ücretsiz Forex VPS
- Ticaret kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Web sitesi politikasını ve kullanım şartlarını kabul edersiniz