English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MQL5'te Trend Bulmanın Birkaç Yolu

MQL5'te Trend Bulmanın Birkaç Yolu

MetaTrader 5Ticaret | 9 Aralık 2021, 11:12
228 0
Dmitriy Skub
Dmitriy Skub

Giriş

Herhangi bir yatırımcı "Trend senin arkadaşındır, trendi takip et" kuralını bilir, ancak hemen hemen herkesin trendin ne olduğu hakkında kendi fikri vardır. Neredeyse her yatırımcı, trende karşı ticaret yapan yatırımcıların kendilerini nasıl mahvettiklerini anlatan korkunç hikayeler duymuş veya okumuştur.

Herhangi bir yatırımcı, herhangi bir zamanda bir trendi doğru bir şekilde tespit etme fırsatı için çok şey verir. Belki de herkesin aradığı Kutsal Kase budur. Bu makalede bir trendi tespit etmenin birkaç yolunu ele alacağız. Daha net olmak gerekirse MQL5 aracılığıyla bir trendi tespit etmek için birkaç klasik yolun nasıl programlanacağına bakacağız.


1. Trend Nedir ve Neden Bilinmelidir?

Her şeyden önce, bir trendin genel kavramını formüle edelim.

Trend - piyasadaki fiyat değişiminin uzun vadeli eğilimi (yönü). Trendin bu genel tanımından şu sonuçlar çıkar:

  • Fiyat değişiminin yönü, fiyat zaman serilerinin dikkate alındığı zaman dilimine bağlıdır.
  • Fiyat değişiminin yönü, bir trendi belirlemek için zaman serilerinin analizinin başladığı referans noktasına bağlıdır.

Bu kavramı örneklendirelim:

Şekil 1. Trend Analizi

Şekil 1. Trend analizi

Şekle bakıldığında, 2005 sonundan Mayıs 2006'ya kadar genel trendin büyüdüğünü görebilirsiniz (grafikteki yeşil ok). Ancak fiyat grafiğinin daha küçük parçalarını ele alırsak, Şubat 2006'da trendin açıkça aşağı doğru olduğunu (grafikte kırmızı ok) ve neredeyse tüm Ocak ayı boyunca fiyatın yan koridorda (sarı ok) olduğunu göreceksiniz.

Bu nedenle, bir trend belirlemeden önce hangi zaman dilimiyle ilgilendiğinizi belirlemelisiniz. Alım satım için zaman dilimi her şeyden önce, açılıştan kapanışa kadar piyasada pozisyon tutma süresini belirler. Buna ek olarak, koruyucu durdurmalar ve beklenen kapanışlar ile alım satım işlemlerin sıklığı bağımlıdır.

Bu makalenin amacı, yeni yatırımcıların MetaTrader 5 platformu tarafından sağlanan trend algılama araçlarını yetkin bir şekilde kullanmalarına yardımcı olmaktır. Bu makale ayrıca, bu süreci otomatikleştiren basit göstergeler yazma konusunda temel bilgileri vermeyi amaçlamaktadır. Nihai hedef, bu göstergeleri otomatik alım satım için kullanan basit uzmanlar yazmaktır.  

  Kesinlik için Forex piyasasındaki en likit enstrüman olan EURUSD'nin günlük fiyat grafiğini (terminalde D1 zaman çerçevesi) dikkate alacağız. Bu tür bir zaman diliminde pozisyon tutma süresi birkaç günden birkaç aya kadar değişebilir. Buna göre amaç, yüzlerce hatta binlerce nokta almaktır ve koruyucu zarar durdurma birkaç yüz nokta uzaklıkta bulunur.

Genel olarak, aşağıda açıklananların tümü herhangi bir zaman diliminde kullanılabilir. Bununla birlikte, grafik zaman dilimi ne kadar küçükse alım satım üzerindeki etkisinin de haberler, ana katılımcıların piyasa spekülasyonları ve piyasanın volatilitesini etkileyen diğer faktörlerin neden olduğu gürültü bileşenine sahip olduğunu unutmayın.

Trend ne kadar uzun olursa kayma olasılığının da o kadar düşük olduğunu hesaba katarsak, trendle alım satım yaparken para kaybetmekten ziyade kazanma olasılığı daha yüksektir. Şimdi fiyat grafiğindeki bir trendi nasıl tespit edeceğinizi anlamalısınız. Bu konu bu makalede tartışılacaktır.


2. Trend Nasıl Tespit Edilir?

Trendi algılamanın bilinen bazı yolları şunlardır:

  1. Hareketli Ortalamalara Göre
  2. Zigzag pik noktalarına göre
  3. ADX göstergelerine göre
  4. NRTR’ye göre
  5. Heiken Ashi mum grafiklerinin rengine göre

Tüm bu yöntemleri, avantajlarını ve dezavantajlarını sürekli olarak ele alacağız. Sonra onları geçmişin aynı döneminde karşılaştıracağız.

2.1. Hareketli Ortalama Kullanarak Trend Algılama

Bir trendi ve yönünü tespit etmenin belki de en kolay yolu - değiştirme. Teknik analizin ilk araçlarından biri olan hareketli ortalama, hala farklı varyasyonlarda kullanılmaktadır ve çoğu göstergenin temelidir. Yatırımcılar hem bir hareketli ortalamayı hem de bazen "yelpaze" olarak adlandırılan bir dizi hareketli ortalamayı kullanırlar. 

Tek bir hareketli ortalama için basit bir kural formüle edelim:
  • Belirli bir zaman diliminde çubuğun kapanış fiyatı hareketli ortalamanın üzerindeyse trend yükselir.
  • Belirli bir zaman diliminde çubuğun kapanış fiyatı hareketli ortalamanın altındaysa trend düşer.

Bu durumda, fiyat hareketli ortalamanın yakınında yukarı ve aşağı dalgalandığında ("sıçrama" olarak adlandırılır) "yanlış" trend değişikliklerinin sayısını azaltmak için çubuğun kapanış fiyatını kullanacağız.  

Bu yöntemi örnekleyelim:

Şekil 2. Hareketli Ortalamayı Kullanarak Trend Belirleme

Şekil 2. Hareketli Ortalamayı Kullanarak Trend Belirleme

Burada EURUSD D1 grafiğini ve kapanış fiyatlarına (grafikte kırmızı çizgi) dayanan 200 dönemine sahip basit bir hareketli ortalama kullanıyoruz. Şeklin alt kısmında özel olarak geliştirilmiş trend göstergesini görebilirsiniz - MATrendDetector. Trendin yönü, gösterge histogramının sıfır eksenine göre pozisyonu ile gösterilir. +1, yukarı trendine, -1 düşüş trendine karşılık gelir. Ayrıca bu makalede kullanılan bu ve diğer göstergeleri tartışacağız.

Çubuk hareketli ortalamanın üstünde/altında kapandığında, fiyatın genellikle ters yöne döndüğünü görebilirsiniz. Yani bu yöntem çok fazla yanlış sinyal veriyor. Bu nedenle uzmanlarda ve göstergelerde kullanımı çok sınırlıdır, yalnızca çok "kaba" bir trend filtresi olarak kullanılır.

2.2. Üç Hareketli Ortalamayı Kullanarak Trend Algılama

Hareketli ortalamaları kullanarak trend algılama kalitesini artırmak için ne yapılabilir? Örneğin, farklı dönemlere sahip iki veya daha fazla hareketli ortalama kullanabilirsiniz. Ardından, farklı dönemlere sahip herhangi bir sayıda (birden fazla) hareketli ortalama için trend algılama kuralı aşağıdaki gibi görünecektir:

  • Belirli bir zaman diliminde tüm hareketli ortalamalar, çubuk kapanışında doğru yükselen sırada çizilirse, trend yükselir.
  • Belirli bir zaman diliminde tüm hareketli ortalamalar, çubuğun kapanmasında doğru düşen sırada çizilirse trend düşer.

Burada aşağıdaki terimleri kullanıyoruz:

  • Doğru yükselen sıra - her hareketli ortalama, daha yüksek dönemli diğer tüm hareketli ortalamalardan daha yüksek olmalıdır.
  • Doğru düşen sıra - her hareketli ortalama, daha yüksek dönemli diğer tüm hareketli ortalamalardan daha düşük olmalıdır.

Bu tür "ortalamaların doğru sırası", görsel benzerlik nedeniyle ortalamalar yelpazesinin yukarı/aşağı açılması olarak da adlandırılır.

Bu yöntemi örnekleyelim:

Şekil 3. Birkaç Hareketli Ortalama Kullanarak Trend Algılama

Şekil 3. Birkaç Hareketli Ortalama Kullanarak Trend Algılama

Burada, kapanış fiyatlarına dayalı olarak 200 (kalın kırmızı çizgi), 50 (orta kalınlıkta sarı çizgi) ve 21 (ince mor çizgi) dönemleriyle EURUSD D1 grafiğini ve basit hareketli ortalamaları kullanıyoruz.

Şeklin alt kısmında özel olarak geliştirilmiş trend göstergesini görebilirsiniz - FanTrendDetector. Trendin yönü, gösterge histogramının sıfır eksenine göre pozisyonu ile gösterilir. +1, yukarı trendine, -1 düşüş trendine karşılık gelir. Histogram değeri sıfıra eşitse bu, trendin algılanamadığı anlamına gelir. Karşılaştırma için MATrendDetector göstergesi de vardır.

Trend değişikliğinin yanlış alarmlarının sayısının azaldığı açıktır. Ancak trend algılama gecikmesi artırıldı. Bu mantıklıdır, tüm hareketli ortalamaların "doğru" sırada sıralanması biraz zaman alabilir. Neyin daha iyi olduğu ve olmadığı, bu yöntemleri kullanan alım satım sistemine bağlıdır.

Bu durumda, ortalamaların dönem değerleri hiçbir şekilde seçilmez ancak en yaygın olarak yatırımcılar ve makalenin yazarı tarafından kullanılır. Bir dizi ortalama ve bunların sayısını seçerek, belirli bir para birimi çifti için bu trend algılama yönteminin özelliklerini iyileştirmeyi deneyebilirsiniz.

2.3. ZigZag Göstergesinin Maksimum ve Minimumlarını Kullanarak Trend Algılama

Şimdi trend algılamaya teknik analiz klasikleri perspektifinden yaklaşalım. Yani, aşağıdaki Charles Dow kuralını kullanacağız:

  • Bir sonraki yerel maksimum fiyat grafiği bir önceki yerel maksimumdan daha yüksekse ve sonraki her yerel minimum fiyat grafiği de önceki yerel minimumdan daha yüksekse trend yükselir.
  • Bir sonraki yerel minimum fiyat grafiği önceki yerel minimumdan düşükse ve sonraki her yerel maksimum fiyat grafiği de önceki yerel maksimumdan düşükse trend düşer.

Zigzag göstergesinin üst kısımlarında yerel maksimumları/minimumları bulacağız.

Bu yöntemi örnekleyelim:

Şekil 4. ZigZag Göstergesini Kullanarak Trend Algılama

Şekil 4. ZigZag Göstergesini Kullanarak Trend Algılama

Burada EURUSD D1 grafiğini ve Zigzag'ı aşağıdaki parametrelerle kullanıyoruz: ExtDepth = 5, ExtDeviation = 5, ExtBackstep = 3.

Şeklin alt kısmında özel olarak geliştirilmiş trend göstergesini görebilirsiniz - ZigZagTrendDetector.

Bu trend algılama yönteminin ana dezavantajı, gerçek zamanlı olarak uç değerin zaten oluşturulup oluşturulmadığını anlamanın imkansız olmasıdır. Geçmişte uç değer çok iyi görülebilir ve bunların nerede oluştuklarını anlayabilirsiniz. Ancak fiyat gerçek zamanlı değiştiğinde, oluşan uç değer aniden kaybolabilir veya tekrar ortaya çıkabilir. Bunu görmek için herhangi bir uzmanın görsel test modunda çizilen Zigzag çizgilerine bakın.

Bu dezavantaj, alım satımda pratik kullanım için bu yöntemi değersiz kılmaktadır. Ancak, modelleri bulmak ve çeşitli alım satım sistemlerinin kalitesini değerlendirmek amacıyla geçmiş verilerin teknik analizi için çok yararlıdır.

2.4. ADX Göstergesini Kullanarak Trend Algılama

Aşağıda ele alınan yol, ADX göstergesini (Ortalama Yönlü Hareket İndisi) kullanarak trend tespitidir. Bu gösterge sadece trend yönünü tespit etmek için değil, aynı zamanda gücünü değerlendirmek için de kullanılır. Bu, ADX göstergesinin çok değerli bir özelliğidir. Trendin gücü, ana ADX çizgisi tarafından belirlenir - değer 20'den büyükse (genel olarak kabul edilen seviyedir, ancak şu anda en iyisi olması gerekmez), o zaman trend yeterince güçlüdür.

Trendin yönü, birbirine yönelik +DI ve -DI çizgileri tarafından belirlenir. Bu gösterge, üssel ortalama ile üç satırın hepsinin düzleştirmesini kullanır ve bu nedenle trend değişikliğine karşı yanıt gecikmesine sahiptir.

Trend algılama kuralını formüle edelim:

  • +DI çizgisi -DI çizgisinden daha yüksekse trend yükselir.
  • +DI çizgisi -DI çizgisinden daha düşükse trend düşer.

Bu durumda, bir trendi tespit etmek için ADX trend çizgisi kullanılmaz. Bu göstergenin yanlış sinyallerinin sayısını azaltmak gerekir. Trend zayıfsa (ADX 20'den azsa), güçlenene kadar beklemek ve ancak o zaman trendle alım satıma başlamak en iyisidir.

Bu yöntemi örnekleyelim:

Şekil 5. ADX Göstergesini Kullanarak Trend Belirleme

Şekil 5. ADX Göstergesini Kullanarak Trend Belirleme

Burada EURUSD D1 grafiğini ve ADX göstergesini aşağıdaki parametrelerle kullanıyoruz: PeriodADX = 21 (kalın mavi çizgi ADX trend gücünün değeri, ince yeşil çizgi +DI değeri, ince kırmızı çizgi -DI değeri).

Şeklin alt kısmında özel olarak geliştirilmiş trend göstergesini görebilirsiniz - ADXTrendDetector. Karşılaştırma için ADXTrendDetector göstergesinin üst grafiğinde (kırmızı) trend gücü filtresi devre dışı bırakılmıştır (ADXTrendLevel = 0) ve alt grafikte (mavi) etkinleştirilmiştir (ADXTrendLevel = 20).

Eğilim gücü filtresini açtığımızda, trend yönünü tespit etmede "sıçrama" denilen kısmın çıkarıldığına dikkat edin. Bu filtrenin gerçek çalışmada kullanılması arzu edilir. Gösterge kalitesinin daha da iyileştirilmesi, piyasadaki mevcut duruma (düz/aralık/trend) ve para birimi çifti hareketinin doğasına bağlı olarak dış parametrelerin ustaca seçilmesiyle sağlanabilir.

Genel olarak bu gösterge, girdi filtresi olarak trend izleme ticaret sistemleri oluşturmak için iyi bir fırsat sağlar.

2.5. NRTR Göstergesini Kullanarak Trend Algılama

Aşağıdaki trend algılama yöntemi - NRTR (Nick Rypock Trailing Reverse) göstergesini kullanarak çalışır. Bu gösterge her zaman ulaşılan uç nokta fiyatından sabit bir mesafede bulunur - yükseliş trendlerinde daha düşük fiyatlar ve düşüş trendlerinde daha yüksek fiyatlar. Bu göstergenin ana fikri, ana trende karşı küçük düzeltici hareketlerin göz ardı edilmesi gerektiği ve ana trende karşı hareket, belirli bir seviyeyi aşarsa, trend yönü değişikliğine işaret etmektir.

Bu bildirimden, trend yönünü tespit etme kuralı gelir:

  • Trend yükselir - gösterge çizgisi, çubuğun kapanmasındaki yükseliş trendine karşılık geldiğinde.
  • Trend düşer - gösterge çizgisi, çubuğun kapanmasındaki düşüş trendine karşılık geldiğinde

Yanlış trend terslerinin fiyat dalgalanmaları üzerindeki etkisini azaltmak için NRTR çizgi pozisyonunu kontrol ederken kapanış fiyatlarını kullanacağız.

Bu yöntemi örnekleyelim:

Şekil 6. NRTR Göstergesini Kullanarak Trend Belirleme

Şekil 6. NRTR Göstergesini Kullanarak Trend Belirleme

Bu büyük mavi noktalar yükseliş eğilimine, büyük kırmızı noktalar ise düşüş eğilimine karşılık gelir. Grafiğin altında, aşağıda açıklanan trend göstergemiz NRTRTrendDetector görüntülenir.

2.6. Üç Heiken Ashi Mumu Kullanarak Trend Algılama

Bir trendi algılamanın bir başka popüler yolu da Heiken Ashi mumlarını kullanmaktır. Heiken Ashi grafikleri, değiştirilmiş Japon mum grafikleridir. Değerlerinin, kısmen bir önceki mumla ortalaması alınır.

Bu yöntemi örnekleyelim:

Şekil 7. Heiken Ashi Mumlarının Rengine Göre Trend Algılama

Şekil 7. Heiken Ashi Mumlarının Rengine Göre Trend Algılama

Gördüğünüz gibi bu yöntem, aynı zamanda bir yan koridorda fiyat dalgalandığında "yanlış" sinyallerden de muaf değildir. Ancak daha da kötüsü, bu göstergenin yalnızca son çubuğu değil, aynı zamanda sondan bir önceki çubuğu da yeniden çizebilmesidir. Yani girdiğimiz sinyal bir sonraki çubukta tersine çevrilebilir. Bunun nedeni, mumların rengi belirlenirken iki çubuğun analiz edilmesidir, bu nedenle bu yöntemin diğer destekleyici sinyallerle birlikte kullanılması önerilir.


3. Trend Göstergeleri

Şimdi trend göstergeleri oluşturalım.

3.1. Hareketli Ortalamaya Dayalı Trend Göstergesi

Bir trend belirlemenin en kolay yolu olarak hareketli ortalamaya dayalı en kolay gösterge. Hangi parçalardan oluştuğunu düşünelim. Göstergenin tam kaynak kodu, makaleye eklenmiş MATrendDetector.MQ5 dosyasındadır.

Gösterge programının başında, çeşitli hareketli ortalamaları hesaplamak için kitaplığı birbirine bağlayan satır gelir. Bu kitaplık, İstemci Terminali ile birlikte gelir ve kurulumdan hemen sonra kullanıma hazırdır. Satır şöyledir:

#include <MovingAverages.mqh>

Basit bir hareketli ortalama hesaplayan bir fonksiyon kullanacağız:

double SimpleMA(const int position, const int period, const double &price[])

Burada giriş parametrelerini tanımlarsınız:

  • pozisyon - price[] dizisindeki ilk indis, hesaplamanın başladığı yerdir.
  • dönem - hareketli ortalama dönemi, sıfırdan büyük olmalıdır.
  • price[] - grafikte gösterge yerleşimi sırasında belirtilen fiyat aralığını içeren dizi. Varsayılan olarak Close[] çubuğunun kapanış fiyatları kullanılır.

Fonksiyon, hareketli ortalamanın hesaplanan değerini verir.

Metnin sonraki kısmı, göstergeyi ekranda görüntülemek için gereken ilk ayarları içerir:

//---------------------------------------------------------------------
#property indicator_separate_window
//---------------------------------------------------------------------
#property indicator_applied_price       PRICE_CLOSE
#property indicator_minimum             -1.4
#property indicator_maximum             +1.4
//---------------------------------------------------------------------
#property indicator_buffers             1
#property indicator_plots               1
//---------------------------------------------------------------------
#property indicator_type1               DRAW_HISTOGRAM
#property indicator_color1              Black
#property indicator_width1              2
//---------------------------------------------------------------------

Aşağıdaki parametreler ayarlanır:

  • #property Indicator_separate_window, MetaTrader 5 terminaline gösterge grafiğini ayrı bir pencerede görüntülemesini söyler.
  • #property indicator_applied_price PRICE_CLOSE - varsayılan olarak kullanılan fiyatların türü.
  • #property indicator_minimum -1.4 - gösterge penceresinde görüntülenen dikey eksenin minimum değeri.
  • #property indicator_maksimum +1.4 - gösterge penceresinde görüntülenen dikey eksenin maksimum değeri.

Son iki parametre, gösterge grafiğini görüntülemek için sabit bir ölçek ayarlamanıza izin verir. Bu mümkündür çünkü göstergemizin minimum ve maksimum değerlerini biliyoruz: -1'den +1'e kadar dahildir. Bu, grafiğin güzel görünmesi, pencere kenarlıkları ve penceredeki gösterge başlığının üst üste gelmemesi için yapılır.

  • #property indicator_buffers 1 - gösterge hesaplaması için tampon sayısı. Tek bir tampon kullanırız.
  • #property Indicator_plots 1 - göstergedeki grafik serilerin sayısı. Ekranda sadece bir grafik gösteriyoruz.
  • #property indicator_type1     DRAW_HISTOGRAM - gösterge grafiğini histogram olarak görüntüleyin.
  • #property indicator_color1     Black - gösterge grafiğinin varsayılan rengi.
  • #property indicator_width1 2 - gösterge grafiğinin çizgi genişliği, bu durumda histogram sütunlarının genişliğidir.

Ardından, göstergenin grafiğe yerleştirilmesi sırasında ve daha sonra çalışırken değiştirilebilen göstergenin dış parametrelerini girme kısmı gelir:

input int   MAPeriod = 200;

Sadece bir parametre vardır - hareketli ortalama sürenin değeri.

Göstergenin bir sonraki önemli kısmı - gösterge, grafik üzerinde çalıştığında meydana gelen çeşitli olayları işleyen fonksiyonlar.

Önce başlatma fonksiyonu gelir - OnInit(). Göstergeyi yükledikten hemen sonra çağrılır. Göstergemizde şöyle görünür:

void OnInit()
{
  SetIndexBuffer( 0, TrendBuffer, INDICATOR_DATA );
  PlotIndexSetInteger( 0, PLOT_DRAW_BEGIN, MAPeriod );
}

SetIndexBuffer() fonksiyonu, TrendBuffer[] trendinin değerlerini depolayacağımız, önceden bildirilen diziyi gösterge tamponlarından biriyle bağlar. Yalnızca bir gösterge tamponumuz var ve indisi sıfıra eşit.

PlotIndexSetInteger() fonksiyonu, başlangıç çubuklarının sayısını, bunları gösterge penceresinde çizmeden ayarlar.

Kendi döneminden küçük çubuk sayısı üzerinden basit bir hareketli ortalamayı hesaplamak matematiksel olarak imkansız olduğundan, hareketli ortalama dönemine eşit çubuk sayısını belirleyelim.

Ardından, bir göstergeyi yeniden hesaplama ihtiyacıyla ilgili olayları işleyen fonksiyon gelir - OnCalculate():

int OnCalculate(const int _rates_total, 
                const int _prev_calculated,
                const int _begin, 
                const double& _price[ ] )
{
  int  start, i;

//   If number of bars on the screen is less than averaging period, calculations can't be made:
  if( _rates_total < MAPeriod )
  {
    return( 0 );
  }

//  Determine the initial bar for indicator buffer calculation:
  if( _prev_calculated == 0 )
  {
    start = MAPeriod;
  }
  else
  {
    start = _prev_calculated - 1;
  }

//      Loop of calculating the indicator buffer values:
  for( i = start; i < _rates_total; i++ )
  {
    TrendBuffer[ i ] = TrendDetector( i, _price );
  }

  return( _rates_total );
}

Bu fonksiyon, göstergenin başlatılmasından sonra ilk kez ve daha sonra fiyat verileri her değiştiğinde çağrılır. Örneğin, göstergenin hesaplandığı sembolde yeni bir tik geldiğinde. Ayrıntılı olarak düşünelim.

İlk olarak, bir grafikte yeterli sayıda çubuk olup olmadığını kontrol edin - hareketli ortalama periyodundan küçükse hesaplanacak bir şey yoktur ve bu fonksiyon dönüş operatörü ile sona erer. Çubuk sayısı hesaplamalar için yeterliyse göstergenin hesaplanacağı ilk çubuğu belirleyin. Bu, her fiyat tikinde tüm gösterge değerlerini yeniden hesaplamamak için yapılır.

Burada terminal tarafından sağlanan mekanizmayı kullanıyoruz. Bir işleyici fonksiyonunu her çağırdığınızda, _prev_calculated fonksiyonu argümanının değeri kontrol edilir - bu, OnCalculate() fonksiyonunun önceki çağrısında işlenen çubuk sayısıdır. Sıfır ise tüm gösterge değerlerini yeniden hesaplayın. Aksi takdirde, yalnızca _prev_calculated - 1 indisi ile son çubuğu yeniden hesaplayın.

Gösterge tamponu değerlerini hesaplama döngüsü for operatörü tarafından gerçekleştirilir - onun gövdesinde, yeniden hesaplanan gösterge tamponunun her değeri için trend algılama TrendDetector fonksiyonunu çağırırız. Böylece, yalnızca bu fonksiyonu geçersiz kılarak, trend yönünü hesaplamak için farklı algoritmalar uygulayabiliriz. Bu durumda, gösterge parçalarının geri kalanı aslında değişmeden kalır (muhtemelen, dış parametreler değişecektir).

Şimdi trend algılamanın kendi fonksiyonunu düşünelim - TrendDetector.

int TrendDetector(int _shift, const double& _price[])
{
  double  current_ma;
  int     trend_direction = 0;

  current_ma = SimpleMA(_shift, MAPeriod, _price);

  if(_price[_shift] > current_ma)
  {
    trend_direction = 1;
  }
  else if(_price[_shift] < current_ma)
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

Fonksiyon aşağıdaki görevleri gerçekleştirir:

  • _shift argümanı tarafından ayarlanan çubuktan başlayarak basit hareketli ortalamayı hesaplar. SimpleMA kitaplık fonksiyonunu kullanır.
  • Bu çubuktaki fiyat değerlerini hareketli ortalama değeri ile karşılaştırır.
  • Fiyat değeri hareketli ortalama değerinden büyükse 1, fiyat değeri hareketli ortalama değerinden küçükse -1, aksi takdirde sıfır verir.

Fonksiyon sıfır verirse bu, trendin algılanamadığı anlamına gelir.

Gösterge çalışmasının sonucu Şekil 2 ve Şekil 3'te görülebilir.

3.2. Hareketli Ortalamaların "Yelpazesi"ne Dayalı Trend Göstergesi

Şimdi, bu göstergeye dayanarak, bir trendi algılamak için hareketli ortalamaların "yelpazesini" kullanan biraz daha karmaşık bir göstergeyi nasıl oluşturabileceğinizi görelim.

Göstergenin tam kaynak kodu, makaleye eklenmiş FanTrendDetector.MQ5 dosyasındadır.

Bu göstergenin öncekinden farklılıkları şunlardır:

  • Üç hareketli ortalamanın dönemleri dış parametrelerde ayarlanır:
input int MA1Period = 200; // period value of senior moving average
input int MA2Period = 50;  // period value of medium moving average
input int MA3Period = 21;  // period value of junior moving average
  • Başka bir TrendDetector fonksiyonu:
int TrendDetector(int _shift, const double& _price[])
{
  double  current_ma1, current_ma2, current_ma3;
  int     trend_direction = 0;

  current_ma1 = SimpleMA(_shift, MA1Period, _price);
  current_ma2 = SimpleMA(_shift, MA2Period, _price);
  current_ma3 = SimpleMA(_shift, MA3Period, _price);

  if(current_ma3 > current_ma2 && current_ma2 > current_ma1)
  {
    trend_direction = 1;
  }
  else if(current_ma3 < current_ma2 && current_ma2 < current_ma1)
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

Fonksiyon, if...else operatörlerini ve sıralarını kullanarak bunları birbirleriyle karşılaştırıp hareketli ortalamaların doğru sırada yer alıp almadığını kontrol eder. Ortalamalar artan sırada düzenlenirse 1 - yükseliş trendini verir. Ortalamalar azalan sırada düzenlenirse, -1 - düşüş trendini verir. if bloğunda kontrol edilen her iki koşul da yanlışsa sıfır verir (trend algılanamaz). Fonksiyonun iki girdi argümanı vardır - analiz edilen çubuğun tamponundaki kayma ve bir fiyat serisiyle tamponun kendisi.

Gösterge parçalarının geri kalanı öncekiyle aynıdır.

3.3. ZigZag Göstergesine Dayalı Trend Göstergesi

Şimdi Charles Dow'a göre uç noktayı belirlemek ve trend yönünü saptamak için Zigzag parçalarını kullanan göstergeyi ele alalım. Göstergenin tam kaynak kodu, makaleye eklenmiş ZigZagTrendDetector.MQ5 dosyasındadır.

Dış değişkenler, dış gösterge ZigZag'ın parametre değerleriyle atanır:

//---------------------------------------------------------------------
//  External parameters:
//---------------------------------------------------------------------
input int   ExtDepth = 5;
input int   ExtDeviation = 5;
input int   ExtBackstep = 3;
//---------------------------------------------------------------------

Bu göstergenin önemli bir farkı, gösterge tamponlarının sayısıdır. Burada görüntüleme tamponunun yanı sıra iki hesaplama tamponu daha kullanıyoruz. Bu nedenle, gösterge kodundaki uygun ayarı değiştirdik:

#property indicator_buffers  3

İki ek tampon ekleyin. Dış gösterge ZigZag'dan elde edilen uç noktayı depolayacaklar:

double ZigZagHighs[];  // zigzag's upper turnarounds
double ZigZagLows[];   // zigzag's lower turnarounds

Gösterge başlatma olay işleyicisinde de değişiklik yapılması gerekir - bu iki ek tamponu hesaplama tamponları olarak ayarlayın:

//  Buffers to store zigzag's turnarounds
SetIndexBuffer(1, ZigZagHighs, INDICATOR_CALCULATIONS);
SetIndexBuffer(2, ZigZagLows, INDICATOR_CALCULATIONS);

OnCalculate fonksiyonunun hesaplama kodunda ayrıca tamponlarımıza okuma zigzag parçaları sağlamalıyız. Bu, şu şekilde yapılır:

//  Copy upper and lower zigzag's turnarounds to buffers:
  CopyBuffer(indicator_handle, 1, 0, _rates_total - _prev_calculated, ZigZagHighs);
  CopyBuffer(indicator_handle, 2, 0, _rates_total - _prev_calculated, ZigZagLows);

//  Loop of calculating the indicator buffer values:
  for(i = start; i < _rates_total; i++)
  {
    TrendBuffer[i] = TrendDetector(i);
  }

TrendDetector fonksiyonu şöyle görünür:

//---------------------------------------------------------------------
//  Determine the current trend direction:
//---------------------------------------------------------------------
//  Returns:
//    -1 - Down trend
//    +1 - Up trend
//     0 - trend is not defined
//---------------------------------------------------------------------
double    ZigZagExtHigh[2];
double    ZigZagExtLow[2];
//---------------------------------------------------------------------
int TrendDetector(int _shift)
{
  int    trend_direction = 0;

//  Find last four zigzag's turnarounds:
  int    ext_high_count = 0;
  int    ext_low_count = 0;
  for(int i = _shift; i >= 0; i--)
  {
    if(ZigZagHighs[i] > 0.1)
    {
      if(ext_high_count < 2)
      {
        ZigZagExtHigh[ext_high_count] = ZigZagHighs[i];
        ext_high_count++;
      }
    }
    else if(ZigZagLows[i] > 0.1)
    {
      if(ext_low_count < 2)
      {
        ZigZagExtLow[ext_low_count] = ZigZagLows[i];
        ext_low_count++;
      }
    }

//  If two pairs of extrema are found, break the loop:
    if(ext_low_count == 2 && ext_high_count == 2)
    {
      break;
    }
  }

//  If required number of extrema is not found, the trend can't be determined:
  if(ext_low_count != 2 || ext_high_count != 2)
  {
    return(trend_direction);
  }

//  Check Dow's condition fulfillment:
  if(ZigZagExtHigh[0] > ZigZagExtHigh[1] && ZigZagExtLow[0] > ZigZagExtLow[1])
  {
    trend_direction = 1;
  }
  else if(ZigZagExtHigh[0] < ZigZagExtHigh[1] && ZigZagExtLow[0] < ZigZagExtLow[1])
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

Burada son dört zigzag uç noktasını ararız. Aramanın geçmişe gittiğine dikkat edin. Bu nedenle, for döngüsündeki indis, her arama yinelemesinde sıfıra düşer. Uç noktalar bulunursa Dow'a göre trend tanımının tutarlılığı için birbirleriyle karşılaştırılır. İki olası uç nokta konumu vardır - yükseliş trendi ve düşüş trendi için. Bu değişkenler if...else operatörleri tarafından kontrol edilir.

3.4. ADX Göstergesine Dayalı Trend Göstergesi

ADX göstergesini kullanan ADXTrendDetector trend göstergesini düşünün. Göstergenin tam kaynak kodu, makaleye eklenen ADXTrendDetector.MQ5 dosyasındadır. Dış parametreler, dış gösterge ADX değerleriyle atanır:

//---------------------------------------------------------------------
//      External parameters
//---------------------------------------------------------------------
input int  PeriodADX     = 14;
input int  ADXTrendLevel = 20;

TrendDetector fonksiyonu şöyle görünür:

//---------------------------------------------------------------------
//  Determine the current trend direction:
//---------------------------------------------------------------------
//  Returns:
//    -1 - Down trend
//    +1 - Up trend
//     0 - trend is not defined
//---------------------------------------------------------------------
int TrendDetector(int _shift)
{
  int     trend_direction = 0;
  double  ADXBuffer[ 1 ];
  double  PlusDIBuffer[ 1 ];
  double  MinusDIBuffer[ 1 ];

//  Copy ADX indicator values to buffers:
  CopyBuffer(indicator_handle, 0, _shift, 1, ADXBuffer);
  CopyBuffer(indicator_handle, 1, _shift, 1, PlusDIBuffer);
  CopyBuffer(indicator_handle, 2, _shift, 1, MinusDIBuffer);

//  If ADX value is considered (trend strength):
  if(ADXTrendLevel > 0)
  {
    if(ADXBuffer[0] < ADXTrendLevel)
    {
      return(trend_direction);
    }
  }

//  Check +DI and -DI positions relative to each other:
  if(PlusDIBuffer[0] > MinusDIBuffer[0])
  {
    trend_direction = 1;
  }
  else if(PlusDIBuffer[0] < MinusDIBuffer[0])
  {
    trend_direction = -1;
  }

  return( trend_direction );
}

CopyBuffer() fonksiyonunu kullanarak, _shift argümanı tarafından verilen çubuk sayısı için dış gösterge ADX'ten gösterge tamponlarının gerekli değerlerini alın. Ardından, +DI ve -DI çizgilerinin pozisyonlarını birbirine göre analiz edin. Gerekirse trend gücünü göz önünde bulundurun - tanımlanandan daha azsa trend algılanmaz.

3.5. NTRT Göstergesine Dayalı Trend Göstergesi

NRTR'ye dayalı NRTRTrendDetector trend göstergesinin yapısı bir öncekine benzer. Göstergenin tam kaynak kodu, makaleye eklenmiş NRTRTrendDetector.MQ5 dosyasındadır.

İlk fark - dış parametreler bloğunda:

//---------------------------------------------------------------------
//      External parameters:
//---------------------------------------------------------------------
input int     ATRPeriod =  40;    // ATR period, in bars
input double  Koeff     = 2.0;    // Coefficient of ATR value change   
//---------------------------------------------------------------------

İkinci fark - trend yönünü algılama TrendDetector fonksiyonunda:

//---------------------------------------------------------------------
//      Determine the current trend direction:
//---------------------------------------------------------------------
//  Returns:
//    -1 - Down trend
//    +1 - Up trend
//     0 - trend is not defined
//---------------------------------------------------------------------
int TrendDetector(int _shift)
{
  int     trend_direction = 0;
  double  Support[1];
  double  Resistance[1];

//      Copy NRTR indicator values to buffers::
  CopyBuffer(indicator_handle, 0, _shift, 1, Support);
  CopyBuffer(indicator_handle, 1, _shift, 1, Resistance);

//  Check values of indicator lines:
  if(Support[0] > 0.0 && Resistance[0] == 0.0)
  {
    trend_direction = 1;
  }
  else if(Resistance[0] > 0.0 && Support[0] == 0.0)
  {
    trend_direction = -1;
  }

  return( trend_direction );
}

Burada, 0 ve 1 indisli dış gösterge NRTR'nin iki tamponundan değerleri okuyoruz. Yükseliş trendi olduğunda Destek tamponundaki değerler sıfırdan farklıdır ve düşüş trendi olduğunda Direnç tamponundaki değerler sıfırdan farklıdır.

3.6. Heiken Ashi Mumlarına Dayalı Trend Göstergesi

Şimdi Heiken Ashi mumlarını kullanan trend göstergesini ele alalım.

Bu durumda dış göstergeyi aramayacağız, ancak mumları kendimiz hesaplayacağız. Bu, daha önemli görevler için gösterge performansını ve boş CPU'yu artıracaktır. Göstergenin tam kaynak kodu, makaleye eklenmiş HeikenAshiTrendDetector.MQ5 dosyasındadır.

Heiken Ashi göstergesi dış parametrelerin ayarını üstlenmediğinden, giriş operatörleri ile bloğu kaldırabiliriz. Gösterge yeniden hesaplama olayının işleyicisinde büyük değişiklikler bizi bekliyor. Burada, mevcut grafiğin tüm fiyat dizilerine erişim sağlayan alternatif bir işleyici çeşidi kullanacağız.

OnCalculate() fonksiyonu şimdi şöyle görünür:

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     start, i;
  double  open, close, ha_open, ha_close;

//  Determine the initial bar for indicator buffer calculation:
  if(_prev_calculated == 0)
  {
    open = Open[0];
    close = Close[0];
    start = 1;
  }
  else
  {
    start = _prev_calculated - 1;
  }

//  Loop of calculating the indicator buffer values:
  for(i = start; i < _rates_total; i++)
  {
//  Heiken Ashi candlestick open price:
    ha_open = (open + close) / 2.0;

//  Heiken Ashi candlestick close price:
    ha_close = (Open[i] + High[i] + Low[i] + Close[i]) / 4.0;

    TrendBuffer[i] = TrendDetector(ha_open, ha_close);

    open = ha_open;
    close = ha_close;
  }

  return(_rates_total);
}

Heiken Ashi mumlarının rengini belirlemek için sadece iki fiyata ihtiyacımız var - açılış ve kapanış; sonra sadece bunlar sayılacaktır. 

TrendDetector fonksiyon çağrısı aracılığıyla trend yönünü tespit ettikten sonra, Heiken Ashi mumlarının mevcut fiyat değerlerini açılış ve kapanış ara değişkenlerine kaydedin. TrendDetector fonksiyonu çok basit görünüyor. Bunu OnCalculate öğesine ekleyebilirsiniz ancak algoritmanın daha fazla geliştirilmesi ve karmaşıklığı durumunda daha fazla çok yönlülük için bu fonksiyonu bırakıyoruz. Fonksiyon şu şekildedir:

int TrendDetector(double _open, double _close)
{
  int    trend_direction = 0;

  if(_close > _open)         // if candlestick is growing, then it is the up trend
  {
    trend_direction = 1;
  }
  else if(_close < _open)     // if candlestick is falling, then it is the down trend
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

Fonksiyon argümanları, Heiken Ashi mum için iki fiyattır - bunun yönünü belirleyen açılış ve kapanış fiyatları.


4. Uzmanda Trend Algılama Göstergesini Kullanma Örneği

Farklı göstergeler kullanan bir Uzman Danışman oluşturalım. Trend algılamanın farklı yollarını kullanan uzmanların sonuçlarını karşılaştırmak ilginç olacaktır. Önce sonuçları varsayılan parametrelerle kontrol edin, ardından en iyilerini bulmak için bunları ayarlamaya çalışın.

Bu durumda, Uzman Danışmanlar oluşturmanın amacı - trend algılama yöntemlerini doğruluk ve hız ile karşılaştırmaktır. Bu nedenle, tüm Uzman Danışmanları oluşturmanın genel ilkelerini formüle edelim:

  • Trend aşağıdan yukarıya veya tanımsızdan yukarıya değiştiğinde alış pozisyonu açılır.
  • Trend yukarıdan aşağıya veya tanımsızdan aşağı doğru değiştiğinde satış pozisyonu açılır.
  • Trend yönünü tersine veya tanımsız olarak değiştirdiğinde pozisyon kapanır.
  • Yeni çubuk açıldığında (karşılık gelen bir sinyal olduğunda) Uzman Danışman bir pozisyonu açmalı/kapatmalıdır.

Oluşturduğumuz tüm trend göstergeleri, trend yönü hakkında gerekli verileri saklayan sıfır indisli gösterge tamponu içerir. Pozisyon açma/kapama sinyali almak için bunu Uzman Danışmanlarda kullanacağız.

Alım satım fonksiyonlarına ihtiyacımız olduğu için MetaTrader 5 ile birlikte kurulan ilgili kitaplığı ekledik. Bu kitaplık, CTrade sınıfını ve pozisyonlar ve emirlerle çalışmanın çeşitli yöntemlerini içerir. Bu, alım satım fonksiyonlarıyla rutin çalışmayı basitleştirir. Kitaplık aşağıdaki satıra dahil edilmiştir:

#include <Trade\Trade.mqh>

Buradan iki yöntem kullanacağız: pozisyon açma ve kapama. İlk yöntem, belirli bir yön ve hacimde bir pozisyon açmanıza izin verir:

PositionOpen(const string symbol, 
             ENUM_ORDER_TYPE order_type,
             double volume, double price,
             double sl, double tp, const string comment )

Girdi argümanları aşağıdaki gibidir:

  • symbol - alım satım enstrümanının adı, örneğin "EURUSD".
  • order_type - pozisyon açma yönü, kısa veya uzun.
  • volume - lotlarda açılan pozisyonun hacmi, örneğin, 0,10.
  • price - açılış fiyatı.
  • sl - Zararı Durdur fiyatı.
  • tp - Kâr Al fiyatı.
  • comment - işlem terminalinde pozisyon görüntülendiğinde gösterilen yorum.

İkinci yöntem, bir pozisyonu kapatmanızı sağlar:

PositionClose( const string symbol, ulong deviation )

Girdi argümanları aşağıdaki gibidir:

  •  symbol - alım satım enstrümanının adı, örneğin "EURUSD".
  •  deviation - bir pozisyonu kapatırken mevcut fiyattan (puan olarak) izin verilen maksimum sapma.

MATrendDetector göstergesini kullanan Uzman Danışmanın yapısını ayrıntılı olarak ele alalım. Uzman Danışmanın tam kaynak kodu, makalenin ekindeki MATrendExpert.MQ5 dosyasındadır. Uzmanın ilk ana bloğu - dış parametrelerin ayarlanma bloğudur.

input double Lots = 0.1;
input int    MAPeriod = 200;

Uzman Danışmanın Lots parametresi - pozisyon açıldığında kullanılan lotun büyüklüğüdür. Farklı trend algılama yöntemlerinin karşılaştırmalı sonuçlarını elde etmek için para yönetimi olmadan kalıcı lotu kullanıyoruz. Diğer tüm dış parametreler, yukarıda tartışılan trend göstergeleri tarafından kullanılır. Liste ve amaç, ilgili gösterge ile tamamen aynıdır.

Uzman Danışmanın ikinci önemli bloğu - Uzman Danışman başlatma olay işleyicisidir.

//---------------------------------------------------------------------
//      Initialization event handler:
//---------------------------------------------------------------------
int OnInit()
{
//  Create external indicator handle for future reference to it:
  ResetLastError();
  indicator_handle = iCustom(Symbol(), PERIOD_CURRENT, "Examples\\MATrendDetector", MAPeriod);

// If initialization was unsuccessful, return nonzero code:
  if(indicator_handle == INVALID_HANDLE)
  {
    Print("MATrendDetector initialization error, Code = ", GetLastError());
    return(-1);
  }
  return(0);
}

Burada trend göstergesine başvurmak için tanıtıcı değer oluşturun ve oluşturma başarılıysa sıfır kodunu döndürün. Gösterge tanıtıcı değeri oluşturulamadıysa (örneğin, gösterge EX5 biçiminde derlenmemiştir), bununla ilgili mesajı yazdırır ve sıfır olmayan kodu döndürürüz. Bu durumda Uzman Danışman diğer çalışmalarını durdurur ve Günlükteki ilgili mesajla birlikte terminalden boşaltılır.

Uzman Danışmanın bir sonraki bloğu - Uzman Danışman sonlandırması olay işleyicisi.

//---------------------------------------------------------------------
//      Indicator deinitialization event handler:
//---------------------------------------------------------------------
void OnDeinit(const int _reason)
{
//  Delete indicator handle:
  if(indicator_handle != INVALID_HANDLE)
  {
    IndicatorRelease(indicator_handle);
  }
}

Burada gösterge tanıtıcı değeri silinir ve ayrılan belleği serbest bırakılır.

Uzman Danışmanı sonlandırmak için başka bir işlem yapmanız gerekmez.

Ardından, mevcut sembole göre yeni tik ile ilgili olayın işleyicisi olan Uzman Danışmanın ana bloğuna geçilir.

//---------------------------------------------------------------------
//  Handler of event about new tick by the current symbol:
//---------------------------------------------------------------------
int    current_signal = 0;
int    prev_signal = 0;
bool   is_first_signal = true;
//---------------------------------------------------------------------
void OnTick()
{
//  Wait for beginning of a new bar:
  if(CheckNewBar() != 1)
  {
    return;
  }

//  Get signal to open/close position:
  current_signal = GetSignal();
  if(is_first_signal == true)
  {
    prev_signal = current_signal;
    is_first_signal = false;
  }

//  Select position by current symbol:
  if(PositionSelect(Symbol()) == true)
  {
//  Check if we need to close a reverse position:
    if(CheckPositionClose(current_signal) == 1)
    {
      return;
    }
  }

//  Check if there is the BUY signal:
  if(CheckBuySignal(current_signal, prev_signal) == 1)
  {
    CTrade  trade;
    trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, Lots, SymbolInfoDouble(Symbol(), SYMBOL_ASK ), 0, 0);
  }

//  Check if there is the SELL signal:
  if(CheckSellSignal(current_signal, prev_signal) == 1)
  {
    CTrade  trade;
    trade.PositionOpen(Symbol(), ORDER_TYPE_SELL, Lots, SymbolInfoDouble(Symbol(), SYMBOL_BID ), 0, 0);
  }

//  Save current signal:
  prev_signal = current_signal;
}

Uzman Danışman tarafından kullanılan yardımcı fonksiyonları ele alalım.

Her şeyden önce Uzman Danışmanımız, grafikte yeni bir çubuk daha açmak için sinyali kontrol etmelidir. Bunun için CheckNewBar fonksiyonu kullanılır:

//---------------------------------------------------------------------
//  Returns flag of a new bar:
//---------------------------------------------------------------------
//  - if it returns 1, there is a new bar
//---------------------------------------------------------------------
int CheckNewBar()
{
  MqlRates  current_rates[1];

  ResetLastError();
  if(CopyRates(Symbol(), Period(), 0, 1, current_rates)!= 1)
  {
    Print("CopyRates copy error, Code = ", GetLastError());
    return(0);
  }

  if(current_rates[0].tick_volume>1)
  {
    return(0);
  }

  return(1);
}

Yeni bir çubuğun varlığı, tik hacminin değeri ile belirlenir. Yeni bir çubuk açarken, hacmi başlangıçta sıfıra eşittir (tırnak işaretleri olmadığı için). Yeni tik gelmesiyle boyut 1'e eşit olur.

Bu fonksiyonda, bir elemandan oluşan MqlRates yapılarının current_rates[] dizisini oluşturacağız, güncel fiyatları ve hacim bilgilerini buna kopyalayacağız ve ardından tik hacminin değerini kontrol edeceğiz. 

Mevcut sembolle yeni tik hakkında olay işleyicimizde bu fonksiyonu aşağıdaki şekilde kullanacağız:

//  Wait for beginning of a new bar:
if(CheckNewBar()!= 1)
{
  return;
}

Böylece yeni bir çubuk açılır ve mevcut trend yönü hakkında bir sinyal alabilirsiniz. Bu, şu şekilde yapılır:

//  Get signal to open/close position:
  current_signal = GetSignal();
  if(is_first_signal == true)
  {
    prev_signal = current_signal;
    is_first_signal = false;
  }

Trenddeki değişiklikleri takip etmemiz gerektiğinden, bir önceki çubuktaki trendin değerini hatırlamamız gerekiyor. Yukarıdaki kod parçasında bunun için prev_signal değişkenini kullanıyoruz. Ayrıca, bunun ilk sinyal olduğunu belirten bayrağı kullanmalısınız (henüz bir önceki sinyal yoktur). Bu, is_first_signal değişkenidir. Bayrak true değerine sahipse, prev_signal değişkenini başlangıç değeriyle başlatırız.

Burada, göstergemizden elde edilen mevcut trend yönünü döndüren GetSignal fonksiyonunu kullanıyoruz. Şöyle görünür:  

//---------------------------------------------------------------------
//      Get signal to open/close position:
//---------------------------------------------------------------------
int GetSignal()
{
  double    trend_direction[1];

//  Get signal from trend indicator:
  ResetLastError();
  if(CopyBuffer(indicator_handle, 0, 0, 1, trend_direction) != 1)
  {
    Print("CopyBuffer copy error, Code = ", GetLastError());
    return(0);
  }

  return((int)trend_direction[0]);
}

Trend göstergesinin verileri sıfır tamponundan, bir elemandan oluşan trend_direction dizimize kopyalanır. Dizi elemanının değeri, fonksiyondan döndürülür. Ayrıca derleyici uyarısını önlemek için double türü, int türüne dönüştürülür.

Yeni pozisyon açmadan önce, daha önce açılmış olan karşı pozisyonu kapatmanın gerekli olup olmadığını kontrol etmelisiniz. Aynı yönde halihazırda açılmış bir pozisyon olup olmadığını da kontrol etmelisiniz. Bütün bunlar aşağıdaki kod parçası ile yapılır:

//  Select position by current symbol:
  if(PositionSelect(Symbol()) == true)
  {
//  Check if we need to close a reverse position:
    if(CheckPositionClose(current_signal) == 1)
    {
      return;
    }
  }

Pozisyona erişmek için önce seçilmesi gerekir - bu, mevcut sembol için PositionSelect() fonksiyonu kullanılarak yapılır. Fonksiyon true değerini verirse pozisyon mevcuttur ve başarıyla seçilmiştir, böylece onu değiştirebilirsiniz.

Karşı pozisyonu kapatmak için CheckPositionClose fonksiyonu kullanılır:

//---------------------------------------------------------------------
//  Check if we need to close position:
//---------------------------------------------------------------------
//  Returns:
//    0 - no open position
//    1 - position already opened in signal's direction
//---------------------------------------------------------------------
int CheckPositionClose(int _signal)
{
  long    position_type = PositionGetInteger(POSITION_TYPE);

  if(_signal == 1)
  {
//  If there is the BUY position already opened, then return:
    if(position_type == (long)POSITION_TYPE_BUY)
    {
      return(1);
    }
  }

  if(_signal==-1)
  {
//  If there is the SELL position already opened, then return:
    if( position_type == ( long )POSITION_TYPE_SELL )
    {
      return(1);
    }
  }

//  Close position:
  CTrade  trade;
  trade.PositionClose(Symbol(), 10);

  return(0);
}

İlk olarak, pozisyonun trend yönünde açık olup olmadığını kontrol edin. Açıksa fonksiyon 1 değerini döndürür ve mevcut pozisyon kapatılmaz. Pozisyon ters trend yönünde açıksa, kapatmalısınız. Bu, yukarıda açıklanan PositionClose yöntemiyle yapılır. Açık pozisyon artık olmadığı için sıfır değerini verir.

Mevcut pozisyonlar için gerekli tüm kontroller ve işlemler yapıldıktan sonra, yeni bir sinyalin varlığını kontrol etmeniz gerekir. Bu, aşağıdaki kod parçası ile yapılır:

//  Check if there is the BUY signal:
if(CheckBuySignal(current_signal, prev_signal)==1)
{
  CTrade  trade;
  trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, Lots, SymbolInfoDouble(Symbol(), SYMBOL_ASK), 0, 0);
}

Al sinyali varsa, SYMBOL_ASK mevcut fiyatına göre verilen hacimde uzun pozisyon açın. Tüm pozisyonlar ters sinyal ile kapatıldığından, Kâr Al ve Zararı Durdur kullanılmaz. Uzman Danışman "her zaman piyasada"dır. 

Gerçek ticarette, DC sunucusuyla bağlantının kesilmesi ve diğer mücbir sebep koşulları gibi öngörülemeyen durumlarda koruyucu bir Zararı Durdurma kullanılması tavsiye edilir.

Sat sinyalleri için her şey benzer şekildedir:

//  Check if there is the SELL signal:
if(CheckSellSignal(current_signal, prev_signal) == 1)
{
  CTrade  trade;
  trade.PositionOpen(Symbol(), ORDER_TYPE_SELL, Lots, SymbolInfoDouble(Symbol(), SYMBOL_BID), 0, 0);
}

Tek fark satış fiyatındadır - SYMBOL_BID.

Bir sinyalin varlığı CheckBuySignal fonksiyonuyla - satın almak için ve CheckSellSignal fonksiyonuyla - kontrol edilir. Bu fonksiyonlar çok basit ve açıktır:

//---------------------------------------------------------------------
//  Check if signal has changed to BUY:
//---------------------------------------------------------------------
//  Returns:
//    0 - no signal
//    1 - there is the BUY signal
//---------------------------------------------------------------------
int CheckBuySignal(int _curr_signal, int _prev_signal)
{
//  Check if signal has changed to BUY:
  if((_curr_signal==1 && _prev_signal==0) || (_curr_signal==1 && _prev_signal==-1))
  {
    return(1);
  }

  return(0);
}

//---------------------------------------------------------------------
//  Check if there is the SELL signal:
//---------------------------------------------------------------------
//  Returns:
//    0 - no signal
//    1 - there is the SELL signal
//---------------------------------------------------------------------
int CheckSellSignal(int _curr_signal, int _prev_signal)
{
//  Check if signal has changed to SELL:
  if((_curr_signal==-1 && _prev_signal==0) || (_curr_signal==-1 && _prev_signal==1))
  {
    return(1);
  }

  return(0);
}

Burada trendin ters yöne değişip değişmediğini veya trend yönünün ortaya çıkıp çıkmadığını kontrol ederiz. Bu koşullardan herhangi biri karşılanırsa fonksiyon, sinyal varlığını döndürür.

Genel olarak, bu tür bir Uzman Danışman şeması, daha karmaşık algoritmalara uyacak şekilde kolayca yükseltilebilen ve genişletilebilen oldukça evrensel bir yapı sağlar.

Diğer Uzman Danışmanlar tamamen aynı şekilde oluşturulur. Yalnızca dış parametreler bloğunda önemli farklılıklar vardır - bunlar kullanılan trend göstergesine karşılık gelmeli ve gösterge tanıtıcı değeri oluşturulurken argüman olarak iletilmelidir.

Geçmiş verileriyle ilgili ilk Uzman Danışmanımızın sonuçlarını ele alalım. Günlük çubuklarda 01.04.2004 ile 06.08.2010 aralığındaki EURUSD geçmişini kullanacağız. Uzman Danışmanı Strateji Sınama Aracında varsayılan parametrelerle çalıştırdıktan sonra aşağıdaki sonuçları alıyoruz:

Şekil 8. MATrendDetector Göstergesini Kullanan Uzman Danışman Test Sonuçları

Şekil 8. MATrendDetector Göstergesini Kullanan Uzman Danışman Test Sonuçları

Strateji Test Cihazı Raporu
MetaQuotes-Demo (Yapı 302)

Ayarlar
Uzman: MATrendExpert
Sembol: EURUSD
Dönem: Günlük (2004.04.01 - 2010.08.06)
Girdiler: Lot=0,100000

MAPeriod=200
Aracı: MetaQuotes Software Corp.
Para birimi: USD
İlk Para Yatırma: 10.000,00

Sonuçlar
Çubuklar: 1649 Tikler: 8462551
Toplam Net Kâr: 3.624,59 Brüt Kâr: 7.029,16 Brüt Zarar: -3.404,57
Kâr Faktörü: 2,06 Beklenen Geri Ödeme: 92,94
Kurtarma faktörü: 1,21 Sharpe Oranı: 0,14

Bakiye Düşüşü:
Mutlak Bakiye Düşüşü: 2.822,83 Maksimum Bakiye Düşüşü: 2.822,83 (%28,23) Bağıl Bakiye Düşüşü: %28,23 (2.822,83)
Hisse Senedi Düşüşü:
Mutlak Hisse Senedi Düşüşü: 2.903,68 Maksimum Hisse Senedi Düşüşü: 2.989,93 (%29,64) Bağıl Hisse Senedi Düşüşü: %29,64 (2.989,93)

Toplam Alım Satım: 39 Kısa Alım Satımlar (kazanılan %): 20 (%20,00) Uzun Alım Satımlar (kazanılan %): 19 (%15,79)
Toplam İşlemler: 78 Kâr Eden Alım Satımlar (toplamın %’si): 7 (%17,95) Zarar Eden Alım Satımlar (toplamın %’si) 32 (%82,05)

En büyük kâr eden alım satım: 3.184,14 En büyük zarar eden alım satım (toplamın yüzdesi): -226,65

Ortalama kâr eden alım satım: 1.004,17 Ortalama zarar eden alım satım (toplamın yüzdesi): -106,39

Maksimum ardışık kazançlar ($): 4 (5.892,18) Maksimum ardışık zararlar ($): 27 (-2.822,83)

Maksimum ardışık kâr (sayı): 5.892,18 (4) Maksimum ardışık zarar (sayı): -2.822,83 (27)

Ortalama ardışık kazançlar: 2 Maksimum ardışık zararlar: 8


Testin başlangıcından 22.09.2004'e kadar olan bölüm dışında genel olarak iyi görünüyor. Bu bölümün gelecekte tekrarlanmayacağının garantisi yoktur. Bu dönemin grafiğine bakarsanız, sınırlı aralıkta baskın yanal hareket olduğunu görebilirsiniz. Bu koşullar altında basit trend uzmanımız pek iyi değildi. İşte sözleşmelerin yapıldığı bu dönemin resmi:

Şekil 9. Yanal Hareketli Bölüm

Şekil 9. Yanal Hareketli Bölüm

Ayrıca grafikte SMA200 hareketli ortalama da var.

Şimdi, aynı aralıkta ve varsayılan parametrelerle birkaç hareketli ortalamaya sahip gösterge kullanarak daha "gelişmiş" Uzman Danışmanı neyin göstereceğini görelim:

Şekil 10. FanTrendDetector Göstergesini Kullanan Uzman Danışman Test Sonuçları

Şekil 10. FanTrendDetector Göstergesini Kullanan Uzman Danışman Test Sonuçları

Strateji Test Cihazı Raporu
MetaQuotes-Demo (Yapı 302)

Ayarlar
Uzman: FanTrendExpert
Sembol: EURUSD
Dönem: Günlük (2004.04.01 - 2010.08.06)
Girdiler: Lot=0,100000

MA1Period=200

MA2Period=50

MA3Period=21
Aracı: MetaQuotes Software Corp.
Para birimi: USD
İlk Para Yatırma: 10.000,00

Sonuçlar
Çubuklar: 1649 Tikler: 8462551
Toplam Net Kâr: 2.839,63 Brüt Kâr: 5.242,93 Brüt Zarar: -2.403,30
Kâr Faktörü: 2,18 Beklenen Geri Ödeme: 149,45
Kurtarma faktörü: 1,06 Sharpe Oranı: 0,32

Bakiye Düşüşü:
Mutlak Bakiye Düşüşü: 105,20 Maksimum Bakiye Düşüşü: 1.473,65 (%11,73) Bağıl Bakiye Düşüşü: %11,73 (1.473,65)
Hisse Senedi Düşüşü:
Mutlak Hisse Senedi Düşüşü: 207,05 Maksimum Hisse Senedi Düşüşü: 2.671,98 (%19,78) Bağıl Hisse Senedi Düşüşü: %19,78 (2.671,98)

Toplam Alım Satım: 19 Kısa Alım Satımlar (kazanılan %): 8 (%50,00) Uzun Alım Satımlar (kazanılan %): 11 (%63,64)
Toplam İşlemler: 38 Kâr Eden Alım Satımlar (toplamın %’si): 11 (%57,89) Zarar Eden Alım Satımlar (toplamın %’si) 8 (%42,11)

En büyük kâr eden alım satım: 1.128,30 En büyük zarar eden alım satım (toplamın yüzdesi): -830,20

Ortalama kâr eden alım satım: 476,63 Ortalama zarar eden alım satım (toplamın yüzdesi): -300,41

Maksimum ardışık kazançlar ($): 2 (1.747,78) Maksimum ardışık zararlar ($): 2 (-105,20)

Maksimum ardışık kâr (sayı): 1.747,78 (2) Maksimum ardışık zarar (sayı): -830,20 (1)

Ortalama ardışık kazançlar: 2 Maksimum ardışık zararlar: 1

Çok daha iyi oldu! Bir önceki uzmanın daha önce vazgeçtiği "sorun" bölümümüze bakarsanız, resim şu şekilde olacaktır:

Şekil 11. Yanal Hareketli Bölümde FanTrendExpert Sonuçları

Şekil 11. Yanal Hareketli Bölümde FanTrendExpert Sonuçları

Şekil 9 ile karşılaştırın - trend değişikliğine ilişkin yanlış alarmların sayısının azaldığı açıktır. Ancak sözleşme sayısı yarı yarıya azaldı, ki bu oldukça mantıklı. Her iki Uzman Danışmanın bakiye/hisse senedi eğrisini analiz ederken, maksimum kâr elde etme açısından birçok sözleşmenin optimumdan daha az seviyede kapatıldığını görebilirsiniz. Bu nedenle, Uzman Danışmanın bir sonraki yükseltmesi, sözleşme kapanış algoritmasının iyileştirilmesidir. Ancak bu konu, bu makalenin kapsamı dışındadır. Okurlar bunu kendi başlarına yapabilirler.


5. Uzman Danışmanların Test Sonuçları

Tüm uzmanlarımızı test edelim. EURUSD çifti ve D1 zaman dilimi üzerinde 1993'ten 2010'a kadar mevcut tüm geçmiş aralığına ilişkin sonuçlar aşağıda sunulmuştur.

Şekil 12. MATrendExpert Testi

Şekil 12. MATrendExpert Testi

Şekil 13. FanTrendExpert Testi

Şekil 13. FanTrendExpert Testi

Şekil 14. ADXTrendExpert Testi (ADXTrendLevel = 0)

Şekil 14. ADXTrendExpert Testi (ADXTrendLevel = 0)

Şekil 15. ADXTrendExpert Testi (ADXTrendLevel = 20)

Şekil 15. ADXTrendExpert Testi (ADXTrendLevel = 20)

Şekil 16. NRTRTrendExpert Testi

Şekil 16. NRTRTrendExpert Testi

Şekil 17. Heiken Ashi Testi

Şekil 17. Heiken Ashi Testi

Test sonuçlarını ele alalım.

Liderler açısından en yaygın iki Uzman Danışman vardır - bir hareketli ortalama ve hareketli ortalamaların "yelpazesi". Aslında bu uzmanlar, yalnızca son dönem için düzleştirilmiş bir dizi fiyat kullanarak trendi (ve dolayısıyla fiyatı) takip etme kuralına en yakın olanlardır. 200 dönemi ile oldukça "ağır" hareketli ortalama kullandığımız için piyasa volatilitesinin etkisi azalıyor gibi görünüyor.

Bu Uzman Danışmanda düşük sayıda sözleşme bir dezavantaj değildir çünkü pozisyon tutma süresi 200 günlük trendin ardından birkaç aya kadar uzayabilir. İlginç bir şekilde, MATrendExpert, bakiyenin büyüdüğü, düz (uzman bağlamında) olduğu, paranın kaybedildiği trend alanlarını değiştirir.

ADX göstergesindeki algılama yöntemi de iyi sonuçlar verdi. Orada PeriodADX, geçmiş boyunca daha tekdüze sonuçlar veren 17 değerine biraz değiştirildi. Trend gücüne göre filtre etkisi önemli değildir. ADXTrendLevel parametresini ayarlamanız veya hatta mevcut piyasa volatilitesine bağlı olarak dinamik olarak ayarlamanız gerekebilir. Birkaç düşüş dönemi vardır ve bu nedenle bakiye eğrisini eşitlemek için ek önlemler gereklidir.

NRTR göstergesi, hem tüm test aralığında hem de rastgele seçilen uzun aralıkta varsayılan ayarları kullanarak pratikte sıfır kârlılık gösterdi. Bu, bir dereceye kadar bu trend algılama yönteminin kararlılığının bir işaretidir. Belki de parametreleri ayarlamak bu Uzman Danışmanı kârlı hale getirecektir, yani optimizasyon gereklidir.

Heiken Ashi tabanlı Uzman Danışman açıkçası kârlı değildi. Geçmişte güzel görünse de muhtemelen gerçek zamanlı olarak yeniden çizim nedeniyle test sonuçları ideal olmaktan uzaktır. Belki de bu göstergenin düzleştirilmiş bir versiyonu kullanılarak daha iyi sonuçlar elde edilecektir - Düzleştirilmiş Heiken Ashi yeniden çizilmeye çok meyilli değildir.

Tüm Uzman Danışmanlar, dinamik bir durdurma seviyesinin çekilmesi ve hedef bir seviyenin oluşturulması ile açık pozisyon yürütme sisteminden kesinlikle faydalanacaktır. Ayrıca, düşüşü en aza indirmeye ve uzun vadede kârı artırmaya izin veren bir sermaye yönetimi sistemine sahip olmak harika olurdu.


Sonuç

Böylece bir trendi algılayan kodu yazmak o kadar da zor değil. Buradaki en önemli şey, piyasanın bazı yasalarından yararlanarak işe yarayan ve mantıklı bir fikirdir. Bu yasalar ne kadar temel olursa bu yasalara dayalı alım satım sistemine o kadar güvenirsiniz - kısa bir çalışma süresinden sonra bozulmaz.

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/136

Ekli dosyalar |
experts.zip (9.35 KB)
indicators.zip (7.82 KB)
Alım Satım Sistemlerinin Değerlendirilmesi - Genel Olarak Giriş, Çıkış ve İşlemlerin Etkililiği Alım Satım Sistemlerinin Değerlendirilmesi - Genel Olarak Giriş, Çıkış ve İşlemlerin Etkililiği
Bir alım satım sisteminin etkililiğini ve kârlılığını belirlemeye izin veren birçok önlem vardır. Ancak, yatırımcılar her zaman herhangi bir sistemi yeni bir çarpışma testine sokmaya hazırdır. Makale, etkililik ölçütlerine dayalı istatistiklerin MetaTrader 5 platformu için nasıl kullanılabileceğini anlatıyor. S.V. Bulashev’in "Statistika dlya traderov" ("Yatırımcılar için İstatistikler") kitabında verilen açıklamaya aykırı olmayan, sözleşmelere göre istatistiklerin yorumlanmasının dönüştürülmesine yönelik sınıfı içerir. Ayrıca optimizasyon için bir özel fonksiyon örneği içerir.
MQL5'te Çok Renkli Göstergeler Oluşturma MQL5'te Çok Renkli Göstergeler Oluşturma
Bu makalemizde çok renkli göstergelerin nasıl oluşturulacağını veya var olan göstergelerin çok renkli hale nasıl dönüştürüleceğini ele alacağız. MQL5, bilgilerin uygun biçimde temsil edilmesini sağlar. Artık göstergelere sahip bir düzine grafiğe bakmak ve RSI veya Stokastik seviyelerinin analizlerini yapmak gerekli değildir, sadece göstergelerin değerlerine bağlı olarak mumları farklı renklerle boyamak daha iyidir.
Bill Williams'ın "Yeni Ticaret Boyutları" kitabına dayanan Uzman Danışman Bill Williams'ın "Yeni Ticaret Boyutları" kitabına dayanan Uzman Danışman
Bu makalede, Uzman Danışmanın Bill Williams tarafından yazılan "New Trading Dimensions: How to Profit from Chaos in Stocks, Bonds and Commodities” (Yeni Ticaret Boyutları: Hisse Senetleri, Tahviller ve Emtialardaki Kaostan Nasıl Kar Edilir) kitabına dayanarak geliştirilmesini ele alacağım. Stratejinin kendisi iyi bilinmektedir ve kullanımı yatırımcılar arasında hala tartışmalıdır. Makale, sistemin alım satım sinyallerini, uygulanmasının özelliklerini ve geçmiş veriler üzerinde test sonuçlarını dikkate almaktadır.
Kendi Takip Eden Durdurma (Trailing Stop) Emrinizi Nasıl Oluşturabilirsiniz? Kendi Takip Eden Durdurma (Trailing Stop) Emrinizi Nasıl Oluşturabilirsiniz?
Yatırımcının temel kuralı - kârın büyümesine izin verin, zararları kesin! Bu makale, bu kuralın izlenmesine izin veren temel tekniklerden birini, pozisyon kârını artırdıktan sonra koruyucu durdurma seviyesini (Zararı Durdur seviyesi), yani Takip Eden Durdurma (Trailing Stop) seviyesini hareket ettirmeyi ele almaktadır. SAR ve NRTR göstergelerinde takip eden durdurma için bir sınıf oluşturmaya yönelik adım adım prosedürü bulacaksınız. Herkes bu takip eden durdurmayı kendi uzmanlarına ekleyebilecek veya hesaplarındaki pozisyonları kontrol etmek için bağımsız olarak kullanabilecek.