Yeni Başlayanlar İçin Hızlı Başlangıç veya Kısa Kılavuz

Dmitriy Parfenovich | 9 Aralık, 2021

Giriş

Merhaba sevgili okuyucu! Bu yazıda, Uzman Danışmanlar (EA) oluşturma, göstergelerle çalışma vb. ilkeleri nasıl kolay ve hızlı bir şekilde kavrayabileceğinizi açıklamaya ve göstermeye çalışacağım. Bu, yeni başlayanlara yöneliktir ve zor veya anlaşılmaz örnekler içermeyecektir. Bu nedenle makale, Uzman Danışmanları (EA) nasıl programlayacağını zaten bilenleriniz için muhtemelen çok ilham verici ve bilgilendirici olmayabilir.

Uzman Danışman (EA) ve Yapısı

Uzman Danışman (EA), MQL dilinde yazılmış, alım satım yapmak veya bir kenarda tutmak için şartları belirten bir programdır.

Temel olarak, bir EA'nın yapısı çok sayıda bloktan oluşabilir, ancak daha kolay anlaşılması için MetaEditor'da varsayılan olarak oluşturulan çok basit bir örnek vereceğim.

Tüm EA görsel olarak her biri yapılacak işin belirli bir bölümünden sorumlu olan 4 bölüme ayrılabilir.

Ana EA blokları 
Şekil 1. Ana EA blokları

  1. Parametre Bloğu terminalin EA'yı uygun bir şekilde işlemesine izin veren bilgileri içerir. En yaygın parametreler EA versiyonu, üretim şirketinin adı ve kısa bir açıklamadır.

  2. OnInit() Bloğu EA terminale yüklendikten sonra kontrolü kazanır. EA'nın başlatılması, değişkenleri ve dizileri bildirme, gösterge tanıtıcılarını alma vb. ile ilgili çeşitli veriler içerebilir. Yani, bu blok, doğrudan alım satımla ilişkilendirilecek herhangi bir fonksiyona sahip değildir.

  3. OnDeinit() Bloğu, OnInit() Bloğunun tersi şekilde hareket eder. Bu, EA çalışmasını tamamladığında çağrılır (EA/Terminal kapatma veya bir EA'nın başlatılamaması). Bu bloğun ana fonksiyonlarından biri, artık ihtiyaç duyulmadığında EA tarafından kullanılan bellek alanının serbest bırakılmasıdır. Başka bir deyişle, değişkenleri, dizileri ve gösterge tanıtıcılarını vb. silme işlemlerini açıklar.

  4. OnTick() Bloğu, sunucudan sembol (para birimi çifti) üzerinde her yeni bilgi alındığında çağrılır. Alım satımı yapmak için koşulları ve alım satımın fonksiyonlarını belirtir.

MetaEditor'da varsayılan olarak oluşturulan yeni bir belge örneği
   Şekil 2. MetaEditor'da varsayılan olarak oluşturulan yeni bir belge örneği

Yukarıdaki örnekle açıklayayım. Daha sonra doldurulması gereken bir tür Uzman Danışman (EA) şablonu olan "boş" Uzman Danışman (EA) koduna sahibiz.
Burada görebildiğimiz şudur:

Daha önce söylediğim gibi, yapı çok daha karmaşık olabilir ve bu anlaşılması kolay örneğin aksine çok sayıda bloktan yapılabilir. Bunun yeterli olmadığını düşündüğünüzde kendi bloklarınızı ekleyebilirsiniz.
 

Göstergeler ve Bunların Nasıl İşleneceği

Göstergeler fiyat grafiğinde veya fiyat grafiğinin altında ayrı bir pencerede görüntülenen ve piyasanın teknik analizini yapmamızı sağlayan MQL ile yazılmış küçük programlardır.

Tüm göstergeler iki türde sınıflandırılabilir: trend takip eden göstergeler ve osilatörler.

Trend takip eden göstergeler, kural olarak, fiyat grafiğinde çizilir ve trend yönünü belirlemek için kullanılırken, osilatörler normalde fiyat grafiğinin altında görülebilir ve giriş noktalarını belirlemeye yarar.

Çoğu gösterge, belirli bir zamanda okuma verilerini içeren en az bir tampona (gösterge tamponu) sahiptir. Bir EA gibi, göstergenin de sembolü ve hesaplandığı zaman dilimi vardır.

Gösterge tamponu, son elemanı çalışan bir değer olan bir kuyruk olarak düşünülebilir.

Hareketli Ortalama Göstergesi Örneği
   Şekil 3. Hareketli Ortalama Göstergesi Örneği

Gösterge tamponu, birinci öğenin (0 indeksli) en sağdaki mumdaki verileri ve takip eden öğenin (1 indeksli) sağdaki ikinci mumdaki verileri vb. taşıdığı bir dizidir. Öğelerin bu şekilde düzenlenmesine zaman serisi denir.

Örneğe aşağıdaki gibi bir göz atın:
Elimizdeki para birimi çiftinin EUR/USD olduğunu, zaman diliminin 1 saat olduğunu varsayalım.
Öncelikle, göstergeyi EA'ya eklememiz ve tanıtıcısını almamız gerekiyor.

Tanıtıcı, bu göstergeyi programın herhangi bir yerinde ele almamızı sağlayan benzersiz bir göstergedir.

int iMA_handle; 
iMA_handle=iMA("EURUSD",PERIOD_H1,10,0,MODE_SMA,PRICE_CLOSE);
Daha yakından bakalım.

Birinci satır, gösterge tanıtıcısını depolayacak bir değişkeni tanımlar. İkinci satır göstergeyi çağırır (burada Hareketli Ortalama göstergesi), parametrelerini belirtir ve tanıtıcıyı ileride kullanmak üzere değişkene kaydeder.
MetaEditor'da "iMA(" yazdıktan sonra, bu satırın üzerinde virgülle ayrılmış gösterge çağrı parametrelerini gösteren bir araç ipucu görünecektir.

Hareketli Ortalama gösterge parametreleri için araç ipucu örneği
   Şekil 4. Hareketli Ortalama gösterge parametreleri için araç ipucu örneği

Aşağıdaki parametreleri soldan sağa listelenmiş şekilde görebiliriz:

  1. sembol adı (araç ipucunda kalın harflerle görünür) bir metin parametresidir, para birimi çiftidir (sembol);
  2. zaman dilimi;
  3. gösterge periyodu (burada ortalama periyot);
  4. N çubuk ileri/geri grafik kaydırma. Pozitif bir sayı, grafiğin N çubuk ileri kaymasını, negatif bir sayı ise grafiğin N çubuk geri kaymasını belirtir;
  5. ortalama alma yöntemi;
  6. uygulanan fiyat veya farklı bir göstergenin tanıtıcısı.

Her gösterge için benzersiz bir değişken seti ve türleri vardır. Bilinmeyen bir göstergeyle karşılaşırsanız, bununla ilgili bilgiler her zaman yerleşik Yardım bağlamında bulunabilir. Örneğin, iMA yazıp F1 tuşuna bastığınızda, bu belirli gösterge hakkında bilgi ve tüm özelliklerinin ayrıntılı bir açıklamasını sağlayan bir Yardım penceresi açılacaktır.

F1 tuşuna basarak göstergenin açıklaması için Yardım penceresinin çağrılması örneği
   Şekil 5. F1 tuşuna basarak göstergenin açıklaması için Yardım penceresinin çağrılması örneği

Kodu yazdıktan ve terminalde EA'yı başlattıktan sonra, (EA fiyat grafiğinin sağ üst köşesinde göründüğünde) göstergenin grafikte eksik olduğunu göreceğiz. Bu bir hata değildir - böyle tasarlanmıştı. Görünmesi için başka bir satır eklememiz gerekiyor:

ChartIndicatorAdd(ChartID(),0,iMA_handle);

Şimdi ne yaptığını görelim. İmleci ChartIndicatorAdd komutunun üzerine getirin ve komutun amacına ilişkin Yardım bilgilerini okumak için F1 tuşuna basın. Bu komutun şunu yaptığını söyler:

Belirtilen tanıtıcıya sahip bir göstergeyi belirtilen grafik alt penceresine ekler.

Sıfıra eşit olan ikinci parametre alt pencere numarasıdır. Alt pencereler genellikle fiyat grafiğinin altında osilatörler içerir. Unutmayın? Bunlardan çokça olabilir. Göstergeyi alt pencerede görüntülemek için, alt pencere numarasını, halihazırda var olan sayıdan 1, yani en son var olandan sonraki numara olacak şekilde belirtmeniz yeterlidir.

Kod satırını aşağıdaki gibi değiştirdikten sonra:

ChartIndicatorAdd(ChartID(),1,iMA_handle);

göstergemiz fiyat grafiğinin altındaki alt pencerede görünecektir.

Şimdi göstergeden bazı verileri almaya çalışmanın zamanı geldi. Bunun için dinamik bir dizi tanımlıyoruz, kolaylık olması açısından dizi indekslemeyi zaman serisi olarak düzenliyoruz ve gösterge değerlerini bu diziye kopyalıyoruz.

double iMA_buf[];
ArraySetAsSeries(iMA_buf,true);
CopyBuffer(iMA_handle,0,0,3,iMA_buf);

Yukarıdaki örnek, Hareketli Ortalama göstergesi fiyatlara dayalı olduğundan ve fiyatların kesirleri olduğundan, iMA_buf[] dinamik dizisini double türünde bildirdiğimizi göstermektedir.

Sonraki satır, dizi için indekslemeyi ayarlar, böylece daha küçük indekslere sahip öğeler daha eski değerleri depolarken, daha büyük indekslere sahip öğeler daha yeni değerleri depolar. Bu, tüm göstergelerdeki gösterge tamponları zaman serisi olarak indekslendiğinden, karışıklığı önlemek için kolaylık sağlamak üzere kullanılır.

Son satır, gösterge değerlerini iMA_buf[] dizisine kopyalamaya yarar. Bu veriler artık kullanıma hazırdır. 

 

Emirler, Alım Satımlar ve Pozisyonlar

Emirlerle başlayalım.

Piyasa emirleri, belirli bir finansal enstrümanın belirli bir miktarını mevcut piyasa fiyatından satma veya satın alma talimatlarını temsil eder.
Bekleyen emirler, belirli koşullara tabi olarak alım satım gerçekleştirilmesine yönelik talimatları temsil eder. Bekleyen emirlerin silindiği belirli bir sona erme süresi vardır.

Daha açık hale getirmek için, bir örnekle açıklayayım: 1 lotluk uzun bir pozisyon açıyoruz, yani mevcut piyasa fiyatından (örneğin) ve 1 lotluk bir emir veriyoruz. Talep geçerliyse, işlenmek üzere sunucuya gönderilir. İşlem tamamlanır tamamlanmaz, terminalin "Alım Satım" sekmesinde emir parametrelerine sahip bir pozisyon görünecektir. Daha sonra 1 lot büyüklüğünde başka bir uzun pozisyon açmaya karar verdiğimizi varsayalım. Emrin işlenmesini takiben, "Alım Satım" sekmesinde iki emir değil, 2 lot büyüklüğünde bir pozisyon göreceğiz. Yani pozisyon, bir dizi emrin yerine getirilmesinin sonucudur.

Şimdi uygulamaya geçelim. Talepte bulunmak için aşağıdaki yapı alanlarının doldurulması gerekir:

struct MqlTradeRequest
{
ENUM_TRADE_REQUEST_ACTIONS action; // Type of action
ulong magic; // Expert Advisor ID (magic number)
ulong order; // Order ticket
string symbol; // Trade instrument
double volume; // Requested trade size in lots
double price; // Price 
double stoplimit; // StopLimit level of the order
double sl; // Stop Loss level of the order
double tp; // Take Profit level of the order
ulong deviation; // Maximum allowed deviation from the requested price
ENUM_ORDER_TYPE type; // Order type
ENUM_ORDER_TYPE_FILLING type_filling; // Order type by execution
ENUM_ORDER_TYPE_TIME type_time; // Order type by duration
datetime expiration; // Order expiration time (for orders of the ORDER_TIME_SPECIFIED type)
string comment; // Comment to the order
};

Çeşitli emirler olduğu için her bir emir türünün kendi zorunlu parametreleri vardır. Bu alanlara uzun uzun değinmeyeceğim. Web sitesi bu konuda birçok bilgi sunmaktadır. Belirli bir emir türü için zorunlu parametrelerden biri bile belirtilmemişse veya yanlış belirtilmişse, talep başarısız olacaktır.

Yukarıdaki yapı, yalnızca doldurulurken ortaya çıkan zorluğu daha iyi göstermek için burada düzenlenmiştir.

Zararı Durdur ve Kar Al

Zarar Durdur ve Kar Al, "geri çekilme önlemi" olarak verilen özel emirlerdir. Yani, Uzman Danışman (EA) tarafından açılan ve zarar gösteren bir pozisyon olması durumunda, Zararı Durdur emri, zararları önceden tanımlanmış belirli bir seviyede sınırlayabilir.

Kar Al benzer şekilde hareket eder, bu durumda sadece karı sınırlar. Bir pozisyonu kapatma konusunda endişelenmeyi bırakmak gerekebilir. Bu, belli bir fiyat seviyesine ulaştığında kapanacaktır. Başka bir deyişle, bu emirler, piyasa aleyhimize dönerse veya biz kar etmek istersek, bizim "sigorta planımızı" temsil eder.

Bu tür emirler tek başına ayrı olarak verilemez - sadece mevcut pozisyonları değiştirebilir.

Standart Kitaplıkları Kullanma

Sonunda Standart Kitaplığa ulaştık. Bu kitaplık terminal ile birlikte gelir, dolayısıyla adı Standart Kitaplıktır. EA'ların programlanmasını kolaylaştıran ve kısmen karmaşık işlemleri üstlenen, örneğin alım satım talebi oluşturma gibi fonksiyonlar içerir.

Alım satım kitaplıkları (ayrıca alım satım sınıflarına bakın) aşağıdaki yolda bulunur: Include\Trade\ ve #include direktifi kullanılarak eklenebilir.
Örnek:

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>

Uzman Danışmanların (EA) çoğunluğu sadece bu iki sınıf (kitaplık) kullanılarak programlanabileceği için, yukarıdaki sınıflar temel sınıflar olarak kabul edilebilir. Ben bunlara kitaplıklar diyorum:


Bazen başka bir kitaplık yararlı olabilir:
#include <Trade\OrderInfo.mqh>
Örneğin, stratejimiz bekleyen emirlerin kullanılmasını gerektiriyorsa, emirlerle çalışmak için fonksiyonlar içerir.

Bilginin doğru kullanılmasını gerektiren çeşitli parametrelerle dolu alım satım talebi yapısını hatırlıyor musunuz?
Şimdi size kitaplık kullanılarak yapılan bir alım satım talebi örneğini vereceğim:
CTrade m_Trade;
m_Trade.Sell(lot,symbol_name,price,sl,tp,comment);

Burada sadece biri zorunlu olan toplam 6 parametre vardır (emir boyutu - bu birinci parametredir).
Şimdi her birini belirteceğim:

Bir pozisyonu kapatmanın birkaç yolu vardır:

  1. tüm pozisyonu kapatmak için
    CPositionInfo m_Position;
    m_Position.Select(symbol_name);
    m_Trade.PositionClose(symbol_name);
  2. aynı boyutta ters emir vererek pozisyonu kapatmak için
    CTrade m_Trade;
    m_Trade.Buy(lot,symbol_name,price,sl,tp,comment);
  3. daha karmaşık bir yöntem kullanarak, tüm açık pozisyonlar, daha sonra kapatılacak gerekli parametreleri (sembol, tip, sihirli sayı, pozisyon tanımlayıcı vb.) karşılayanı seçmek için ilk önce aranır.
    Yeni başlayanlar için zorluğundan dolayı yukarıdakilere herhangi bir örnek vermeyeceğim.

Hepsini Bir Araya Getirme

Artık yeni edinilen bilgileri tek bir Uzman Danışmana (EA) koymanın tam zamanı.

//+------------------------------------------------------------------+
//|                                           fast-start-example.mq5 |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>                                         //include the library for execution of trades
#include <Trade\PositionInfo.mqh>                                  //include the library for obtaining information on positions

int               iMA_handle;                              //variable for storing the indicator handle
double            iMA_buf[];                               //dynamic array for storing indicator values
double            Close_buf[];                             //dynamic array for storing the closing price of each bar

string            my_symbol;                               //variable for storing the symbol
ENUM_TIMEFRAMES   my_timeframe;                             //variable for storing the time frame

CTrade            m_Trade;                                 //structure for execution of trades
CPositionInfo     m_Position;                              //structure for obtaining information of positions
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   my_symbol=Symbol();                                      //save the current chart symbol for further operation of the EA on this very symbol
   my_timeframe=PERIOD_CURRENT;                              //save the current time frame of the chart for further operation of the EA on this very time frame
   iMA_handle=iMA(my_symbol,my_timeframe,40,0,MODE_SMA,PRICE_CLOSE);  //apply the indicator and get its handle
   if(iMA_handle==INVALID_HANDLE)                            //check the availability of the indicator handle
   {
      Print("Failed to get the indicator handle");              //if the handle is not obtained, print the relevant error message into the log file
      return(-1);                                           //complete handling the error
   }
   ChartIndicatorAdd(ChartID(),0,iMA_handle);                  //add the indicator to the price chart
   ArraySetAsSeries(iMA_buf,true);                            //set iMA_buf array indexing as time series
   ArraySetAsSeries(Close_buf,true);                          //set Close_buf array indexing as time series
   return(0);                                               //return 0, initialization complete
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(iMA_handle);                             //deletes the indicator handle and deallocates the memory space it occupies
   ArrayFree(iMA_buf);                                      //free the dynamic array iMA_buf of data
   ArrayFree(Close_buf);                                    //free the dynamic array Close_buf of data
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   int err1=0;                                             //variable for storing the results of working with the indicator buffer
   int err2=0;                                             //variable for storing the results of working with the price chart
   
   err1=CopyBuffer(iMA_handle,0,1,2,iMA_buf);               //copy data from the indicator array into the dynamic array iMA_buf for further work with them
   err2=CopyClose(my_symbol,my_timeframe,1,2,Close_buf);    //copy the price chart data into the dynamic array Close_buf for further work with them
   if(err1<0 || err2<0)                                    //in case of errors
   {
      Print("Failed to copy data from the indicator buffer or price chart buffer");  //then print the relevant error message into the log file
      return;                                                               //and exit the function
   }

   if(iMA_buf[1]>Close_buf[1] && iMA_buf[0]<Close_buf[0])   //if the indicator values were greater than the closing price and became smaller
     {
      if(m_Position.Select(my_symbol))                     //if the position for this symbol already exists
        {
         if(m_Position.PositionType()==POSITION_TYPE_SELL) m_Trade.PositionClose(my_symbol);  //and this is a Sell position, then close it
         if(m_Position.PositionType()==POSITION_TYPE_BUY) return;                              //or else, if this is a Buy position, then exit
        }
      m_Trade.Buy(0.1,my_symbol);                          //if we got here, it means there is no position; then we open it
     }
   if(iMA_buf[1]<Close_buf[1] && iMA_buf[0]>Close_buf[0])  //if the indicator values were less than the closing price and became greater
     {
      if(m_Position.Select(my_symbol))                     //if the position for this symbol already exists
        {
         if(m_Position.PositionType()==POSITION_TYPE_BUY) m_Trade.PositionClose(my_symbol);   //and this is a Buy position, then close it
         if(m_Position.PositionType()==POSITION_TYPE_SELL) return;                             //or else, if this is a Sell position, then exit
        }
      m_Trade.Sell(0.1,my_symbol);                         //if we got here, it means there is no position; then we open it
     }
  }
//+------------------------------------------------------------------+

Uzman Danışmanımızı (EA) aşağıdaki parametrelerle test edelim:

Birinci çubuktan başlayan gösterge değerlerini ve kapanış fiyatlarını kullandığımız için (sıfır çubuk güncel, aktif bir çubuktur), grafik yeniden çizilmeyecektir. Bu, "Yalnızca açılış fiyatları" alım satım modunu kullanabileceğimiz anlamına gelir. Bu, test kalitesini etkilemeyecek ancak daha hızlı çalışmasını sağlayacaktır.

Ve işte geçmiş verileri kullanan hızlı test sonuçları. 

Uzman Danışman test sonuçlarımız
   Şekil 6. Uzman Danışman test sonuçlarımız

Dezavantajlar kesinlikle gözden kaçmaz. Ancak bu makale, minimum düşüşle büyük kar potansiyeline sahip olacak bir "süper Uzman Danışman (EA)" programlamayı amaçlamamış, bunun yerine temel bilgilerle donanmış bir EA'nın ne kadar kolay yapılabileceğini göstermeyi amaçlamıştır.
Yüz satırdan daha az koddan oluşan Uzman Danışmanımız (EA) var.
 

Sonuç

Bu makale, bir EA'yı programlarken göz önünde bulundurulması gereken ana ilkeleri kapsamaktadır. Çeşitli fonksiyonlar hakkında bilgi almak için MetaEditor 5'teki yerleşik bağlam Yardımını nasıl kullanacağımızı öğrendik, genel emirler ve pozisyonlar hakkında fikir sahibi olduk ve standart kitaplıkların kullanımını benimsedik.