English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Zaman Serilerinin Tahmini için MetaTrader 5 Göstergelerini ENCOG Makine Öğrenimi Çerçevesi ile Kullanma

Zaman Serilerinin Tahmini için MetaTrader 5 Göstergelerini ENCOG Makine Öğrenimi Çerçevesi ile Kullanma

MetaTrader 5Örnekler | 16 Aralık 2021, 14:52
272 0
investeo
investeo

Giriş

Bu makale, MetaTrader 5'i Heaton Research tarafından geliştirilen gelişmiş sinir ağı ve makine öğrenimi çerçevesi olan ENCOG ile tanıştıracak. Bildiğim kadarıyla halihazırda MetaTrader'ın makine öğrenimi tekniklerini kullanmasını sağlamayı gösteren yöntemler var: FANN, NeuroSolutions, Matlab ve NeuroShell. ENCOG sağlam ve iyi tasarlanmış bir kod olduğu için tamamlayıcı bir çözüm olacağını umuyorum.

Neden ENCOG'u seçtim? Bunun bir kaç nedeni var.

  1. ENCOG, iki farklı ticari yazılım paketinde daha kullanılmakta. Biri C#', ikincisi JAVA tabanlı. Bu, mali zaman serisi verilerini tahmin etme konusunda test edilmiş demektir. 
  2. ENCOG ücretsiz ve açık kaynaklı bir yazılımdır. Bir sinir ağının içinde neler olup bittiğini görmek isterseniz kaynak koduna göz atabilirsiniz. Zaman serisi tahmin probleminin bazı kısımlarını anlamak için ben de bunu yaptım. C# ise yalın ve anlaşılması kolay bir programlama dili.
  3. ENCOG çok detaylı şekilde hazırlanmış ve belgelenmiştir. Heaton Research'ün kurucusu Bay Heaton, Sinir Ağları, Makine Öğrenimi ve gelecekteki verileri tahmin etmek için ENCOG kullanımı hakkında ücretsiz bir çevrimiçi kurs sunuyor. Bu makaleyi yazmadan önce kendisinin birçok dersini aldım. Bu dersler Yapay Sinir Ağlarını anlamama çok yardımcı oldu. Ayrıca Heaton Research web sitesinde JAVA ve C# ile ENCOG programlama hakkında e-kitaplar da bulunuyor. ENCOG’un bütün belgeleri çevrimiçi olarak mevcut.
  4. ENCOG ölü bir proje değil. Ben bu makaleyi yazarken ENCOG 2.6 hala geliştirilmeye devam ediyor. ENCOG 3.0 yol haritası yakın zamanda yayınlandı.
  5. ENCOG sağlamdır. İyi tasarlanmıştır, sinir ağı hesaplamalarını hızlandırmak için birden fazla CPU çekirdeğini çoklu kullanım ile kullanabilir. Kodun bölümleri OpenCL - GPU etkin hesaplamaları için taşınmaya başlar.
  6. ECNOG’un halihazırda desteklenen özellikleri: 

Makine Öğrenimi Çeşitleri

Sinir Ağı Mimarileri

Eğitim Teknikleri Aktivasyon Fonksiyonları Rastgeleleştirme Teknikleri
  • Aralık Rastgeleleştirme
  • Gauss Rastgele Sayılar
  • Fan Girişi
  • Nguyen-Widrow

Planlanan özellikler:

Gördüğünüz üzere bu oldukça uzun bir özellik listesi.

Bu konuya giriş makalesi, Esnek Yayılım (RPROP) eğitimi ile ileri beslemeli Sinir Ağı mimarisine odaklanmaktadır. Ayrıca, veri hazırlamanın temellerini de kapsar. Örneğin zaman sınırlaması ve zamansal zaman dizileri tahmini için normalleştirme.

Bu makaleyi yazmamı sağlayan bilgiler, Heaton Research web sitesinde bulunan kılavuzlara ve NinjaTrader'daki mali zaman serilerinin tahmini üzerine fazlasıyla yakın zamanda yazılan makalelere dayanmaktadır. ENCOG'un JAVA ve C# tabanlı olduğunu lütfen unutmayın. Önceki çalışmalarım olmadan bu makaleyi yazmak mümkün olmazdı: Yönetilmeyen dışa aktarmaları kullanarak C# kodunu MQL5'e maruz bırakma. Bu çözüm, C# DLL'nin Metatrader 5 göstergesi ile ENCOG zaman serisi tahmincisi arasında bir köprü olarak kullanılmasına olanak sağladı.


1. Bir Sinir Ağı İçin Girdi Olarak Teknik Gösterge Değerlerini Kullanma

Yapay Sinir Ağı, beynin sinir ağını taklit etmeye çalışan, insan yapımı bir algoritmadır.

Çeşitli sinirsel algoritma türleri bulunur ve bunların içinde çeşitli sinir ağı mimarileri mevcuttur. Araştırma alanı o kadar geniştir ki, tamamı tek bir sinir ağı türü üzerine yazılan kitaplar vardır. Bu tür ayrıntılar bu makalenin kapsamı dışında olduğundan, yalnızca Heaton Research kılavuzlarını incelemenizi veya konuyla ilgili kitaplar okumanızı tavsiye edebilirim. Ben ileri beslemeli sinir ağının girdileri ve çıktılarına odaklanacağım ve mali zaman serisi tahmininin pratik örneğini açıklamaya çalışacağım.

Mali zaman serilerini öngörmeye başlamak için sinir ağına vermemiz gerekenleri ve bunun karşılığında ne bekleyebileceğimizi düşünmemiz gerek. Çoğu soyut kara kutu düşünme şeklinde, belirli bir menkul kıymetin sözleşmesinde uzun veya kısa pozisyonlar alarak ve bir süre sonra anlaşmayı kapatarak kâr veya zarar elde ederiz.

Bir menkul kıymetin geçmiş fiyatlarını ve teknik göstergelerin değerlerini gözlemleyerek, bir sözleşmeyi satın almak veya satmak için gelecekteki duyarlılığı veya fiyatların gideceği yönü tahmin etmeye çalışırız ve kararımızın yazı tura atar gibi alınmadığından emin oluruz. Durum hemen hemen aşağıdaki şekle benziyor:

Şekil 1. Teknik göstergeleri kullanarak mali zaman serilerini tahmin etme

Şekil 1. Teknik göstergeleri kullanarak mali zaman serilerini tahmin etme 

Bunun aynısını yapay zeka ile başarmaya çalışacağız. Sinir ağı, gösterge değerlerini tanımaya çalışacak ve fiyatın yükselme veya düşme ihtimalinin olup olmadığına karar verecektir. Bunu nasıl başarabiliriz? Mali zaman serilerini ileri beslemeli sinir ağı mimarisini kullanarak tahmin edeceğimiz için bu mimariye de bir giriş yapmamız gerektiğini düşünüyorum.

İleri beslemeli sinir ağı, katmanlar halinde gruplandırılmış nöronlardan oluşur. En az 2 katmandan oluşabilir: girdi nöronlarını içeren bir giriş katmanı ve çıktı nöronlarını içeren bir çıkış katmanı. Giriş ve çıkış katmanları arasında gizli katmanlar da olabilir. Giriş katmanı temel olarak çift değerlerden oluşan bir dizi olarak düşünülebilir ve çıkış katmanı da aynı şekilde bir çift değerler dizisi oluşturan bir veya daha fazla nörondan oluşabilir. Aşağıdaki şekle bakınız:

  Şekil 2. İleri beslemeli sinir ağı katmanları

Şekil 2. İleri beslemeli sinir ağı katmanları 

Çizimi basitleştirmek için nöronlar arasındaki bağlantılar çizilmemiştir. Giriş katmanındaki her bir nöron, gizli katmandaki bir nörona bağlanır. Gizli katmandaki her nöron, çıkış katmanındaki bir nörona bağlanır.

Her bağlantının kendi ağırlığı vardır, bu aynı zamanda bir çift değerdir ve bir nöronu aktive etmekten ve bilgiyi bir sonraki nörona iletmekten sorumlu olan bir eşiği olan aktivasyon fonksiyonudur. Bu nedenle buna 'ileri beslemeli’ ağ denir - aktive edilmiş nöronların çıktılarına dayanan bilgi, bir katmandan başka bir nöron katmanına ileriye doğru beslenir. İleri beslemeli sinir ağları hakkındaki ayrıntılı bilgilendirici videolar için aşağıdaki bağlantıları ziyaret etmek isteyebilirsiniz:

Sinir ağı mimarisini ve mekanizmalarını öğrendikten sonra hala kafanız karışık olabilir.

Başlıca sorunlar şunlardır:

  1. Bir sinir ağına hangi verileri besleyeceğiz?
  2. Nasıl besleyeceğiz?
  3. Bir sinir ağı için girdi verileri nasıl hazırlanır? 
  4. Sinir ağı mimarisi nasıl seçilir? Kaç adet girdi nöronu, gizli nöron ve çıktı nöronu gerekli?
  5. Ağ nasıl eğitilir?
  6. Çıktı olarak ne beklenmeli?

 

2. Sinir Ağına Beslenecek Veriler

Gösterge çıktılarına dayalı mali tahminlerle ilgilendiğimiz için, ağı göstergenin çıktı değerleriyle beslememiz gerekir. Bu makalede girdi olarak Stokastik %K’yi, Yavaş Stokastik %D’yi ve Williams %R’yi seçtim.

Şekil 3. Tahmin için kullanılan teknik göstergeler

Şekil 3. Tahmin için kullanılan teknik göstergeler

Göstergelerin değerlerini çıkarmak için iStochastic ve iWPR MQL5 fonksiyonlarını kullanabiliriz:

double StochKArr[], StochDArr[], WilliamsRArr[];

ArraySetAsSeries(StochKArr, true);   
ArraySetAsSeries(StochDArr, true);   
ArraySetAsSeries(WilliamsRArr, true);

int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
CopyBuffer(hStochastic, 0, 0, bufSize, StochKArr);
CopyBuffer(hStochastic, 1, 0, bufSize, StochDArr);
CopyBuffer(hWilliamsR, 0, 0, bufSize, WilliamsRArr);

Bu kod çalıştırıldıktan sonra üç StochKArr, StochDArr ve WilliamsRArr dizileri gösterge çıkış değeri ile doldurulmalıdır. Eğitim örneklem büyüklüğüne bağlı olarak bu, birkaç binlik değerlere kadar çıkabilir. Lütfen bu iki göstergenin yalnızca eğitim amaçlı seçildiğini unutmayın.

Tahmin için uygun bulduğunuz herhangi bir göstergeyi denemenizi tavsiye ederim. Hisse senedi endekslerini tahmin etmek için ağı altın ve petrol fiyatları ile beslemek isteyebilirsiniz veya başka bir döviz çiftini tahmin etmek için korelasyonlu forex çiftlerini kullanabilirsiniz. 

 

3. Girdi Verilerine Zaman Sınırlaması Koymak

Birkaç göstergeden girdi verilerini topladıktan sonra sinir ağına beslemeden önce girdiye "zaman sınırı koymaya" ihtiyacımız var. Zaman sınırlaması, ağdaki girdilerin hareketli veri dilimleri olarak sunulmasına olanak sağlayan bir yöntemdir. Zaman ekseninde ilerleyen hareketli bir girdi verisi kutusu gibi hayal edebilirsiniz. Bu prosedürün temelde iki adımı vardır:

1. Her göstergenin ara belleğinden girdi verilerinin toplanması. Başlangıç konumundan geleceğe doğru INPUT_WINDOW (Girdi_Penceresi) sayıda öğe kopyalamamız gerekir. Girdi penceresi, tahmin için kullanılan çubuk sayısıdır. 

  Şekil 4. Gösterge ara belleğinden girdi penceresi verilerinin toplanması

Şekil 4. Gösterge ara belleğinden girdi penceresi verilerinin toplanması 

Yukarıdaki örnekte görebileceğiniz gibi INPUT_WINDOW 4 çubuğa eşit ve unsurları I1 dizisine kopyaladık. I1[0] ilk öğedir, I1[3] son öğedir. Benzer şekilde, veriler diğer göstergelerden de INPUT_WINDOW boyutlu dizilere kopyalanmalıdır. Bu rakam, AS_SERIES işaretinin true(doğru) olarak ayarlandığı zaman serisi dizileri için geçerlidir. 

2. INPUT_WINDOW dizilerini, sinir ağı giriş katmanına beslenen tek bir dizi olacak şekilde birleştirmek. 

Şekil 5. Zaman sınırlı girdi penceresi dizileri  

Şekil 5. Zaman sınırlı girdi penceresi dizileri

3 adet gösterge bulunuyor, önce her göstergenin ilk değerini, ardından her göstergenin ikinci değerini alıyoruz ve yukarıdaki şekildeki gibi girdi penceresi dolana kadar buna devam ediyoruz. Gösterge çıktılarından birleştirilen bu dizi, sinir ağımızın giriş katmanına beslenebilir. Yeni bir çubuk geldiğinde, veriler bir unsur tarafından dilimlenir ve tüm işlem tekrarlanır. Verileri tahmin için hazırlamak konusunda daha detaylı bilgi edinmek isterseniz konuyla ilgili bir video da izlemek isteyebilirsiniz.

 

4. Girdi Verilerini Normalleştirme

Sinir ağını etkili kılmak için verileri normalleştirmemiz gerekir. Bu, aktivasyon fonksiyonlarının doğru hesaplanması için gereklidir. Normalleştirme, verileri 0..1 veya -1..1 aralığına dönüştüren matematiksel bir işlemdir. Normalleştirilmiş veriler denormalize edilebilir, yani başka bir deyişle orijinal aralıklarına geri dönüştürülebilir.

Denormalizasyon, sinir ağı çıktısını insanlar tarafından okunabilir bir biçime dönüştürmek için gereklidir. Neyse ki ENCOG normalleştirme ve denormalizasyon işlemlerini halleder, bu nedenle uygulamaya gerek yoktur. Bunun nasıl işlediğini merak ediyorsanız aşağıdaki kodu inceleyebilirsiniz:

/**
         * Normalize the specified value.
         * @param value The value to normalize.
         * @return The normalized value.
         */
        public static double normalize(final int value) {
                return ((value - INPUT_LOW) 
                                / (INPUT_HIGH - INPUT_LOW))
                                * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW;
        }
        
        /**
         * De-normalize the specified value.
         * @param value The value to denormalize.
         * @return The denormalized value.
         */
        public static double deNormalize(final double data) {
                double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH
                                * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW)
                                / (OUTPUT_LOW - OUTPUT_HIGH);
                return result;
        }

ve daha fazla ayrıntı için normalleştirmeyle ilgili bir makale okuyabilirsiniz 

 

5. Ağ mimarisini ve nöron sayısını seçme

Bu konuda acemi olanlar için doğru ağ mimarisini seçmek zor bir kısımdır. Bu makalede, beslemeli sinir ağı mimarisini üç katmanla sınırlandırıyorum: bir giriş katmanı, bir gizli katman ve bir çıkış katmanı. Daha fazla sayıda katmanla deneme yapmakta özgürsünüz.

Giriş ve çıkış katmanı için gerekli nöron sayısını doğru bir şekilde sayabileceğiz. Gizli bir katman için, ileriye doğru bir seçim algoritması kullanarak sinir ağı hatalarını en aza indirmeye çalışacağız. Diğer yöntemleri de kullanmanızı tavsiye ederim; nöron sayısını hesaplamak için bazı genetik algoritmalar olabilir.

ENCOG tarafından kullanılan bir diğer yöntem ise geriye doğru seçim algoritması veya budama olarak adlandırılır, yapılan şey temel olarak katmanlar arasındaki bağlantıları değerlendirmek ve sıfır ağırlıklı bağlantılarla gizli nöronları kaldırmaktır, bunu da denemek isteyebilirsiniz.

5.1. Giriş nöronları katmanı

Zaman sınırlaması nedeniyle, giriş katmanındaki nöronların sayısı, bir sonraki çubuğu tahmin etmek için kullanılan gösterge sayısı çarpı çubuk sayısına eşit olmalıdır. Girdi olarak 3 gösterge kullanırsak ve giriş penceresi boyutu 6 çubuğa eşitse, giriş katmanı 18 nörondan oluşacaktır. Giriş katmanı, zaman sınırlaması ile hazırlanan verilerle beslenir.

5.2. Gizli nöron katmanı

Gizli ağların sayısı, eğitilmiş sinir ağı performansına dayalı olarak tahmin edilmelidir. Belirli sayıda gizli nöron için basit bir matematiksel denklem yoktur. Makaleyi yazmadan önce birden fazla deneme yanılma yaklaşımı kullandım ve Heaton Research web sitesinde ileriye doğru seçim algoritmasını anlamaya yardımcı olan bir algoritma buldum:

Şekil 6. Gizli nöron sayısı için ileriye doğru seçim algoritması 

Şekil 6. Gizli nöron sayısı için ileriye doğru seçim algoritması  

5.3. Çıktı nöronları katmanı

Amaçlarımız doğrultusunda, çıktı nöronlarının sayısı, tahmin etmeye çalıştığımız çubukların sayısıdır. Lütfen gizli ve çıktı nöron sayıları arttıkça ağın eğitilme süresinin de aynı ölçekte arttığını unutmayın. Bu makalede gelecekteki tek bir çubuğu tahmin etmeye çalışıyorum, bu nedenle çıkış katmanı tek bir nörondan oluşuyor.

 

6. Eğitim Verilerini MetaTrader 5'ten ENCOG'a Dışa Aktarma

Encog, sinir ağı eğitimi için CSV dosyalarını kabul eder.

Diğer ticari yazılımlardan ENCOG'a aktarılan dosya formatına baktım ve aynı dosya formatını eğitim için hazırlayan MQL5 komut dosyasını uyguladım. İlk önce tek bir göstergeyi dışa aktarmayı göstereceğim ve daha sonra birden fazla göstergeyle devam edeceğim. 

İlk veri satırı, virgülle ayrılmış bir başlıktır:

DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3

İlk üç sütun tarih, saat ve kapanış değerlerini içerir, sonraki sütunlar gösterge adlarını içerir. Eğitim dosyasının sonraki satırları virgülle ayrılmış veriler içermeli, gösterge değerleri de bilimsel formatta yazılmalıdır:  

20110103,0000,0.93377000,-7.8970208860e-002

Aşağıda bulunan bir göstergenin hazır komut dosyasını inceleyiniz.

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 400;
extern int  maPeriod = 210;

MqlRates srcArr[];
double expBullsArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(expBullsArr, true);      
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hBullsPower = iBullsPower(Symbol(), Period(), maPeriod);
   
   CopyBuffer(hBullsPower, 0, 0, trainSize, expBullsArr);
   
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,BullsPower\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(expBullsArr[i], -10));
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

 Eğitim için kullanılabilecek sonuç dosyası aşağıdaki çıktı gibi görünmelidir: 

DATE,TIME,CLOSE,BullsPower
20110103,0000,0.93377000,-7.8970208860e-002
20110104,0000,0.94780000,-6.4962292188e-002
20110105,0000,0.96571000,-4.7640374727e-002
20110106,0000,0.96527000,-4.4878854587e-002
20110107,0000,0.96697000,-4.6178012364e-002
20110110,0000,0.96772000,-4.2078647318e-002
20110111,0000,0.97359000,-3.6029181466e-002
20110112,0000,0.96645000,-3.8335729509e-002
20110113,0000,0.96416000,-3.7054869514e-002
20110114,0000,0.96320000,-4.4259373120e-002
20110117,0000,0.96503000,-4.4835729773e-002
20110118,0000,0.96340000,-4.6420936126e-002
20110119,0000,0.95585000,-4.6868984125e-002
20110120,0000,0.96723000,-4.2709941621e-002
20110121,0000,0.95810000,-4.1918330800e-002
20110124,0000,0.94873000,-4.7722659418e-002
20110125,0000,0.94230000,-5.7111591557e-002
20110126,0000,0.94282000,-6.2231529077e-002
20110127,0000,0.94603000,-5.9997865295e-002
20110128,0000,0.94165000,-6.0378312069e-002
20110131,0000,0.94414000,-6.2038328069e-002
20110201,0000,0.93531000,-6.0710334438e-002
20110202,0000,0.94034000,-6.1446445012e-002
20110203,0000,0.94586000,-5.2580791504e-002
20110204,0000,0.95496000,-4.5246755566e-002
20110207,0000,0.95730000,-4.4439392954e-002

Orijinal makaledeki Stokastik ve Williams' R göstergelerini içeren örneğe geri dönersek, göstergeleri virgülle ayrılmış üç sütunu dışa aktarmamız gerekiyor, her sütun ayrı gösterge değerleri içeriyor, bu nedenle de dosyayı genişletmemiz ve ek arabellekler eklememiz gerekiyor:

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 2000;

MqlRates srcArr[];
double StochKArr[], StochDArr[], WilliamsRArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(StochKArr, true);   
   ArraySetAsSeries(StochDArr, true);   
   ArraySetAsSeries(WilliamsRArr, true);
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
   
   CopyBuffer(hStochastic, 0, 0, trainSize, StochKArr);
   CopyBuffer(hStochastic, 1, 0, trainSize, StochDArr);
   CopyBuffer(hWilliamsR, 0, 0, trainSize, WilliamsRArr);
    
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,StochK,StochD,WilliamsR\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), 
                                                 DoubleToString(StochKArr[i], -10),
                                                 DoubleToString(StochDArr[i], -10),
                                                 DoubleToString(WilliamsRArr[i], -10)
                                                 );
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

Sonuç dosyası tüm gösterge değerlerini içermelidir:

DATE,TIME,CLOSE,StochK,StochD,WilliamsR
20030707,0000,1.37370000,7.1743119266e+001,7.2390220187e+001,-6.2189054726e-001
20030708,0000,1.36870000,7.5140977444e+001,7.3307139273e+001,-1.2500000000e+001
20030709,0000,1.35990000,7.3831775701e+001,7.3482018082e+001,-2.2780373832e+001
20030710,0000,1.36100000,7.1421933086e+001,7.2795323083e+001,-2.1495327103e+001
20030711,0000,1.37600000,7.5398313027e+001,7.3662986398e+001,-3.9719626168e+000
20030714,0000,1.37370000,7.0955352856e+001,7.2760441884e+001,-9.6153846154e+000
20030715,0000,1.38560000,7.4975891996e+001,7.3498925255e+001,-2.3890784983e+000
20030716,0000,1.37530000,7.5354107649e+001,7.4117319386e+001,-2.2322435175e+001
20030717,0000,1.36960000,7.1775345074e+001,7.3336661282e+001,-3.0429594272e+001
20030718,0000,1.36280000,5.8474576271e+001,6.8382632945e+001,-3.9778325123e+001
20030721,0000,1.35400000,4.3498596819e+001,6.0087954237e+001,-5.4946524064e+001
20030722,0000,1.36130000,2.9036761284e+001,4.9737556586e+001,-4.5187165775e+001
20030723,0000,1.34640000,1.6979405034e+001,3.8818172735e+001,-6.5989159892e+001
20030724,0000,1.34680000,1.0634573304e+001,2.9423639592e+001,-7.1555555556e+001
20030725,0000,1.34400000,9.0909090909e+000,2.2646062758e+001,-8.7500000000e+001
20030728,0000,1.34680000,1.2264922322e+001,1.9185682613e+001,-8.2705479452e+001
20030729,0000,1.35250000,1.4960629921e+001,1.7777331716e+001,-7.2945205479e+001
20030730,0000,1.36390000,2.7553336360e+001,2.1035999930e+001,-5.3979238754e+001
20030731,0000,1.36990000,4.3307839388e+001,2.8459946416e+001,-4.3598615917e+001
20030801,0000,1.36460000,5.6996412096e+001,3.7972101643e+001,-5.2768166090e+001
20030804,0000,1.34780000,5.7070193286e+001,4.4338132191e+001,-8.1833910035e+001
20030805,0000,1.34770000,5.3512705531e+001,4.7396323304e+001,-8.2006920415e+001
20030806,0000,1.35350000,4.4481132075e+001,4.6424592894e+001,-7.1972318339e+001
20030807,0000,1.35020000,3.3740028156e+001,4.2196404648e+001,-7.7681660900e+001
20030808,0000,1.35970000,3.0395426394e+001,3.8262745230e+001,-6.1245674740e+001
20030811,0000,1.35780000,3.4155781326e+001,3.6893757262e+001,-6.4532871972e+001
20030812,0000,1.36880000,4.3488943489e+001,3.9092152671e+001,-4.5501730104e+001
20030813,0000,1.36690000,5.1160443996e+001,4.3114916446e+001,-4.8788927336e+001
20030814,0000,1.36980000,6.2467599793e+001,4.9565810895e+001,-2.5629290618e+001
20030815,0000,1.37150000,6.9668246445e+001,5.6266622745e+001,-2.1739130435e+001
20030818,0000,1.38910000,7.9908906883e+001,6.4147384124e+001,-9.2819614711e+000

İkinci örneği ihtiyaçlarınıza uygun bir komut dosyasını kolayca oluşturmak için kolayca düzenleyebilirsiniz.


7. Sinir Ağı Eğitimi

Ağın eğitimi Heaton Research tarafından halihazırda C# dilinde hazırlanmıştır. ENCOG 2.6, mali zaman serisi tahmini için bir temel olan Encog.App.Quant ad alanını uygular. Eğitim komut dosyası çok esnektir, herhangi bir sayıda girdi göstergesine kolayca ayarlanabilir. MetaTrader 5 dizin konumunu yalnızca DIRECTORY sabitinde değiştirmelisiniz.

Ağ mimarisi ve eğitim parametreleri, aşağıdaki değişkenler değiştirilerek kolayca özelleştirilebilir:

        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

Kod fazlasıyla açıktır, bu nedenle yapabileceğiniz en iyi şey dikkatlice okumak olacaktır:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Encog.App.Quant.Normalize;
using Encog.Util.CSV;
using Encog.App.Quant.Indicators;
using Encog.App.Quant.Indicators.Predictive;
using Encog.App.Quant.Temporal;
using Encog.Neural.NeuralData;
using Encog.Neural.Data.Basic;
using Encog.Util.Simple;
using Encog.Neural.Networks;
using Encog.Neural.Networks.Layers;
using Encog.Engine.Network.Activation;
using Encog.Persist;

namespace NetworkTrainer
{
    public class Program
    {
        /// <summary>
        /// The directory that all of the files will be stored in.
        /// </summary>
        public const String DIRECTORY = "d:\\mt5\\MQL5\\Files\\";

        /// <summary>
        /// The input file that starts the whole process.  This file should be downloaded from NinjaTrader using the EncogStreamWriter object.
        /// </summary>
        public const String STEP1_FILENAME = DIRECTORY + "mt5export.csv";

        /// <summary>
        /// We apply a predictive future indicator and generate a second file, with the additional predictive field added.
        /// </summary>
        public const String STEP2_FILENAME = DIRECTORY + "step2_future.csv";

        /// <summary>
        /// Next the entire file is normalized and stored into this file.
        /// </summary>
        public const String STEP3_FILENAME = DIRECTORY + "step3_norm.csv";

        /// <summary>
        /// The file is time-boxed to create training data.
        /// </summary>
        public const String STEP4_FILENAME = DIRECTORY + "step4_train.csv";

        /// <summary>
        /// Finally, the trained neural network is written to this file.
        /// </summary>
        public const String STEP5_FILENAME = DIRECTORY + "step5_network.eg";
       
        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

        static void Main(string[] args)
        {
            // Step 1: Create future indicators
            Console.WriteLine("Step 1: Analyze MT5 Export & Create Future Indicators");
            ProcessIndicators ind = new ProcessIndicators();
            ind.Analyze(STEP1_FILENAME, true, CSVFormat.DECIMAL_POINT);
            int externalIndicatorCount = ind.Columns.Count - 3;
            ind.AddColumn(new BestReturn(RESULT_WINDOW,true)); 
            ind.Process(STEP2_FILENAME);          
            Console.WriteLine("External indicators found: " + externalIndicatorCount);
            //Console.ReadKey();

            // Step 2: Normalize
            Console.WriteLine("Step 2: Create Future Indicators");
            EncogNormalize norm = new EncogNormalize();
            norm.Analyze(STEP2_FILENAME, true, CSVFormat.ENGLISH);
            norm.Stats[0].Action = NormalizationDesired.PassThrough; // Date
            norm.Stats[1].Action = NormalizationDesired.PassThrough; // Time
            
            norm.Stats[2].Action = NormalizationDesired.Normalize; // Close
            norm.Stats[3].Action = NormalizationDesired.Normalize; // Stoch K
            norm.Stats[4].Action = NormalizationDesired.Normalize; // Stoch Dd
            norm.Stats[5].Action = NormalizationDesired.Normalize; // WilliamsR
       
            norm.Stats[6].Action = NormalizationDesired.Normalize; // best return [RESULT_WINDOW]

            norm.Normalize(STEP3_FILENAME);

            // neuron counts
            int inputNeurons = INPUT_WINDOW * externalIndicatorCount;
            int outputNeurons = PREDICT_WINDOW;

            // Step 3: Time-box
            Console.WriteLine("Step 3: Timebox");
            //Console.ReadKey();
            TemporalWindow window = new TemporalWindow();
            window.Analyze(STEP3_FILENAME, true, CSVFormat.ENGLISH);
            window.InputWindow = INPUT_WINDOW;
            window.PredictWindow = PREDICT_WINDOW;
            int index = 0;
            window.Fields[index++].Action = TemporalType.Ignore; // date
            window.Fields[index++].Action = TemporalType.Ignore; // time
            window.Fields[index++].Action = TemporalType.Ignore; // close
            for(int i=0;i<externalIndicatorCount;i++)
                window.Fields[index++].Action = TemporalType.Input; // external indicators
            window.Fields[index++].Action = TemporalType.Predict; // PredictBestReturn

            window.Process(STEP4_FILENAME);

            // Step 4: Train neural network
            Console.WriteLine("Step 4: Train");
            Console.ReadKey();
            INeuralDataSet training = (BasicNeuralDataSet)EncogUtility.LoadCSV2Memory(STEP4_FILENAME, inputNeurons, 
                                                                                      outputNeurons, true, CSVFormat.ENGLISH);

            BasicNetwork network = new BasicNetwork();
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, inputNeurons));
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, HIDDEN1_NEURONS));
            network.AddLayer(new BasicLayer(new ActivationLinear(), true, outputNeurons));
            network.Structure.FinalizeStructure();
            network.Reset();

            //EncogUtility.TrainToError(network, training, TARGET_ERROR);
            EncogUtility.TrainConsole(network, training, 3);

            // Step 5: Save neural network and stats
            EncogMemoryCollection encog = new EncogMemoryCollection();
            encog.Add("network", network);
            encog.Add("stat", norm.Stats);
            encog.Save(STEP5_FILENAME);
            Console.ReadKey();
        }
    }
}

Bir satırı yorumladığımı ve eğitim işlevini EncogUtility.TrainToError() yerine EncogUtility.TrainConsole() olarak değiştirdiğimi fark edebilirsiniz.

EncogUtility.TrainConsole(network, training, 3);

TrainConsole yöntemi, ağın eğitileceği dakika sayısını belirtir. Bu örnekte ağı üç dakika boyunca eğitiyorum. Ağın karmaşıklığına ve eğitim verilerinin boyutuna bağlı olarak, ağın eğitilmesi dakikalar, saatler hatta günler boyu sürebilir. Heaton Research web sitesinde veya konuyla ilgili başka herhangi bir kitapta hata hesaplama ve eğitim algoritmaları hakkında daha fazla okuma yapmanızı tavsiye ederim.

EncogUtility.TrainToError() yöntemleri, hedef koyulan bir ağ hatasına ulaşıldıktan sonra ağı eğitmeyi durdurur. Orijinal örnekte olduğu gibi ağı istenen bir hata bulunana kadar eğitmek için EncongUtiliy.TrainConsole() yorumunu yapabilir ve EncogUtility.TrainToError() yorumunu kaldırabilirsiniz. 

EncogUtility.TrainToError(network, training, TARGET_ERROR);

Lütfen, bazen nöronların sayısı çok az olduğundan, ağın belirli bir hataya kadar eğitilemediğini unutmayın.


8. MetaTrader 5 Sinir Göstergesi Oluşturmak için Eğitilmiş Sinir Ağını Kullanma

Eğitilmiş ağ, en iyi yatırım getirisini tahmin etmeye çalışan bir sinir ağı göstergesi tarafından kullanılabilir.

MetaTrader 5’te ENCOG sinir göstergesi iki bölümden oluşur. Bir kısım MQL5'te yazılmıştır ve temelde ağın eğitildiği göstergelerle aynı göstergeleri alır ve girdi penceresi gösterge değerleri ile ağı besler. İkinci kısım C# ile yazılmıştır ve girdi verilerini zaman sınırlarının arasına yerleştirir ve sinir ağı çıkışını MQL5'e geri döndürür. C# gösterge kısmı, C# kodunu MQL5'e Tanıtma konusundaki daha önce yazdığım makaleme dayanmaktadır.

using System;
using System.Collections.Generic;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using Encog.Neural.Networks;
using Encog.Persist;
using Encog.App.Quant.Normalize;
using Encog.Neural.Data;
using Encog.Neural.Data.Basic;

namespace EncogNeuralIndicatorMT5DLL
{

    public class NeuralNET
    {
        private EncogMemoryCollection encog;
        public BasicNetwork network;
        public NormalizationStats stats;

        public NeuralNET(string nnPath)
        {
            initializeNN(nnPath);
        }

        public void initializeNN(string nnPath)
        {
            try
            {
                encog = new EncogMemoryCollection();
                encog.Load(nnPath);
                network = (BasicNetwork)encog.Find("network");
                stats = (NormalizationStats)encog.Find("stat");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }
    };

   class UnmanagedExports
   {

      static NeuralNET neuralnet; 

      [DllExport("initializeTrainedNN", CallingConvention = CallingConvention.StdCall)]
      static int initializeTrainedNN([MarshalAs(UnmanagedType.LPWStr)]string nnPath)
      {
          neuralnet = new NeuralNET(nnPath);

          if (neuralnet.network != null) return 0;
          else return -1;
      }

      [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                           int len, 
                                           [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                           int rates_total)
      {
          INeuralData input = new BasicNeuralData(3 * len);
          
          int index = 0;
          for (int i = 0; i <len; i++)
          {
              input[index++] = neuralnet.stats[3].Normalize(t1[i]);
              input[index++] = neuralnet.stats[4].Normalize(t2[i]);
              input[index++] = neuralnet.stats[5].Normalize(t3[i]);
          }

          INeuralData output = neuralnet.network.Compute(input);
          double d = output[0];
          d = neuralnet.stats[6].DeNormalize(d);        
          result[rates_total-1]=d;

          return 0;
      }  
   }
}

Üçten başka herhangi bir sayıda gösterge kullanmak isterseniz, computeNNIndicator() yöntemini ihtiyaçlarınıza uygun şekilde değiştirmeniz gerekir. 

 [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                         int len, 
                                         [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                         int rates_total)

Bu durumda, ilk üç giriş parametresi, gösterge giriş değerlerini içeren tablolar olacaktır, dördüncü parametre ise girdi penceresinin uzunluğudur.

SizeParamIndex =3, giriş değişkenleri sayısı 0'dan itibaren artırıldığından, pencere uzunluğu değişkenliğini gösterir. Beşinci parametre, sinir ağı sonuçlarını içeren bir tablodur. 

MQL5 gösterge bölümünün, bir C# EncogNNTrainDLL.dll dosyasını içe aktarması ve dll'den dışa aktarılan initializeTrainedNN() ve computingNNIndicator() işlevlerini kullanması gerekir.

//+------------------------------------------------------------------+
//|                                         NeuralEncogIndicator.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 indicator_plots 1
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1  2

#import "EncogNNTrainDLL.dll"
   int initializeTrainedNN(string nnFile);
   int computeNNIndicator(double& ind1[], double& ind2[],double& ind3[], int size, double& result[], int rates);  
#import


int INPUT_WINDOW = 6;
int PREDICT_WINDOW = 1;

double ind1Arr[], ind2Arr[], ind3Arr[]; 
double neuralArr[];

int hStochastic;
int hWilliamsR;

int hNeuralMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, neuralArr, INDICATOR_DATA);
   
   PlotIndexSetInteger(0, PLOT_SHIFT, 1);

   ArrayResize(ind1Arr, INPUT_WINDOW);
   ArrayResize(ind2Arr, INPUT_WINDOW);
   ArrayResize(ind3Arr, INPUT_WINDOW);
     
   ArrayInitialize(neuralArr, 0.0);
   
   ArraySetAsSeries(ind1Arr, true);   
   ArraySetAsSeries(ind2Arr, true);  
   ArraySetAsSeries(ind3Arr, true);
  
   ArraySetAsSeries(neuralArr, true);   
               
   hStochastic = iStochastic(NULL, 0, 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   hWilliamsR = iWPR(NULL, 0, 21);
 
   Print(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
   initializeTrainedNN(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
      
//---
   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[])
  {
//---
   int calc_limit;
   
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
        calc_limit=rates_total-34; 
   else calc_limit=rates_total-prev_calculated;
    
   ArrayResize(neuralArr, rates_total);
  
   for (int i=0; i<calc_limit; i++)     
   {
      CopyBuffer(hStochastic, 0, i, INPUT_WINDOW, ind1Arr);
      CopyBuffer(hStochastic, 1, i, INPUT_WINDOW, ind2Arr);
      CopyBuffer(hWilliamsR,  0, i, INPUT_WINDOW, ind3Arr);    
      
      computeNNIndicator(ind1Arr, ind2Arr, ind3Arr, INPUT_WINDOW, neuralArr, rates_total-i); 
   }
     
  //Print("neuralArr[0] = " + neuralArr[0]);
  
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Lütfen USDCHF günlük verilerine dayalı eğitilen gösterge çıktılarını ve Stokastik ve Williams %R göstergelerine bakınız.

  Şekil 7. Sinirsel Encog göstergesi

Şekil 7. Sinirsel Encog göstergesi

Gösterge, bir sonraki çubukta tahmin edilen en iyi yatırım getirisini gösterir.

Gelecek kısmında göstergeyi bir çubuk değiştirdiğimi fark etmiş olabilirsiniz:

PlotIndexSetInteger(0, PLOT_SHIFT, 1);

Bu, göstergenin tahmin etme görevi olduğunu belirtmek içindir. Sinirsel göstergeyi oluşturduğumuzdan, bu göstergeye dayalı bir Expert Advisor oluşturmaya hazırız.


9. Sinirsel Göstergeye Dayalı Expert Advisor

Expert Advisor, sinirsel gösterge çıktısını alır ve bir menkul kıymeti alıp satma konusunda karar verir. İlk izlenimim şu yöndeydi, gösterge sıfırın üzerindeyken satın almalı ve sıfırın altındayken satmalı, yani belirli bir zaman aralığındaki en iyi getiri tahmini pozitif olduğunda alınmalı ve en iyi getiri tahmini negatif olduğunda satılmalı.

Yaptığım ilk testlerden sonra performansın daha iyi olabileceği ortaya çıktı, bu yüzden 'güçlü yükseliş trendi' ve 'güçlü düşüş trendi' değişkenlerini tanıttım, yani meşhur 'trend dostunuzdur’ kuralına göre güçlü bir trend olduğunda ticaretten çıkmak için hiçbir neden yok.

Ek olarak Heaton Research forumunda hareketli kayıp durdurma için ATR kullanmam tavsiye edildi, bu yüzden MQL5 forumunda bulduğum Chandelier ATR göstergesini kullandım. Geriye dönük testler sırasında öz sermaye kazancını gerçekten artırdı. Expert Advisor'ın kaynak kodunu aşağıya yapıştırıyorum.

//+------------------------------------------------------------------+
//|                                           NeuralEncogAdvisor.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

double neuralArr[];

double trend;
double Lots=0.3;

int INPUT_WINDOW=8;

int hNeural,hChandelier;

//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArrayResize(neuralArr,INPUT_WINDOW);
   ArraySetAsSeries(neuralArr,true);
   ArrayInitialize(neuralArr,0.0);

   hNeural=iCustom(Symbol(),Period(),"NeuralEncogIndicator");
   Print("hNeural = ",hNeural,"  error = ",GetLastError());

   if(hNeural<0)
     {
      Print("The creation of ENCOG indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("ENCOG indicator initialized");

   hChandelier=iCustom(Symbol(),Period(),"Chandelier");
   Print("hChandelier = ",hChandelier,"  error = ",GetLastError());

   if(hChandelier<0)
     {
      Print("The creation of Chandelier indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("Chandelier indicator initialized");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(),0,0,1,tickCnt);
   if(tickCnt[0]==1)
     {
      if(!CopyBuffer(hNeural,0,0,INPUT_WINDOW,neuralArr)) { Print("Copy1 error"); return; }

      // Print("neuralArr[0] = "+neuralArr[0]+"neuralArr[1] = "+neuralArr[1]+"neuralArr[2] = "+neuralArr[2]);
      trend=0;

      if(neuralArr[0]<0 && neuralArr[1]>0) trend=-1;
      if(neuralArr[0]>0 && neuralArr[1]<0) trend=1;

      Trade();
     }
  }
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---

//---
   return(0.0);
  }
//+------------------------------------------------------------------+

void Trade()
  {
   double bufChandelierUP[2];
   double bufChandelierDN[2];

   double bufMA[2];

   ArraySetAsSeries(bufChandelierUP,true);
   ArraySetAsSeries(bufChandelierUP,true);

   ArraySetAsSeries(bufMA,true);

   CopyBuffer(hChandelier,0,0,2,bufChandelierUP);
   CopyBuffer(hChandelier,1,0,2,bufChandelierDN);

   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,3,rates);

   bool strong_uptrend=neuralArr[0]>0 && neuralArr[1]>0 && neuralArr[2]>0 &&
                      neuralArr[3]>0 && neuralArr[4]>0 && neuralArr[5]>0 &&
                       neuralArr[6]>0 && neuralArr[7]>0;
   bool strong_downtrend=neuralArr[0]<0 && neuralArr[1]<0 && neuralArr[2]<0 &&
                        neuralArr[3]<0 && neuralArr[4]<0 && neuralArr[5]<0 &&
                        neuralArr[6]<0 && neuralArr[7]<0;

   if(PositionSelect(_Symbol))
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;

      if((type==POSITION_TYPE_BUY) && (trend==-1))

         if(!(strong_uptrend) || (bufChandelierUP[0]==EMPTY_VALUE)) close=true;
      if((type==POSITION_TYPE_SELL) && (trend==1))
         if(!(strong_downtrend) || (bufChandelierDN[0]==EMPTY_VALUE))
            close=true;
      if(close)
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
      else // adjust s/l
        {
         CTrade trade;

         if(copied>0)
           {
            if(type==POSITION_TYPE_BUY)
              {
               if(bufChandelierUP[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierUP[0],0.0);
              }
            if(type==POSITION_TYPE_SELL)
              {
               if(bufChandelierDN[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierDN[0],0.0);
              }
           }
        }
     }

   if((trend!=0) && (!PositionSelect(_Symbol)))
     {
      CTrade trade;
      MqlTick tick;
      MqlRates rates[];
      ArraySetAsSeries(rates,true);
      int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,INPUT_WINDOW,rates);

      if(copied>0)
        {
         if(SymbolInfoTick(_Symbol,tick)==true)
           {
            if(trend>0)
              {
               trade.Buy(Lots,_Symbol,tick.ask);
               Print("Buy at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
            if(trend<0)
              {
               trade.Sell(Lots,_Symbol,tick.bid);
               Print("Sell at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
           }
        }
     }

  }
//+------------------------------------------------------------------+

Expert Advisor, USDCHF para birimi D1 verileri kullanılarak çalıştırıldı. Verilerin yaklaşık %50'si eğitim örneğinden alınmıştı.


10. Expert Advisor’ın Geriye Dönük Test Sonuçları

Geriye dönük test sonuçlarını aşağıya yapıştırıyorum. Geriye dönük test 2000.01.01'den 2011.03.26'ya kadar yapılmıştır.

Şekil 8. Sinirsel Expert Advisor’ın geriye dönük test sonuçları

Şekil 8. Sinirsel Expert Advisor’ın geriye dönük test sonuçları

Şekil 9. Sinirsel Expert Advisor’ın Bakiye/Öz sermaye üzerine geriye dönük test grafiği

Şekil 9. Sinirsel Expert Advisor’ın Bakiye/Öz sermaye üzerine geriye dönük test grafiği

Lütfen bu performansın diğer zaman dilimleri ve diğer menkul kıymetler için tamamen farklı olabileceğini unutmayın.

Lütfen bu EA'yı eğitici olarak ele alın ve daha fazla araştırma için bir başlangıç noktası olarak kullanın. Benim kişisel görüşüm, ağın daha sağlam hale getirmek için belirli bir zaman diliminde yeniden eğitilebileceğidir, belki birileri bunu başarmak için iyi bir yol bulacaktır ve hatta belki çoktan bulmuştur. Belki de sinirsel bir göstergeye dayalı Al/Sat tahminleri yapmanın daha iyi bir yolu vardır. Okuyucuları bu konuda denemeler yapmaya teşvik ediyorum.


Sonuç

Aşağıdaki makalede, ENCOG makine öğrenimi çerçevesinin yardımıyla bu göstergeye dayalı bir sinirsel tahmin edici gösterge ve expert advisor oluşturmanın bir yolunu sundum. Tüm kaynak kod, derlenmiş ikili dosyalar, DLL'ler ve örnek bir eğitimli ağ makalede ek olarak verilmiştir.


".NET'te çift DLL kaydırma" nedeniyle Cloo.dll, encog-core-cs.dll ve log4net.dll dosyaları istemci terminalinin klasöründe bulunur.
EncogNNTrainDLL.dll dosyası \Terminal Data klasörü\MQL5\Libraries\ klasöründe bulunur.


MetaQuotes Ltd tarafından İngilizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/en/articles/252

Ekli dosyalar |
encogcsharp.zip (2202.77 KB)
files.zip (270.14 KB)
libraries.zip (321.62 KB)
experts.zip (1.56 KB)
scripts.zip (1.03 KB)
indicators.zip (2.24 KB)
Piyasa Fiyat Tahmini için Evrensel Regresyon Modeli Piyasa Fiyat Tahmini için Evrensel Regresyon Modeli
Piyasa fiyatı, sırayla çeşitli ekonomik, politik ve psikolojik faktörlere bağlı olan talep ve arz arasındaki istikrarlı bir dengeden oluşur. Doğadaki farklılıklar ve bu faktörlerin etki nedenleri, tüm bileşenlerin doğrudan ele alınmasını zorlaştırmaktadır. Bu makale, ayrıntılı bir regresyon modeli temelinde piyasa fiyatını tahmin etme girişimini ortaya koymaktadır.
MQL5 Sihirbazı: Risk ve Para Yönetimi Modülü Nasıl Oluşturulur MQL5 Sihirbazı: Risk ve Para Yönetimi Modülü Nasıl Oluşturulur
MQL5 Sihirbazının alım satım stratejileri üreticisi, alım satım fikirlerinin test edilmesini büyük ölçüde basitleştirir. Bu makale özel bir risk ve para yönetimi modülünün nasıl geliştirileceğini ve bunun MQL5 Sihirbazında nasıl etkinleştirileceğini açıklar. Örnek olarak, bu makalede alım satım hacminin boyutunun önceki işlemin sonuçlarına göre belirlendiği bir para yönetimi algoritmasını ele aldık. MQL5 Sihirbazı için oluşturulan sınıfın açıklamasının yapısı ve formatı da bu makalede tartışılmaktadır.
Yönetilmeyen dışa aktarmaları kullanarak C# kodunu MQL5'e gösterme Yönetilmeyen dışa aktarmaları kullanarak C# kodunu MQL5'e gösterme
Bu yazıda MQL5 kodu ile yönetilen C# kodu arasındaki etkileşimin farklı yöntemlerini sundum. Ayrıca MQL5 yapılarının C#'a karşı nasıl sıralanacağı ve MQL5 betiklerinde dışa aktarılan DLL işlevlerinin nasıl çağrılacağı konusunda da birkaç örnek sağladım. Sağlanan örneklerin, yönetilen kodda DLL yazma konusunda gelecekteki araştırmalar için bir temel oluşturabileceğine inanıyorum. Bu makale aynı zamanda MetaTrader'ın C#'da halihazırda uygulanmış olan birçok kütüphaneyi kullanmasına da kapı aralamaktadır.
MQL5'te Elektronik Tablolar MQL5'te Elektronik Tablolar
Bu makale ilk boyutunda farklı türde veriler içeren bir dinamik iki boyutlu dizi sınıfını açıklar. Verileri bir tablo biçiminde depolamak farklı türlerdeki bağımlı bilgilerle birçok düzenleme, depolama ve çalıştırma problemlerini çözmek için uygundur. Tablolarla çalışma fonksiyonunu uygulayan sınıfın kaynak kodu makaleye eklenmiştir.