English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
HedgeTerminal API'sini Kullanarak MetaTrader 5'te İki Yönlü Alım Satım ve Pozisyonların Korunması, Bölüm 2

HedgeTerminal API'sini Kullanarak MetaTrader 5'te İki Yönlü Alım Satım ve Pozisyonların Korunması, Bölüm 2

MetaTrader 5Ticaret sistemleri | 14 Ocak 2022, 13:33
292 0
Vasiliy Sokolov
Vasiliy Sokolov

İçerik Tablosu


Giriş

Bu makale, "MetaTrader 5 HedgeTerminal Panelini Kullanarak İki Yönlü Alım Satım ve Pozisyonların Korunması, Bölüm 1" birinci bölümün devamı niteliğindedir. İkinci bölümde Expert Advisor'lar ve diğer MQL5 programlarının HedgeTerminalAPI kütüphanesi ile entegrasyonunu ele alacağız. Kütüphaneyle nasıl çalışılacağını öğrenmek için bu makaleyi okuyun. Rahat ve basit bir alım satım ortamında çalışmaya devam ederken, iki yönlü alım satım Expert Advisor'ları oluşturmanıza yardımcı olacaktır.

Kitaplık açıklamasına ek olarak, makale eşzamansız alım satım ve çok kanallı programlamanın temellerine değiniyor. Bu açıklamalar bu makalenin üçüncü ve dördüncü bölümlerinde verilmiştir. Bu nedenle, bu materyal, çift yönlü alım satımla ilgilenmeyen ancak eşzamansız ve çok kanallı programlama hakkında yeni bir şeyler öğrenmek isteyen yatırımcılar için faydalı olacaktır.

Aşağıda sunulan materyal, MQL5 programlama dilini bilen deneyimli algoritmik yatırımcılara yöneliktir. MQL5'i bilmiyorsanız lütfen kitaplığın ve HedgeTerminal panelinin genel prensibini açıklayan basit diyagramlar ve çizimler içeren makalenin ilk bölümünü okuyun.


Bölüm 1. Expert Advisor'ların HedgeTerminal ve paneli ile Etkileşimi

1.1. HedgeTermianlAPI kurulumu. Kütüphanenin İlk Başlangıcı

HedgeTerminalAPI kurulum süreci, HT görsel panelinin kurulumundan farklıdır çünkü kitaplık MetaTrader 5'te tek başına çalışamaz. Bunun yerine, kitaplıktan HedgeTerminalInstall() işlevini çağırmak için özel bir Expert Advisor geliştirmeniz gerekir. Bu işlev, HedgeTerminalAPI'de bulunan işlevleri açıklayan özel bir başlık dosyası Prototypes.mqh ayarlayacaktır.

Bir bilgisayara üç adımda bir kitaplık kurulur:

Adım 1. HedgeTerminalAPI kitaplığını bilgisayarınıza indirin. Terminalinize göre kitaplık konumu: \MQL5\Experts\Market\HedgeTerminalApi.ex5.

Adım 2. Standart bir şablon kullanarak MQL5 Sihirbazında yeni bir Expert Advisor oluşturun. MQL5 Sihirbazı aşağıdaki kaynak kodunu oluşturur:

//+------------------------------------------------------------------+
//|                                   InstallHedgeTerminalExpert.mq5 |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }

Adım 3. Ortaya çıkan Expert Advisor'ın yalnızca bir işlevine - OnInit() ve HedgeTerminalApi kitaplığı tarafından dışa aktarılan HedgeTerminalInstall() özel yükleyici işlevini açıklayan dışa aktarma yönergesine ihtiyacınız olacak. Bu işlevi, doğrudan OnInit() işlevinde çalıştırın. Sarı ile işaretlenmiş kaynak kodu şu işlemleri gerçekleştirir:

//+------------------------------------------------------------------+
//|                                   InstallHedgeTerminalExpert.mq5 |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#import "HedgeTerminalAPI.ex5"
   void HedgeTerminalInstall(void);
#import

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   HedgeTerminalInstall();
   ExpertRemove();   
//---
   return(INIT_SUCCEEDED);
  }

Adım 4. Diğer eylemleriniz kitaplığı satın alıp almadığınıza bağlıdır. Satın aldıysanız Expert Advisor'ı doğrudan grafik üzerinde gerçek zamanlı olarak çalıştırabilirsiniz. Bu, HedgeTerminal'in tüm ürün serisinin standart yükleyicisini başlatacaktır. Bu adımı, "HedgeTerminal Panelini Kullanarak MetaTrader 5'te İki Yönlü Alım Satım ve Pozisyonların Korunması, Bölüm 1" makalesinin 2.1 ve 2.2 bölümlerinde açıklanan talimatları izleyerek kolayca tamamlayabilirsiniz. Kurulum sihirbazı, başlık dosyası ve test Expert Advisor dahil olmak üzere gerekli tüm dosyaları bilgisayarınıza yükler.

Kitaplığı satın almadıysanız ve yalnızca test etmek istiyorsanız gerçek zamanlı olarak EA işlemi sizin için geçerli olmayacaktır, ancak strateji test cihazında EA'yı çalıştırarak API'yi test edebilirsiniz. Bu durumda yükleyici çalışmayacaktır. Test modunda, HedgeTermianalAPI tek kullanıcı modunda çalışır, bu nedenle normal modda yüklü dosyalara ihtiyaç duymaz. Bu, başka bir yapılandırmaya gerek olmadığı anlamına gelir.

EA testi yapılır yapılmaz, terminalin ortak klasöründe \HedgeTerminal klasörü oluşturulur. MetaTrader terminallerinin ortak dizinine giden normal yol c:\Users\<Username>\AppData\Roaming\MetaQuotes\Terminal\Common\Files\HedgeTerminal\ şeklindedir, burada <Username> mevcut bilgisayar hesabınızın adıdır. \HedgeTerminal klasörü zaten \MQL5\Include\Prototypes.mqh ve \MQL5\Experts\Chaos2.mq5 dosyalarını içerir. Bu dosyaları terminalinizin aynı dizinlerine kopyalayın: Prototypes.mqh dosyasını {\MetaTrader5\MQL5\Include dizinine ve Chaos2.mq5 dosyasını \MetaTrader5\MQL5\Experts dizinine kopyalayın.

Prototypes.mqh dosyası, HedgeTerminalAPI kitaplığından dışa aktarılan işlevlerin açıklamasını içeren bir başlık dosyasıdır. Amaçları ve açıklamaları onlara yapılan yorumlarda yer almaktadır.

Chaos2.mq5 dosyası, "Chaos II EA Örneği Üzerinden SendTradeRequest İşlevi ve HedgeTradeRequest Yapısı" bölümünde açıklanan bir örnek EA içerir. Bu şekilde HedgeTerminalAPI'nin nasıl çalıştığını ve HedgeTerminal'in sanallaştırma teknolojisini kullanan bir Expert Advisor'ın nasıl geliştirileceğini görsel olarak anlayabilirsiniz.

Kopyalanan dosyalar EA'larınız için kullanılabilir. Bu nedenle, kitaplığı kullanmaya başlamak için yalnızca başlık dosyasını Expert Advisor kaynak koduna eklemeniz gerekir. Bir örnek:

#include <Prototypes.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int transTotal = TransactionsTotal();
   printf((string)transTotal);
  }

Örneğin yukarıdaki kod toplam etkin pozisyon sayısını alır ve sayıyı MetaTrader 5 terminalinin "Expert'ler" sekmesinde görüntüler.

HedgeTerminal öğesinin işlevlerinden birinin ilk çağrısında gerçekten başlatıldığını anlamak önemlidir. Bu başlatmaya lazy denir. Bu nedenle, işlevlerinden birinin ilk çağrısı uzun sürebilir. İlk çalıştırma sırasında hızlı bir yanıt istiyorsanız HT'yi önceden başlatmanız gerekir, örneğin OnInit() bloğundaki TransactionTotal() işlevini çağırabilirsiniz.

Tembel başlatma ile Expert Advisor'ın açık başlatmasını atlayabilirsiniz. Bu, HedgeTerminal ile çalışmayı büyük ölçüde basitleştirir ve önceden yapılandırmayı gereksiz kılar.


1.2. HedgeTerminal Paneli ile Expert Advisors Entegrasyonu

HedgeTerminal görsel paneline ve kitaplığın gerçek zamanlı olarak çalıştırılabilen tam özellikli versiyonuna sahipseniz Expert Advisor'larınızı panel ile entegre ederek gerçekleştirdiği tüm alım satım işlemlerinin panelde görünmesini sağlayabilirsiniz. Genel olarak, entegrasyon görünmez. HedgeTermianalAPI fonksiyonlarını kullanırsanız robotlar tarafından gerçekleştirilen işlemler panelde otomatik olarak görüntülenir. Ancak taahhüt edilen her işlemde EA adını belirterek görselliği genişletebilirsiniz. Settings.xml dosyasındaki aşağıdaki satırı yorumdan kaldırarak bunu yapabilirsiniz:

<Column ID="Magic" Name="Magic" Width="100"/>

Bu etiket, <Etkin-Pozisyon> ve <Geçmiş-Pozisyon> bölümlerindedir.

Artık yorumlar kaldırıldı ve etiketler işlemeye dahil edildi. Panel yeniden başlatıldıktan sonra, etkin ve geçmiş pozisyonların tablolarında "Magic" yeni sütunu görünecektir. Sütun, pozisyonun ait olduğu Expert Advisor'ın sihirli numarasını içerir.

Sihirli numarası yerine EA adını göstermek istiyorsanız adı ExpertAliases.xml diğer ad dosyasına ekleyin. Örneğin bir EA'nın sihirli numarası 123847'dir ve adını "ExPro 1.1" gibi görüntülemek istiyorsanız dosyaya aşağıdaki etiketi ekleyin:

<Expert Magic="123847" Name="ExPro 1.1"></Expert>

Doğru yapılırsa uygun sütunda sihri yerine EA adı görüntülenecektir:

Şek. 1.  Magic yerine EA adını görüntüleme

Şek. 1. Magic yerine EA adını görüntüleme

Panelin ve Expert Advisor'ların gerçek zamanlı olarak iletişim kurduğunu unutmayın. Bu, bir EA'nın pozisyonunu doğrudan panelde kapatırsanız EA'nın bunu TransactionsTotal() işlevinin sonraki çağrısıyla öğreneceği anlamına gelir. Tam tersi de geçerlidir: Expert Advisor pozisyonunu kapattıktan sonra etkin pozisyonlar sekmesinden hemen kaybolur.


1.3. HedgeTerminalAPI İşletimi Genel İlkeleri

HedgeTerminal, çift yönlü pozisyonlara ek olarak, bekleyen talimatlar, yatırımlar ve komisyoncu işlemleri gibi diğer alım satım türleriyle de çalışır. HedgeTerminal, tüm bu türleri tek bir işlem grubu olarak ele alır. Bir yatırım, bekleyen bir talimat, çift yönlü bir pozisyon: bunların hepsi işlemdir. Ancak, bir işlem tek başına var olamaz. Nesne yönelimli programlama açısından, bir işlem, yatırımlar ve çift yönlü pozisyonlar gibi tüm olası alım satım varlıkların miras alındığı soyut bir temel sınıf olarak tanıtılabilir. Bu bağlamda HedgeTerminalAPI'nin tüm işlevleri birkaç gruba ayrılabilir:

  1. İşlem arama ve seçim işlevleri. İşlevlerin ortak imzası ve çalışma biçimleri, MetaTrader 4'teki OrderSend() ve OrderSelect() işlevleriyle neredeyse tamamen örtüşüyor;
  2. Seçili bir işlemin özelliklerini almak için işlevler. Her işlemin belirli bir dizi özelliği ve özellik seçimi için belirli işlevleri vardır. Fonksiyonların ortak imzası ve çalışma şekilleri, pozisyonlara, yatırımlara ve talimatlara (OrderGetDouble() veya HistoryDealGetInteger() gibi) erişimlerinde MetaTrader 5 sistem işlevlerine benzer;
  3. HedgeTerminalAPI yalnızca bir alım satım işlevi kullanır: SendTradeRequest(). Bu işlev, çift yönlü bir pozisyonun veya bunun bir kısmının kapatılmasına izin verir. Aynı işlev zararı durdur, kar al veya giden yorumu değiştirmek için kullanılır. İşlevle çalışmak, MetaTrader 5'teki OrderSend() işlevine benzer;
  4. Yaygın hataları alma işlevi GetHedgeError(), HedgeTerminal alım satım işlemlerinin ayrıntılı analizi için işlevler: TotalActionsTask() ve GetActionResult(). Ayrıca hata tespiti için kullanılır. MetaTrader 4 veya MetaTrader 5'te analog yoktur.

Hemen hemen tüm işlevlerle çalışmak, MetaTrader 4 ve MetaTrader 5 sistem işlevlerini kullanmaya benzer. Kural olarak, işlev girişi bir tanımlayıcıdır (numaralandırma değeri) ve işlev buna karşılık gelen bir değer verir.

Her fonksiyon için özel numaralandırmalar mevcuttur. Ortak çağrı imzası aşağıdaki gibidir:

<value> = Function(<identifier>);

Benzersiz bir pozisyon tanımlayıcısı alma örneğini ele alalım. MetaTrader 5'te çizgi şu şekilde görünüyor:

ulong id = PositionGetInteger(POSITION_IDENTIFIER);

HedgeTerminal'de iki yönlü bir pozisyonun benzersiz tanımlayıcısını almak aşağıdaki gibidir:

ulong id = HedgePositionGetInteger(HEDGE_POSITION_ENTRY_ORDER_ID)

Fonksiyonların genel prensipleri aynıdır. Yalnızca numaralandırma türleri farklıdır.


1.4. İşlemleri Seçme

Bir işlem seçmek, MetaTrader 4'te talimat aramaya benzer şekilde işlem listesinden geçiyor. Ancak MetaTrader 4'te yalnızca talimatlar aranırken, HedgeTerminal'de bekleyen bir talimat veya riskten korunma pozisyonu gibi herhangi bir şey işlem olarak bulunabilir. Bu nedenle, her işlem önce TransactionSelect() işlevi kullanılarak seçilmeli ve ardından türü TransactionType() aracılığıyla tanımlanmalıdır.

Bugüne kadar iki işlem listesi mevcuttur: etkin ve geçmiş işlemler. Uygulanacak liste, ENUM_MODE_TRADES değiştiricisine göre tanımlanır. MetaTrader 4'teki MODE_TRADES değiştiricisine benzer.

İşlem arama ve seçim algoritması aşağıdaki gibidir:

1: for(int i=TransactionsTotal(MODE_TRADES)-1; i>=0; i--)
2:     {
3:      if(!TransactionSelect(i,SELECT_BY_POS,MODE_TRADES))continue;
4:      if(TransactionType()!=TRANS_HEDGE_POSITION)continue;
5:      if(HedgePositionGetInteger(HEDGE_POSITION_MAGIC) != Magic)continue;
6:      if(HedgePositionGetString(HEDGE_POSITION_SYMBOL) != Symbol())continue;
7:      if(HedgePositionGetInteger(HEDGE_POSITION_STATE) == POSITION_STATE_FROZEN)continue;
8:      ulong id = HedgePositionGetInteger(HEDGE_POSITION_ENTRY_ORDER_ID)
9:     }

Kod, için (satır 1) döngüsündeki etkin işlemler listesinde döngüye girer. İşleme devam etmeden önce, TransactionSelect() (satır 3) kullanarak işlemi seçin. Bu işlemlerden sadece çift yönlü pozisyonlar seçilir (satır 4). Konumun sihirli numarası ve sembolü, mevcut EA'nın sihirli numarası ve üzerinde çalıştığı sembolle eşleşmiyorsa HT bir sonraki pozisyona geçer (satır 5 ve 6). Ardından benzersiz pozisyon tanımlayıcısını tanımlar (satır 8).

Satır 7'ye özellikle dikkat edilmelidir. Seçilen pozisyonlar değişiklik imkanı açısından kontrol edilmelidir. Pozisyon zaten değişiklik sürecindeyse özelliklerinden birini alabilmenize rağmen mevcut iş parçacığında değiştirilemez. Pozisyon kilitliyse özelliklerine erişmek için serbest bırakılana kadar bekleyin veya bunu değiştirmeyi yeniden deneyin. HEDGE_POSITION_STATE özelliği, pozisyon değişikliğinin mümkün olup olmadığını öğrenmek için kullanılır.

POSITION_STATE_FROZEN değiştiricisi, pozisyonun "donmuş" olduğunu ve değiştirilemeyeceğini belirtir. POSITION_STATE_ACTIVE değiştiricisi, bir pozisyonun etkin olduğunu ve değiştirilebileceğini gösterir. Bu değiştiriciler, uygun bölümde belgelenen ENUM_HEDGE_POSITION_STATE numaralandırmasında listelenmiştir.

Geçmiş işlemlerde arama yapılması gerekiyorsa TransactionTotal() ve TransactionSelect() işlevlerindeki MODE_TRADES değiştiricisi MODE_HISTORY ile değiştirilmelidir.

HedgeTerminal'deki bir işlem diğerine yuvalanabilir. Bu, iç içe geçmenin olmadığı MetaTrader 5 konseptinden çok farklıdır. Örneğin HedgeTerminal'deki geçmiş çift yönlü pozisyon, her biri rastgele bir yatırım kümesi içeren iki talimattan oluşur. Yuvalama aşağıdaki gibi temsil edilebilir:

Şek. 2. Yuvalanmış işlemler

Şek. 2. Yuvalanmış işlemler

HedgeTerminal görsel panelinde işlemlerin yuvalanması açıkça görülmektedir.

Aşağıdaki ekran görüntüsü, MagicEx 1.3'ün bir pozisyonun ayrıntılarını gösterir:

Şek. 3. HedgeTerminal panelinde iç içe geçmiş işlemler

Şek. 3. HedgeTerminal panelinde yuvalanmış işlemler

Belirli bir talimatın veya yatırımın özelliklerine çift yönlü pozisyonda erişebilirsiniz.

Bunu yapmak için:

  1. Geçmiş bir işlem seçin ve bunun çift yönlü bir pozisyon olduğundan emin olun;
  2. HedgeOrderSelect() kullanarak bu pozisyonun talimatlarından birini seçin;
  3. Seçilen talimatın özelliklerinden birini alın: içerdiği yatırım sayısı;
  4. Tüm yatırımlar arasında arama yaparak talimata ait yatırımlardan birini seçin;
  5. Gerekli yatırım özelliğini alın.

İşlem seçildikten sonra, belirli özelliklerinin kendisine uygun hale geldiğini unutmayın. Örneğin, işlem bir talimat ise HedgeOrderSelect() üzerinden seçim yaptıktan sonra, işlem sayısını (HedgeOrderGetInter(HEDGE_ORDER_DEALS_TOTAL)) veya ağırlıklı ortalama giriş fiyatını (HedgeDealGetDouble(HEDGE_DEAL_PRICE_EXECUTED)) bulabilirsiniz.

Ekran görüntüsünde kırmızı ile işaretlenmiş #1197610 yatırımının fiyatını öğrenelim. Bu yatırım, MagicEx 1.3 EA'nın çift yönlü pozisyonunun bir parçasıdır.

Aşağıdaki kod aracılığıyla, EA pozisyonuna ve bu yatırıma erişebilir:

#include <Prototypes.mqh>

ulong Magic=5760655; // MagicEx 1.3.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+ 
void OnTick()
  {
   for(int i=TransactionsTotal(MODE_HISTORY)-1; i>=0; i--)
    {
      if(!TransactionSelect(i,SELECT_BY_POS,MODE_HISTORY))continue;        // Select transaction #i;
      if(TransactionType()!=TRANS_HEDGE_POSITION)continue;                 // If transaction is not position - continue;
      if(HedgePositionGetInteger(HEDGE_POSITION_MAGIC) != Magic)continue;  // If position is not main - continue;
      ulong id = HedgePositionGetInteger(HEDGE_POSITION_ENTRY_ORDER_ID);   // Get id for closed order;
      if(id!=5917888)continue;                                             // If id of position != 5917888 - continue;
      printf("1: -> Select position #"+(string)id);                        // Print position id;
      if(!HedgeOrderSelect(ORDER_SELECTED_CLOSED))continue;                // Select closed order or continue;    
      ulong order_id = HedgeOrderGetInteger(HEDGE_ORDER_ID);               // Get id closed order;
      printf("2: ----> Select order #" + (string)order_id);                // Print id closed order;
      int deals_total = (int)HedgeOrderGetInteger(HEDGE_ORDER_DEALS_TOTAL);// Get deals total in selected order;
      for(int deal_index = deals_total-1; deal_index >= 0; deal_index--)   // Search deal #1197610...
        {
         if(!HedgeDealSelect(deal_index))continue;                         // Select deal by index or continue;
         ulong deal_id = HedgeDealGetInteger(HEDGE_DEAL_ID);               // Get id for current deal;
         if(deal_id != 1197610)continue;                                   // Select deal #1197610;
         double price = HedgeDealGetDouble(HEDGE_DEAL_PRICE_EXECUTED);     // Get price executed;
         printf("3: --------> Select deal #"+(string)deal_id+              // Print price excecuted;
              ". Executed price = "+DoubleToString(price,0));
        }
     }
  }

Kod yürütüldükten sonra MetaTrader 5 terminalinin Expert sekmesinde aşağıdaki giriş oluşturulacaktır:

2014.10.21 14:46:37.545 MagicEx1.3 (VTBR-12.14,D1)      3: --------> Select deal #1197610. Executed price = 4735
2014.10.21 14:46:37.545 MagicEx1.3 (VTBR-12.14,D1)      2: ----> Select order #6389111
2014.10.21 14:46:37.545 MagicEx1.3 (VTBR-12.14,D1)      1: -> Select position #5917888

EA önce #5917888 pozisyonunu seçer ve ardından pozisyonun içinde #6389111 talimatını seçer. Talimat seçildikten sonra EA, 1197610 yatırım numarasını aramaya başlar. Yatırım bulunduğunda, EA yürütme fiyatını alır ve fiyatı günlüğe ekler.


1.5. GetHedgeError() Kullanılarak Hata Kodları Nasıl Alınır

HedgeTerminal ortamı ile çalışırken hatalar ve öngörülemeyen durumlar meydana gelebilir. Bu durumlarda hata alma ve analiz etme işlevleri kullanılır.

Bir hata aldığınızdaki en basit durum, TransactionSelect() işlevini kullanarak bir işlem seçmeyi unutmanızdır. TransactionType() işlevi, bu durumda TRANS_NOT_DEFINED değiştiricisini verir.

Sorunun nerede olduğunu anlamak için son hatanın değiştiricisini almamız gerekiyor. Değiştirici bize şimdi işlemin seçildiğini söyleyecektir. Aşağıdaki kod bunu yapar:

for(int i=TransactionsTotal(MODE_HISTORY)-1; i>=0; i--)
  {
   //if(!TransactionSelect(i,SELECT_BY_POS,MODE_HISTORY))continue;        // forgot to select;
   ENUM_TRANS_TYPE type = TransactionType();
   if(type == TRANS_NOT_DEFINED)
   {
      ENUM_HEDGE_ERR error = GetHedgeError();
      printf("Error, transaction type not defined. Reason: " + EnumToString(error));
   }
  }

Bu sonuçta ortaya çıkan mesajdır:

Error, transaction type not defined. Reason: HEDGE_ERR_TRANS_NOTSELECTED

Hata kimliği, türünü almaya çalışmadan önce bir işlem seçmeyi unuttuğumuzu gösteriyor.

Tüm olası hatalar ENUM_HEDGE_ERR yapısında listelenmiştir.


1.6. TotalActionsTask() ve GetActionResult() Kullanılarak Alım Satım İşlemlerinin Ayrıntılı Analizi ve Hataların Tanımlanması

HedgeTerminal ortamı ile çalışma sürecinde meydana gelen hatalara ek olarak SendTradeRequest() çağrısı sonucunda alım satım hataları meydana gelebilir. Bu tür hataların üstesinden gelmek daha zordur. SendTradeRequest() tarafından gerçekleştirilen bir görev, birden fazla alım satım faaliyeti (alt görevler) içerebilir. Örneğin zararı durdurma seviyesi tarafından korunan etkin bir pozisyonda giden yorumu değiştirmek için iki işlem yapmanız gerekir:

  1. Durdurma seviyesini temsil eden bekleyen durdurma talimatını iptal edin;
  2. Önceki talimatın yerine yeni bir açıklama ile yeni bir bekleyen durdurma talimatı verin.

Yeni dur talimatı tetiklenirse yorumu pozisyonu kapatan bir yorum olarak görüntülenecektir, bu doğru bir yoldur.

Bununla birlikte, görev kısmen yürütülebilir. Bekleyen talimatın başarıyla iptal edildiğini varsayalım, ancak herhangi bir nedenle yeni talimat verilmedi. Bu durumda pozisyon, zararı durdur seviyesi olmadan bırakılacaktır. Bu hatayı işleyebilmek için, EA'nın özel bir görev günlüğü çağırması ve başarısız olan alt görevi bulmak için içinde arama yapması gerekecektir.

Bu, iki işlev kullanılarak yapılır: TotalActionsTask(), bu görevdeki toplam alım satım işlemlerinin (alt görevlerin) sayısını verir ve GetActionResult(), alt görev dizinini kabul eder ve türünü ve yürütme sonucunu iade eder. Tüm alım satım işlemleri standart MetaTrader 5 araçları kullanılarak yapıldığından, performanslarının sonucu alım satım işlemi sunucusunun dönüş koduna karşılık gelir.

Genel olarak arıza nedeninin arama algoritması aşağıdaki gibidir:

  1. TotalActionsTask() kullanarak görevdeki toplam alt görev sayısını alma;
  2. for döngüsündeki tüm alt görevleri arama. Her alt görevin türünü ve sonucunu belirleme.

Diyelim ki, talimat uygulama fiyatı mevcut fiyat seviyesine çok yakın olduğu için yeni bir açıklama içeren dur talimatı verilemedi.

Aşağıdaki örnek kod, EA'nın bu başarısızlığın nedenini nasıl bulabileceğini gösterir:

#include <Prototypes.mqh> 

ulong Magic=5760655; // MagicEx 1.3.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+ 
void OnTick()
  {
//detect active position
   for(int i=TransactionsTotal(MODE_HISTORY)-1; i>=0; i--)
     {
      if(!TransactionSelect(i,SELECT_BY_POS,MODE_HISTORY))continue;
      ENUM_TRANS_TYPE type=TransactionType();
      if(type==TRANS_NOT_DEFINED)
        {
         ENUM_HEDGE_ERR error=GetHedgeError();
         printf("Error, transaction not defined. Reason: "+EnumToString(error));
        }
      if(TransactionType()!=TRANS_HEDGE_POSITION)continue;
      if(HedgePositionGetInteger(HEDGE_POSITION_MAGIC) != Magic)continue;
      if(HedgePositionGetString(HEDGE_POSITION_SYMBOL) != Symbol())continue;
      HedgeTradeRequest request;
      request.action=REQUEST_MODIFY_COMMENT;
      request.exit_comment="My new comment";
      if(!SendTradeRequest(request)) // Is error?
        {
         for(uint action=0; action < TotalActionsTask(); action++)
           {
            ENUM_TARGET_TYPE typeAction;
            int retcode=0;
            GetActionResult(action, typeAction, retcode);
            printf("Action#" + (string)action + ": " + EnumToString(type) +(string)retcode);
           }
        }
     }
  }

Kodun yürütülmesinden sonra aşağıdaki mesaj görünecektir:

Action #0 TARGET_DELETE_PENDING_ORDER 10009 (TRADE_RETCODE_PLACED)
Action #1 TARGET_SET_PENDING_ORDER 10015 (TRADE_RETCODE_INVALID_PRICE)

Rakamları alım satım sunucusu dönüş kodlarının standart değiştiricileri ile karşılaştırarak, bekleyen talimatın başarıyla kaldırıldığını, ancak yeni bir talimatın verilmediğini öğrendik. Alım satım işlemi sunucusu 10015 hatası verdi (yanlış fiyat), bu da mevcut fiyatın durma seviyesine çok yakın olduğu anlamına gelebilir.

Bu bilgi ışında EA, durdurma seviyeleri üzerinde kontrolü ele alabilir. Bunu yapmak için, EA'nın yalnızca aynı SendTradeRequest() işlevini kullanarak bu pozisyonu kapatması gerekir.


1.7. Ticari Görev Yürütme Durumunu İzleme

Her alım satım görevi, sırayla gerçekleştirilmesi gereken bir dizi alt görevden oluşabilir.

Eşzamansız modda, sırayla gerçekleştirilmesi gereken alt görevlerin kod numarası birkaç geçişinde bir görev gerçekleştirilebilir. Görevin "donabileceği" durumlar da olabilir. Bu nedenle, EA'nın görev yürütme üzerindeki denetimi gereklidir. HEDGE_POSITION_TASK_STATUS değiştiricisiyle HedgePositionGetInteger() işlevini çağırırken, geçerli pozisyon görevinin durumunu içeren ENUM_TASK_STATUS türü numaralandırmayı verir.

Örneğin bir pozisyonu kapatmak için talimat gönderdikten sonra bir şeyler ters giderse pozisyonun kapanmaması nedeniyle, görevin durumunu almanız gerekir.

Aşağıdaki örnek, pozisyon için görevin durumunu analiz etmek için eşzamansız bir Expert Advisor yürütebileceği kodu gösterir:

ENUM_TASK_STATUS status=HedgePositionGetInteger(HEDGE_POSITION_TASK_STATUS);
switch(status)
  {
   case TASK_STATUS_COMPLETE:
      printf("Task complete!");
      break;
   case TASK_STATUS_EXECUTING:
      printf("Task executing. Waiting...");
      Sleep(200);
      break;
   case TASK_STATUS_FAILED:
      printf("Filed executing task. Print logs...");
      for(int i=0; i<TotalActionsTask(); i++)
        {
         ENUM_TARGET_TYPE type;
         uint retcode;
         GetActionResult(i,type,retcode);
         printf("#"+i+" "+EnumToString(type)+" "+retcode);
        }
      break;
   case TASK_STATUS_WAITING:
      printf("task will soon start.");
      break;
  }

Bazı karmaşık görevlerin yürütülmesinin birden çok iterasyon gerektirdiğini unutmayın.

Eşzamansız modda alım satım ortamındaki değişiklikleri işaret eden gelen olaylar yeni bir iterasyon başlatır. Böylece tüm iterasyonlar, işlem sunucusundan alınan yanıtların ardından birbiri ardına gecikmeden gerçekleştirilir. Görev yürütme, eşzamanlı modda farklılık gösterir.

Eşzamanlı yöntem, kullanıcıların tek geçişte bileşik görevleri bile gerçekleştirebilmesi nedeniyle eşzamanlı işlem emülatörünü kullanır. Emülatör zaman gecikmelerini kullanır. Örneğin bir alt görevin yürütülmesi başladıktan sonra, emülatör yürütme iş parçacığını EA'ya verir. Bunun yerine, alım satım ortamının değişmesini beklemek için bir süre bekler. Bundan sonra, alım satım ortamını tekrar okur. Alt görevin başarıyla tamamlandığını anlarsa sonraki alt görevleri başlatır.

Bu işlem, beklemesi biraz zaman aldığından genel performansı biraz düşürür. Ancak karmaşık görevlerin bile yürütülmesini, tek bir işlev çağrısında gerçekleştirilen oldukça basit bir sıralı işleme dönüştürür. Bu nedenle, eşzamanlı yöntemde görev yürütme günlüğünü neredeyse hiç analiz etmeniz gerekmez.


1.8. Çift Yönlü Pozisyonlar Nasıl Değiştirilir ve Kapatılır

Çift yönlü pozisyonlar SendTradeRequest() işlevi kullanılarak değiştirilir ve kapatılır. Etkin bir pozisyona yalnızca üç seçenek uygulanabilir:

  1. Bir pozisyon tamamen veya kısmen kapatılabilir;
  2. Zararı durdur ve kar al pozisyonu değiştirilebilir;
  3. Bir pozisyonun giden yorumu değiştirilebilir.

Geçmiş pozisyon değiştirilemez. MetaTrader 5'teki OrderSend() işlevine benzer şekilde, SendTradeRequest(), HedgeTraderRequest alım satım yapısı biçiminde önceden derlenmiş bir sorgu kullanır. SendTradeRequest() işlevi ve HedgeTraderRequest yapısı hakkında daha fazla ayrıntı için belgeleri okuyun. Pozisyon değişikliğini ve kapanmayı gösteren örnek, Chaos II EA bölümünde mevcuttur.


1.9. Bir Expert Advisor'dan HedgeTerminal Özellikleri Nasıl Ayarlanır

HedgeTerminal, yenileme sıklığı, sunucudan yanıt beklemek için gereken saniye sayısı ve diğerleri gibi bir dizi özelliğe sahiptir.

Bu özelliklerin tümü Settings.xml içinde tanımlanmıştır. Bir EA gerçek zamanlı olarak çalışırken, kitaplık dosyadan özellikleri okur ve uygun dahili parametreleri ayarlar. EA bir grafik üzerinde test edildiğinde, Settings.xml dosyası kullanılmaz. Bununla birlikte, bazı durumlarda, bir grafikte mi yoksa strateji test cihazında mı çalıştığından bağımsız olarak EA özelliklerini ayrı ayrı değiştirmeniz gerekebilir.

Bu, özel işlevler kümesi aracılığıyla yapılır HedgePropertySet… Geçerli sürüm, bu kümeden yalnızca bir prototip içerir:

enum ENUM_HEDGE_PROP_INTEGER
{
   HEDGE_PROP_TIMEOUT,
};

bool HedgePropertySetInteger(ENUM_HEDGE_PROP_INTEGER property, int value)

Örneğin kitaplığın sunucu yanıtını beklemesi için zaman aşımını ayarlamak için aşağıdakini yazın:

bool res = HedgePropertySetInteger(HEDGE_PROP_TIMEOUT, 30);

Eşzamansız bir istek gönderdikten sonra 30 saniye içinde sunucu yanıtı alınmazsa kilitli pozisyon serbest bırakılır.


1.10. Senkronize ve Asenkron Operasyon Modları

HedgeTerminal ve API'si, alım satım faaliyetlerini tamamen eşzamansız olarak gerçekleştirir.

Ancak, bu mod daha karmaşık EA mantığı gerektirir. Bu karmaşıklığı gizlemek için HedgeTerminalAPI, geleneksel bir eşzamanlı yöntemde geliştirilen EA'ların, HedgeTerminalAPI'nin eşzamanlı algoritmalarıyla iletişim kurmasına olanak tanıyan özel bir senkron işlem emülatörü içerir. Bu etkileşim, SendTradeRequest() aracılığıyla çift yönlü pozisyon değişikliği ve kapanış sırasında ortaya çıkar. Bu işlev, bir alım satım görevinin eşzamanlı veya eşzamansız modda yürütülmesine izin verir. Varsayılan olarak tüm alım satım eylemleri, eşzamanlı işlem emülatörü aracılığıyla eşzamanlı olarak yürütülür. Ancak, bir alım satım işlemi talebi (HedgeTradeRequest yapısı) açıkça belirtilen bir asynch_mode = true bayrağı içeriyorsa alım satım görevi eşzamansız modda gerçekleştirilecektir.

Eşzamansız modda, görevler ana iş parçacığından bağımsız olarak gerçekleştirilir. Eşzamansız bir EA ile HedgeTerminal'in asenkron algoritmaları arasındaki etkileşimin uygulanması henüz tamamlanmamıştır.

Eşzamanlı emülatör çok basittir. Alt görevleri sırayla başlatır ve ardından MetaTrader 5'teki alım satım ortamı değişene kadar bir süre bekler. Emülatör bu değişiklikleri analiz eder ve mevcut görevin durumunu belirler. Görev yürütme başarılı olursa emülatör bir sonrakine geçer.

Eşzamanlı emülatör, alım satım talimatlarının yürütülmesinde küçük gecikmelere neden olur. Bunun nedeni MetaTrader 5'teki alım satım ortamının yürütülen alım satım faaliyetlerini yansıtmasının biraz zaman almasıdır. Ortama erişim gerekliliği, öncelikle HedgeTermianlAPI'nin, eşzamanlı iş parçacığı emülasyon modunda OnTradeTransaction() işleyicisine gelen olaylara erişememesi gerçeğiyle bağlantılıdır.

Eşzamansız iş parçacıkları arasındaki etkileşimin yanı sıra eşzamansız ve eşzamanlı iş parçacıkları arasındaki emülasyon yoluyla etkileşim sorunları çok karmaşıktır ve belirgin çözümleri yoktur.


1.11. Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi

Aşağıdaki komut dosyasında, TransactionSelect() işlevi, etkin işlemler listesindeki tüm kullanılabilir işlemleri arar.

Her işlem listeden seçilir. İşlem bir pozisyon ise bazı özelliklerine erişilir ve ardından yazdırılır. Pozisyonların özelliklerine ek olarak, pozisyon içindeki talimat ve yatırımların özellikleri de yazdırılır. Sırasıyla HedgeOrderSelect() ve HedgeDealSelect() kullanılarak bir talimat ve bir yatırım seçilir.

Pozisyonun tüm özellikleri, talimatları ve yatırımları birleştirilir ve sistem işlevi printf. kullanılarak tek bir satır olarak yazdırılır

//+------------------------------------------------------------------+
//|                                           sample_using_htapi.mq5 |
//|         Copyright 2014, Vasiliy Sokolov, Russia, St.-Petersburg. |
//|                              https://login.mql5.com/ru/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Vasiliy Sokolov."
#property link      "https://login.mql5.com/ru/users/c-4"
#property version   "1.00"

// Include prototypes function of HedgeTerminalAPI library.
#include <Prototypes.mqh> 

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+ 
void OnStart()
  {
   // Search all transaction in list transaction...
   for(int i=TransactionsTotal(); i>=0; i--)
     {
      if(!TransactionSelect(i,SELECT_BY_POS,MODE_TRADES))                           // Selecting from active transactions
        {
         ENUM_HEDGE_ERR error=GetHedgeError();                                      // Get reason if selecting has failed
         printf("Error selecting transaction # "+(string)i+". Reason: "+            // Print reason
                EnumToString(error));
         ResetHedgeError();                                                         // Reset error
         continue;                                                                  // Go to next transaction
        }
      // Only for hedge positions
      if(TransactionType()==TRANS_HEDGE_POSITION) 
        {
         // --- Position captions --- //
         ENUM_TRANS_DIRECTION direction=(ENUM_TRANS_DIRECTION)                      // Get direction caption
                              HedgePositionGetInteger(HEDGE_POSITION_DIRECTION);
         double price_entry = HedgeOrderGetDouble(HEDGE_ORDER_PRICE_EXECUTED);      // Get volume of positions
         string symbol = HedgePositionGetString(HEDGE_POSITION_SYMBOL);             // Get symbol of position
         // --- Order captions --- //
         if(!HedgeOrderSelect(ORDER_SELECTED_INIT))continue;                        // Selecting init order in position
         double slippage = HedgeOrderGetDouble(HEDGE_ORDER_SLIPPAGE);               // Get some slippage was
         uint deals_total = (uint)HedgeOrderGetInteger(HEDGE_ORDER_DEALS_TOTAL);    // Get deals total
         // --- Deals captions --- //
         double commissions=0.0;
         ulong deal_id=0;
         //Search all deals in list deals...
         for(uint d_index=0; d_index<deals_total; d_index++)                        
           {
            if(!HedgeDealSelect(d_index))continue;                                  // Selecting deal by its index
            deal_id = HedgeDealGetInteger(HEDGE_DEAL_ID);                           // Get deal id
            commissions += HedgeDealGetDouble(HEDGE_DEAL_COMMISSION);               // Count commissions
           }
         int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
         printf("Position #" + (string)i + ": DIR " + EnumToString(direction) +     // Print result line
         "; PRICE ENTRY " + DoubleToString(price_entry, digits) + 
         "; INIT SLIPPAGE " + DoubleToString(slippage, 2) + "; LAST DEAL ID " +
         (string)deal_id + "; COMMISSIONS SUM " + DoubleToString(commissions, 2));
        }
     }
  }

1.12. Chaos II EA Örneği aracılığıyla SendTradeRequest() İşlevi ve HedgeTradeRequest Yapısı

Örnek olarak Bill Williams'ın Trading Chaos adlı kitabında önerilen alım satım taktiklerine dayalı bir alım satım robotu geliştirelim. İkinci Baskı.

Tüm tavsiyelerini takip etmeyeceğiz, ancak Alligator göstergesini ve diğer bazı koşulları atlayarak şemayı basitleştireceğiz. Bu stratejinin seçimi birkaç düşünceden kaynaklanmaktadır. Bunlardan en önemlisi, bu stratejinin bileşik pozisyon koruma taktiklerini içermesidir. Bazen bir pozisyonun bir kısmını kapatmanız ve zararı durdurmayı başabaş noktasına taşımanız gerekir.

Başabaş noktasına taşındığında, fiyatın ardından durma seviyesi izlenmelidir. İkinci düşünce, bu taktiğin yeterince bilindiği ve bunun için geliştirilen göstergelerin standart MetaTrader 5 teslimat paketinde yer almasıdır. Expert Advisor'ın karmaşık mantığının birincil hedeflerini engellemesini önlemek için kuralları biraz değiştirelim ve basitleştirelim: HedgeTerminalAPI kitaplığı ile EA etkileşiminin bir örneğini göstermek. EA'nın mantığı, HedgeTerminalAPI'nin alım satım işlevlerinin çoğunu kullanır. Bu kütüphane için iyi bir test.

Tersine çevirme çubuğu ile başlayalım. Yükselen bir dönüş çubuğu, kapanış fiyatı üst üçte birlik kısımda olan ve Düşük kısmı son N çubuk için en düşük olan çubuktur. Alçalan bir dönüş çubuğu, kapanış fiyatı alt üçte birlik dilimde olan ve Yüksek kısmı son N çubuk için en yüksek olan çubuktur. N rastgele seçilen bir parametredir, Expert Advisor'ın başlatılması sırasında ayarlanabilir. Bu, klasik "Chaos 2" stratejisinden farklıdır.

Dönüş çubuğu tanımlandıktan sonra, bekleyen iki talimat verilir. Yükselen çubuk için, talimatlar yüksek seviyesinin üstüne, alçalan çubuk en düşük seviyesinin hemen altına yerleştirilir. Bu iki talimat, OldPending çubukları sırasında tetiklenmezse sinyal geçersiz sayılır ve talimatlar iptal edilir. OldPending ve N değerleri, grafikte EA'yı başlatmadan önce kullanıcı tarafından belirlenir.

Talimatlar tetiklenir ve iki çift yönlü pozisyona dönüşür. EA, bunları sırasıyla "# 1" ve "# 2" yorumlarındaki sayılarla ayırt eder. Bu çok zarif bir çözüm olmasa da, tanıtım amaçlı olarak gayet iyidir. Talimatlar tetiklendiğinde, dönüş çubuğunun yüksek (alçalan çubuk için) veya düşük (çubuk yükseliyorsa) bir zararı durdur yerleştirilir.

İlk pozisyonun sıkı hedefleri var. Karı al, tetikleme durumunda pozisyon karı, tetiklenen bir zarar durdurun mutlak kaybına eşit olacak şekilde ayarlanmıştır. Örneğin 1,0000 fiyatında bir uzun pozisyon açılırsa ve zararı durdur 0,9000 seviyesindeyse kar al seviyesi 1,0000 + (1,0000 - 0,9000) = 1,1000 olacaktır. EA, zararı durdur veya kârı al pozisyonundan çıkar.

İkinci pozisyon uzun vadeli bir pozisyondur. Durdurma kaybı, fiyatın ardından takip edilir. Durdurma, yeni oluşturulan Bill Williams'ın fraktalından sonra hareket eder. Uzun pozisyon için durdur, alt fraktallara göre hareket ettirilir ve kısa pozisyon için üst fraktallar kullanılır. EA, pozisyondan sadece zararı durdur işleminde çıkar.

Aşağıdaki çizelge bu stratejiyi göstermektedir:

Şek. 4. Chaos 2 EA'nın çift yönlü pozisyonlarının fiyat tablosunda gösterimi

Şek. 4. Chaos 2 EA'nın çift yönlü pozisyonlarının fiyat tablosunda gösterimi

Dönüş çubukları kırmızı bir çerçeve ile işaretlenmiştir. Bu grafikteki N dönemi, 2'ye eşittir. Bu strateji için en uygun an seçilir. Kısa pozisyonlar mavi noktalı çizgi ile gösterilir, uzun pozisyonlar yeşil ile temsil edilir. Görüldüğü gibi, nispeten basit bir stratejide bile uzun ve kısa pozisyonlar aynı anda var olabilir. 5-8 Ocak 2014 arasındaki döneme dikkat edin.

Bu, AUDCAD düşüş trendi için bir dönüm noktasıdır. 4 Ocak yükselen dönüş çubuğundan bir sinyal alındı ve 5 Ocak'ta iki uzun pozisyon açıldı. Aynı zamanda, trendi takip eden durmaları takip edilen üç kısa pozisyon vardı (kesikli kırmızı çizgi). Ardından 7 Ocak'ta kısa pozisyonlar için durma tetiklendi ve piyasada sadece uzun pozisyonlar kaldı.

Net hacim, EA tarafından fiilen tutulan pozisyonların sayısını hesaba katmayacağından, net pozisyonda değişiklikleri izlemek zor olacaktır. HedgeTerminal, EA'ların mevcut net pozisyondan bağımsız olarak bireysel pozisyonlarını izlemelerine izin vererek, bu çizelgeleri almayı ve benzer stratejiler geliştirmeyi mümkün kılar.

Bu stratejiyi uygulayan kod aşağıdadır.

Kodu yeni başlayanlar için uyarlayarak kasıtlı olarak nesne yönelimli programlama kullanmadım:

//+------------------------------------------------------------------+
//|                                                       Chaos2.mq5 |
//|     Copyright 2014, Vasiliy Sokolov specially for HedgeTerminal. |
//|                                          St.-Petersburg, Russia. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Vasiliy Sokolov."
#property link      "https://login.mql5.com/ru/users/c-4"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Prototypes.mqh>           // Include prototypes function of HedgeTerminalAPI library

//+------------------------------------------------------------------+
//| Input parameters.                                                |
//+------------------------------------------------------------------+
input uint N=2;                     // Period of extermum/minimum
input uint OldPending=3;            // Old pending

//+------------------------------------------------------------------+
//| Private variables of expert advisor.                             |
//+------------------------------------------------------------------+
ulong Magic = 2314;                 // Magic number of expert
datetime lastTime = 0;              // Remembered last time for function DetectNewBar
int hFractals = INVALID_HANDLE;     // Handle of indicator 'Fractals'. See: 'https://www.mql5.com/tr/docs/indicators/ifractals'
//+------------------------------------------------------------------+
//| Type of bar by Bill Wiallams strategy.                           |
//+------------------------------------------------------------------+
enum ENUM_BAR_TYPE
  {
   BAR_TYPE_ORDINARY,               // Ordinary bar. 
   BAR_TYPE_BEARISH,                // This bar close in the upper third and it's minimum is lowest at N period
   BAR_TYPE_BULLISH,                // This bar close in the lower third and it's maximum is highest at N period
  };
//+------------------------------------------------------------------+
//| Type of Extremum.                                                |
//+------------------------------------------------------------------+
enum ENUM_TYPE_EXTREMUM
  {
   TYPE_EXTREMUM_HIGHEST,           // Extremum from highest prices
   TYPE_EXTREMUM_LOWEST             // Extremum from lowest prices
  };
//+------------------------------------------------------------------+
//| Type of position.                                                |
//+------------------------------------------------------------------+
enum ENUM_ENTRY_TYPE
  {
   ENTRY_BUY1,                      // Buy position with short target
   ENTRY_BUY2,                      // Buy position with long target
   ENTRY_SELL1,                     // Sell position with short target
   ENTRY_SELL2,                     // Sell position with long target
   ENTRY_BAD_COMMENT                // My position, but wrong comment
  };
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Create indicator 'Fractals' ---//
   hFractals=iFractals(Symbol(),NULL);
   if(hFractals==INVALID_HANDLE)
      printf("Warning! Indicator 'Fractals' not does not create. Reason: "+
             (string)GetLastError());
//--- Corection magic by timeframe ---//
   int minPeriod=PeriodSeconds()/60;
   string strMagic=(string)Magic+(string)minPeriod;
   Magic=StringToInteger(strMagic);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete indicator 'Fractals' ---//
   if(hFractals!=INVALID_HANDLE)
      IndicatorRelease(hFractals);
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Run logic only open new bar. ---//
   int totals=SupportPositions();
   if(NewBarDetect()==true)
     {
      MqlRates rates[];
      CopyRates(Symbol(),NULL,1,1,rates);
      MqlRates prevBar=rates[0];
      //--- Set new pendings order ---//
      double closeRate=GetCloseRate(prevBar);
      if(closeRate<=30 && BarIsExtremum(1,N,TYPE_EXTREMUM_HIGHEST))
        {
         DeleteOldPendingOrders(0);
         SetNewPendingOrder(1,BAR_TYPE_BEARISH);
        }
      else if(closeRate>=70 && BarIsExtremum(1,N,TYPE_EXTREMUM_LOWEST))
        {
         DeleteOldPendingOrders(0);
         SetNewPendingOrder(1,BAR_TYPE_BULLISH);
        }
      DeleteOldPendingOrders(OldPending);
     }
//---
  }
//+------------------------------------------------------------------+
//| Analyze open positions and modify it if needed.                  |
//+------------------------------------------------------------------+
int SupportPositions()
  {
//---
   int count=0;
   //--- Analize active positions... ---//
   for(int i=0; i<TransactionsTotal(); i++) // Get total positions.
     {
      //--- Select main active positions ---//
      if(!TransactionSelect(i, SELECT_BY_POS, MODE_TRADES))continue;             // Select active transactions
      if(TransactionType() != TRANS_HEDGE_POSITION)continue;                     // Select hedge positions only
      if(HedgePositionGetInteger(HEDGE_POSITION_MAGIC) != Magic)                 // Select main positions by magic
      if(HedgePositionGetInteger(HEDGE_POSITION_STATE) == POSITION_STATE_FROZEN) // If position is frozen - continue
         continue;                                                               // Let's try to get access to positions later
      count++;
      //--- What position do we choose?... ---//
      ENUM_ENTRY_TYPE type=IdentifySelectPosition();
      bool modify=false;
      double sl = 0.0;
      double tp = 0.0;
      switch(type)
        {
         case ENTRY_BUY1:
         case ENTRY_SELL1:
           {
            //--- Check sl, tp levels and modify it if need. ---//
            double currentStop=HedgePositionGetDouble(HEDGE_POSITION_SL);
            sl=GetStopLossLevel();
            if(!DoubleEquals(sl,currentStop))
               modify=true;
            tp=GetTakeProfitLevel();
            double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
            double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
            //--- Close by take-profit if price more tp level
            bool isBuyTp=tp<bid && !DoubleEquals(tp,0.0) && type==ENTRY_BUY1;
            bool isSellTp=tp>ask && type==ENTRY_SELL1;
            if(isBuyTp || isSellTp)
              {
               HedgeTradeRequest request;
               request.action=REQUEST_CLOSE_POSITION;
               request.exit_comment="Close by TP from expert";
               request.close_type=CLOSE_AS_TAKE_PROFIT;
               if(!SendTradeRequest(request))
                 {
                  ENUM_HEDGE_ERR error=GetHedgeError();
                  string logs=error==HEDGE_ERR_TASK_FAILED ? ". Print logs..." : "";
                  printf("Close position by tp failed. Reason: "+EnumToString(error)+" "+logs);
                  if(error==HEDGE_ERR_TASK_FAILED)
                     PrintTaskLog();
                  ResetHedgeError();
                 }
               else break;
              }
            double currentTakeProfit=HedgePositionGetDouble(HEDGE_POSITION_TP);
            if(!DoubleEquals(tp,currentTakeProfit))
               modify=true;
            break;
           }
         case ENTRY_BUY2:
           {
            //--- Check sl level and set modify flag. ---//
            sl=GetStopLossLevel();
            double currentStop=HedgePositionGetDouble(HEDGE_POSITION_SL);
            if(sl>currentStop)
               modify=true;
            break;
           }
         case ENTRY_SELL2:
           {
            //--- Check sl level and set modify flag. ---//
            sl=GetStopLossLevel();
            double currentStop=HedgePositionGetDouble(HEDGE_POSITION_SL);
            bool usingSL=HedgePositionGetInteger(HEDGE_POSITION_USING_SL);
            if(sl<currentStop || !usingSL)
               modify=true;
            break;
           }
        }
      //--- if  need modify sl, tp levels - modify it. ---//
      if(modify)
        {
         HedgeTradeRequest request;
         request.action=REQUEST_MODIFY_SLTP;
         request.sl = sl;
         request.tp = tp;
         if(type==ENTRY_BUY1 || type==ENTRY_SELL1)
            request.exit_comment="Exit by T/P level";
         else
            request.exit_comment="Exit by trailing S/L";
         if(!SendTradeRequest(request))
           {
            ENUM_HEDGE_ERR error=GetHedgeError();
            string logs=error==HEDGE_ERR_TASK_FAILED ? ". Print logs..." : "";
            printf("Modify stop-loss or take-profit failed. Reason: "+EnumToString(error)+" "+logs);
            if(error==HEDGE_ERR_TASK_FAILED)
               PrintTaskLog();
            ResetHedgeError();
           }
         else break;
        }
     }
   return count;
//---
  }
//+------------------------------------------------------------------+
//| Return stop-loss level for selected position.                    |
//| RESULT                                                           |
//|   Stop-loss level                                                |
//+------------------------------------------------------------------+
double GetStopLossLevel()
  {
//---
   double point=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE)*3;
   double fractals[];
   double sl=0.0;
   MqlRates ReversalBar;

   if(!LoadReversalBar(ReversalBar))
     {
      printf("Reversal bar load failed.");
      return sl;
     }
   //--- What position do we choose?... ---//
   switch(IdentifySelectPosition())
     {
      case ENTRY_SELL2:
        {
         if(HedgePositionGetInteger(HEDGE_POSITION_USING_SL))
           {
            sl=NormalizeDouble(HedgePositionGetDouble(HEDGE_POSITION_SL),Digits());
            CopyBuffer(hFractals,UPPER_LINE,ReversalBar.time,TimeCurrent(),fractals);
            for(int i=ArraySize(fractals)-4; i>=0; i--)
              {
               if(DoubleEquals(fractals[i],DBL_MAX))continue;
               if(DoubleEquals(fractals[i],sl))continue;
               if(fractals[i]<sl)
                 {
                  double price= SymbolInfoDouble(Symbol(),SYMBOL_ASK);
                  int ifreeze =(int)SymbolInfoInteger(Symbol(),SYMBOL_TRADE_FREEZE_LEVEL);
                  double freeze=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE)*ifreeze;
                  if(fractals[i]>price+freeze)
                     sl=NormalizeDouble(fractals[i]+point,Digits());
                 }
              }
            break;
           }
        }
      case ENTRY_SELL1:
         sl=ReversalBar.high+point;
         break;
      case ENTRY_BUY2:
         if(HedgePositionGetInteger(HEDGE_POSITION_USING_SL))
           {
            sl=NormalizeDouble(HedgePositionGetDouble(HEDGE_POSITION_SL),Digits());
            CopyBuffer(hFractals,LOWER_LINE,ReversalBar.time,TimeCurrent(),fractals);
            for(int i=ArraySize(fractals)-4; i>=0; i--)
              {
               if(DoubleEquals(fractals[i],DBL_MAX))continue;
               if(DoubleEquals(fractals[i],sl))continue;
               if(fractals[i]>sl)
                 {
                  double price= SymbolInfoDouble(Symbol(),SYMBOL_BID);
                  int ifreeze =(int)SymbolInfoInteger(Symbol(),SYMBOL_TRADE_FREEZE_LEVEL);
                  double freeze=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE)*ifreeze;
                  if(fractals[i]<price-freeze)
                     sl=NormalizeDouble(fractals[i]-point,Digits());
                 }
              }
            break;
           }
      case ENTRY_BUY1:
         sl=ReversalBar.low-point;
     }
   sl=NormalizeDouble(sl,Digits());
   return sl;
//---
  }
//+------------------------------------------------------------------+
//| Return Take-Profit level for selected position.                  |
//| RESULT                                                           |
//|   Take-profit level                                              |
//+------------------------------------------------------------------+
double GetTakeProfitLevel()
  {
//---
   double point=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE)*3;
   ENUM_ENTRY_TYPE type=IdentifySelectPosition();
   double tp=0.0;
   if(type==ENTRY_BUY1 || type==ENTRY_SELL1)
     {
      if(!HedgePositionGetInteger(HEDGE_POSITION_USING_SL))
         return tp;
      double sl=HedgePositionGetDouble(HEDGE_POSITION_SL);
      double openPrice=HedgePositionGetDouble(HEDGE_POSITION_PRICE_OPEN);
      double deltaStopLoss=MathAbs(NormalizeDouble(openPrice-sl,Digits()));
      if(type==ENTRY_BUY1)
         tp=openPrice+deltaStopLoss;
      if(type==ENTRY_SELL1)
         tp=openPrice-deltaStopLoss;
      return tp;
     }
   else
      return 0.0;
//---
  }
//+------------------------------------------------------------------+
//| Identify what position type is select.                           |
//| RESULT                                                           |
//|   Return type position. See ENUM_ENTRY_TYPE                      |
//+------------------------------------------------------------------+
ENUM_ENTRY_TYPE IdentifySelectPosition()
  {
//---   
   string comment=HedgePositionGetString(HEDGE_POSITION_ENTRY_COMMENT);
   int pos=StringLen(comment)-2;
   string subStr=StringSubstr(comment,pos);
   ENUM_TRANS_DIRECTION posDir=(ENUM_TRANS_DIRECTION)HedgePositionGetInteger(HEDGE_POSITION_DIRECTION);
   if(subStr=="#0")
     {
      if(posDir==TRANS_LONG)
         return ENTRY_BUY1;
      if(posDir==TRANS_SHORT)
         return ENTRY_SELL1;
     }
   else if(subStr=="#1")
     {
      if(posDir==TRANS_LONG)
         return ENTRY_BUY2;
      if(posDir==TRANS_SHORT)
         return ENTRY_SELL2;
     }
   return ENTRY_BAD_COMMENT;
//---
  }
//+------------------------------------------------------------------+
//| Set pending orders under or over bar by index_bar.               |
//| INPUT PARAMETERS                                                 |
//|   index_bar - index of bar.                                      |
//|   barType - type of bar. See enum ENUM_BAR_TYPE.                 |
//| RESULT                                                           |
//|   True if new order successfully set, othewise false.            | 
//+------------------------------------------------------------------+
bool SetNewPendingOrder(int index_bar,ENUM_BAR_TYPE barType)
  {
//---
   MqlRates rates[1];
   CopyRates(Symbol(),NULL,index_bar,1,rates);
   MqlTradeRequest request={0};
   request.volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   double vol=request.volume;
   request.symbol = Symbol();
   request.action = TRADE_ACTION_PENDING;
   request.type_filling=ORDER_FILLING_FOK;
   request.type_time=ORDER_TIME_GTC;
   request.magic=Magic;
   double point=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE)*3;
   string comment="";
   if(barType==BAR_TYPE_BEARISH)
     {
      request.price=rates[0].low-point;
      comment="Entry sell by bearish bar";
      request.type=ORDER_TYPE_SELL_STOP;
     }
   else if(barType==BAR_TYPE_BULLISH)
     {
      request.price=rates[0].high+point;
      comment="Entry buy by bullish bar";
      request.type=ORDER_TYPE_BUY_STOP;
     }
   MqlTradeResult result={0};
//--- Send pending order twice...
   for(int i=0; i<2; i++)
     {
      request.comment=comment+" #"+(string)i;       // Detect order by comment;
      if(!OrderSend(request,result))
        {
         printf("Trade error #"+(string)result.retcode+" "+
                result.comment);
         return false;
        }
     }
   return true;
//---
  }
//+------------------------------------------------------------------+
//| Delete old pending orders. If pending order set older that       |
//| n_bars ago pending orders will be removed.                       |
//| INPUT PARAMETERS                                                 |
//|   period - count bar.                                            |
//+------------------------------------------------------------------+
void DeleteOldPendingOrders(int n_bars)
  {
//---
   for(int i=0; i<OrdersTotal(); i++)
     {
      ulong ticket = OrderGetTicket(i);            // Get ticket of order by index.
      if(!OrderSelect(ticket))                     // Continue if not selected.
         continue;
      if(Magic!=OrderGetInteger(ORDER_MAGIC))      // Continue if magic is not main.
         continue;
      if(OrderGetString(ORDER_SYMBOL)!=Symbol())   // Continue if symbol is not main.
         continue;
      //--- Count time elipsed ---//
      datetime timeSetup=(datetime)OrderGetInteger(ORDER_TIME_SETUP);
      int secElapsed=(int)(TimeCurrent()-timeSetup);
      //--- delete old pending order ---//
      if(secElapsed>=PeriodSeconds() *n_bars)
        {
         MqlTradeRequest request={0};
         MqlTradeResult result={0};
         request.action= TRADE_ACTION_REMOVE;
         request.order = ticket;
         if(!OrderSend(request,result))
            printf("Delete pending order failed. Reason #"+(string)result.retcode+" "+result.comment);
        }
     }
//---
  }
//+------------------------------------------------------------------+
//| Detect new bar.                                                  |
//+------------------------------------------------------------------+
bool NewBarDetect(void)
  {
//---
   datetime timeArray[1];
   CopyTime(Symbol(),NULL,0,1,timeArray);
   if(lastTime!=timeArray[0])
     {
      lastTime=timeArray[0];
      return true;
     }
   return false;
//---
  }
//+------------------------------------------------------------------+
//| Get close rate. Type bar defined in trade chaos strategy         |
//| and equal enum 'ENUM_TYPE_BAR'.                                  |
//| INPUT PARAMETERS                                                 |
//|   index - index of bars series. for example:                     |
//|   '0' - is current bar. 1 - previous bar.                        |
//| RESULT                                                           |
//|   Type of ENUM_TYPE_BAR.                                         | 
//+------------------------------------------------------------------+
double GetCloseRate(const MqlRates &bar)
  {
//---
   double highLowDelta = bar.high-bar.low;      // Calculate diaposon bar.
   double lowCloseDelta = bar.close - bar.low;  // Calculate Close - Low delta.
   double percentClose=0.0;
   if(!DoubleEquals(lowCloseDelta, 0.0))                    // Division by zero protected.   
      percentClose = lowCloseDelta/highLowDelta*100.0;      // Calculate percent 'lowCloseDelta' of 'highLowDelta'.
   return percentClose;
//---
  }
//+------------------------------------------------------------------+
//| If bar by index is extremum - return true, otherwise             |
//| return false.                                                    |
//| INPUT PARAMETERS                                                 |
//|   index - index of bar.                                          |
//|   period - Number of bars prior to the extremum.                 |
//|   type - Type of extremum. See ENUM_TYPE_EXTREMUM TYPE enum.     |
//| RESULT                                                           |
//|   True - if bar is extremum, otherwise false.                    | 
//+------------------------------------------------------------------+
bool BarIsExtremum(const int index,const int period,ENUM_TYPE_EXTREMUM type)
  {
//--- Copy rates --- //
   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   CopyRates(Symbol(),NULL,index,N+1,rates);
//--- Search extremum --- //
   for(int i=1; i<ArraySize(rates); i++)
     {
      //--- Reset comment if you want include volume analize. ---//
      //if(rates[0].tick_volume<rates[i].tick_volume)
      //   return false;
      if(type==TYPE_EXTREMUM_HIGHEST && 
         rates[0].high<rates[i].high)
         return false;
      if(type==TYPE_EXTREMUM_LOWEST && 
         rates[0].low>rates[i].low)
         return false;
     }
   return true;
//---
  }
//+------------------------------------------------------------------+
//| Print current error and reset it.                                |
//+------------------------------------------------------------------+  
void PrintTaskLog()
  {
//---
   uint totals=(uint)HedgePositionGetInteger(HEDGE_POSITION_ACTIONS_TOTAL);
   for(uint i = 0; i<totals; i++)
     {
      uint retcode=0;
      ENUM_TARGET_TYPE type;
      GetActionResult(i,type,retcode);
      printf("---> Action #"+(string)i+"; "+EnumToString(type)+"; RETCODE: "+(string)retcode);
     }
//---
  }
//+------------------------------------------------------------------+
//| Load reversal bar. The current position must be selected.        |
//| OUTPUT PARAMETERS                                                |
//|   bar - MqlRates bar.
//+------------------------------------------------------------------+  
bool LoadReversalBar(MqlRates &bar)
  {
//---
   datetime time=(datetime)(HedgePositionGetInteger(HEDGE_POSITION_ENTRY_TIME_SETUP_MSC)/1000+1);
   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   CopyRates(Symbol(),NULL,time,2,rates);
   int size=ArraySize(rates);
   if(size==0)return false;
   bar=rates[size-1];
   return true;
//---   
  }
//+------------------------------------------------------------------+
//| Compares two double numbers.                                     |
//| RESULT                                                           |
//|   True if two double numbers equal, otherwise false.             |
//+------------------------------------------------------------------+
bool DoubleEquals(const double a,const double b)
  {
//---
   return(fabs(a-b)<=16*DBL_EPSILON*fmax(fabs(a),fabs(b)));
//---
  }

Aşağıda bu kodun nasıl çalıştığına dair kısa bir açıklama bulunmaktadır. EA her onay işaretinde çağrılır. BarIsExtremum() işlevini kullanarak önceki çubuğu analiz eder: düşüş eğilimindeyse veya yükselişteyse bekleyen iki talimat yerleştirir (SetNewPendingOrder() işlevi). Etkinleştirildiğinde bekleyen talimatlar pozisyonlara dönüştürülür. EA, pozisyonlar için zararı durdur ve kar al özelliklerini ayarlar.

Ne yazık ki, bu seviyeler bekleyen talimatlarla birlikte verilemez çünkü henüz gerçek bir pozisyon yoktur. Düzeyler, SupportPositions() işlevi aracılığıyla ayarlanır. Düzgün bir şekilde çalışmak için, kar al pozisyonunun yerleştirilmesi gereken pozisyonu ve fraktalların ardından takip edilmesi gereken pozisyonu bilmemiz gerekir. Pozisyonların bu tanımı, IdentifySelectPosition() işlevi tarafından yapılır. Bu, başlatma pozisyonu yorumunu analiz eder ve "#1" dizesini içeriyorsa bunun için sıkı bir hedef belirlenir; "#2" içeriyorsa takip eden durdurma uygulanır.

Açık bir çift yönlü pozisyonu değiştirmek veya kapatmak için özel bir alım satım talebi oluşturulur ve bu talep daha sonra yürütme için SendTradeRequest() işlevine gönderilir:

...
if(modify)
  {
   HedgeTradeRequest request;
   request.action=REQUEST_MODIFY_SLTP;
   request.sl = sl;
   request.tp = tp;
   if(type==ENTRY_BUY1 || type==ENTRY_SELL1)
      request.exit_comment="Exit by T/P level";
   else
      request.exit_comment="Exit by trailing S/L";
   if(!SendTradeRequest(request))
     {
      ENUM_HEDGE_ERR error=GetHedgeError();
      string logs=error==HEDGE_ERR_TASK_FAILED ? ". Print logs..." : "";
      printf("Modify stop-loss or take-profit failed. Reason: "+EnumToString(error)+" "+logs);
      if(error==HEDGE_ERR_TASK_FAILED)
         PrintTaskLog();
      ResetHedgeError();
     }
   else break;
  }
...

Hata işlemeye dikkat edin.

Gönderme başarısız olursa ve işlev yanlış verilirse GetHedgeError() işlevini kullanarak son hata kodunu almamız gerekir. Bazı durumlarda bir alım satım talimatının yürütülmesi bile başlamaz. Pozisyon önceden seçilmemişse sorgu yanlış yapılır ve yürütülmesi imkansızdır.

Bir talimat yürütülmezse uygulanmasının günlüğünü analiz etmek anlamsızdır, bir hata kodu almak yeterlidir.

Ancak sorgu doğruysa ve herhangi bir nedenle talimat yürütülmezse HEDGE_ERR_TASK_FAILED hatası verilir. Bu durumda günlük üzerinden arama yaparak talimiat yürütme günlüğünü analiz etmek gerekir. Bu, PrintTaskLog() özel işlevi aracılığıyla yapılır:

//+------------------------------------------------------------------+
//| Print current error and reset it.                                |
//+------------------------------------------------------------------+  
void PrintTaskLog()
  {
//---
   uint totals=(uint)HedgePositionGetInteger(HEDGE_POSITION_ACTIONS_TOTAL);
   for(uint i = 0; i<totals; i++)
     {
      uint retcode=0;
      ENUM_TARGET_TYPE type;
      GetActionResult(i,type,retcode);
      printf("---> Action #"+(string)i+"; "+EnumToString(type)+"; RETCODE: "+(string)retcode);
     }
//---
  }

Bu mesajlar, arızanın nedenini belirlemeye ve düzeltmeye izin verir.

Şimdi Chaos2 EA'nın görüntüsünü ve HedgeTerminal'deki pozisyonlarını gerçek zamanlı olarak gösterelim. EA, M1 grafiğinde çalışıyor:

Şek. 5. HedgeTerminal panelinde Chaos 2 EA'nın çift yönlü pozisyonlarının temsili

Şek. 5. HedgeTerminal panelinde Chaos 2 EA'nın çift yönlü pozisyonlarının temsili

Görülebileceği gibi, bir EA'nın çift yönlü pozisyonları bile mükemmel bir şekilde bir arada var olabilir.


1.13. Komisyoncu tarafından "Yinelenen Semboller" ve Sanallaştırma Hakkında

MetaTrader 5 piyasaya sürüldüğünde, bazı komisyoncular sözde yinelenen sembolleri sağlamaya başladı. Kotasyonları orijinal enstrümanlara eşittir, ancak kural olarak "_m" veya 2>"_1" gibi bir son ekleri vardır. Yatırımcıların neredeyse aynı sembol üzerinde iki yönlü pozisyonlara sahip olmalarına izin vermek için tanıtıldılar.

Bununla birlikte, bu tür semboller, robot kullanan algoritmik yatırımcılar için neredeyse işe yaramaz. Bunun sebebini açıklıyoruz. HedgeTerminalAPI kitaplığı olmadan "Chaos II" EA'yı yazmamız gerektiğini varsayalım. Bunun yerine, bazı yinelenen sembollerimiz olurdu. Bunu nasıl yapardık? Tüm satış işlemlerinin EURUSD gibi tek bir enstrümanda açıldığını ve tüm satın alma işlemlerinin diğerinde, örneğin EURUSD_m1 üzerinde açıldığını varsayın.

Ancak, pozisyon açma anında sembollerden biri zaten başka bir robot veya yatırımcı tarafından takas edildiyse ne olurdu? Bu tür semboller her zaman ücretsiz olsa bile, aynı yönde aynı anda birden fazla pozisyona sahip olabilen bu robot için sorun çözülmezdi.

Yukarıdaki ekran görüntüsü üç satış pozisyonu gösteriyor ve bunlardan daha fazlası olabilir. Pozisyonların farklı koruyucu durdurma seviyeleri vardır, bu nedenle tek bir ağ pozisyonunda birleştirilemezler. Çözüm, yeni bir yinelenen sembol için yeni bir pozisyon açmaktır. Ancak bu tür semboller yeterli olmayabilir, çünkü bir robotun altı kopya enstrümana ihtiyacı vardır (her alım satım yönünde üç). İki robot farklı zaman dilimlerinde çalışıyorsa 12 sembol gerekir.

Aracıların hiçbiri bu kadar çok sayıda yinelenen sembol sağlamaz. Ancak bu tür sembollerin sınırsız miktarı olsa ve bunlar her zaman özgür olsa bile, algoritmanın karmaşık bir şekilde ayrıştırılması gerekecektir. Robot, kopyaları ve kendi pozisyonlarını arayan mevcut tüm sembolleri gözden geçirmek zorunda kalacaktı. Bu, çözebileceğinden daha fazla sorun yaratır. 

Yinelenen sembollerle ilgili daha da fazla zorluk mevcuttur. Kullanımlarından kaynaklanan ek sorunların kısa bir listesi:

  • Her bir yinelenen sembol için negatif takas şeklinde ödeme yaparsınız, çünkü kilitleme veya kısmi kilitleme takasları her zaman negatiftir ve bu, iki farklı enstrümanda iki çift yönlü pozisyon tuttuğunuzda ortaya çıkan durumdur.
  • Tüm komisyoncular yinelenen semboller sağlamaz. Yinelenen semboller sağlayan bir komisyoncu için geliştirilen bir strateji, yalnızca bir enstrüman sağlayan bir komisyoncuyla çalışmayacaktır. Sembol adlarındaki fark, başka bir potansiyel sorun kaynağıdır.
  • Yinelenen bir sembol oluşturmak her zaman mümkün değildir. Katı düzenlemelere tabi olan şeffaf piyasalarda, herhangi bir işlem finansal bir belgedir. Net pozisyon, bu tür pazarlarda fiili standarttır ve bu nedenle burada bireysel sembollerin yaratılması mümkün olmaktan uzaktır. Örneğin Moskova Borsası MOEX'te çift semboller sağlayan hiçbir komisyoncu asla görünemez. Daha az katı düzenlemelere sahip piyasalarda komisyoncular, müşterileri için herhangi bir sembol oluşturabilir.
  • Yinelenen enstrümanlar, robotları kullanarak alım satım yaparken etkisizdir. Etkisizliklerinin nedenleri yukarıdaki Chaos 2 EA örneğinde açıklanmıştır.

Yinelenen bir sembol, esasen komisyoncu tarafında bir sanallaştırmadır. HedgeTerminal, istemci tarafında sanallaştırmayı kullanır.

Her iki durumda da sanallaştırmayı bu şekilde kullanırız. Yatırımcının yükümlülüklerinin fiili temsilini değiştirir. Sanallaştırma ile bir pozisyon iki pozisyona dönüşebilir. İstemci tarafında gerçekleştiğinde herhangi bir sorun yoktur, çünkü istemciler ne isterse onu temsil edebilir. Ancak sanallaştırma aracı tarafından yapılırsa düzenleyici ve lisans veren kuruluşların sağlanan bilgilerin gerçek bilgilerle nasıl ilişkili olduğu konusunda soruları olabilir. İkinci zorluk, bunun birinde iki API'ye sahip olmayı gerektirmesidir: net modunda kullanım için bir dizi işlev ve değiştirici ile çift yönlü mod için bir diğeri.

Birçok algoritmik yatırımcı, alım satımları tek bir pozisyona bağlamak için kendi yollarını buldular. Bu yöntemlerin çoğu iyi çalışıyor ve bu yöntemleri açıklayan makaleler de mevcut. Ancak pozisyonların sanallaştırılması göründüğünden daha karmaşık bir işlemdir. HedgeTerminal'de pozisyonların sanallaştırılmasıyla ilgili algoritmalar kaynak kodun yaklaşık 20.000 satırını alır. Ayrıca HedgeTerminal yalnızca temel işlevleri uygular. EA'nızda yalnızca çift yönlü pozisyonlara eşlik etmek için benzer miktarda kod oluşturmak çok fazla kaynak tüketecektir.


Bölüm 2. HedgeTerminal API Kılavuzu

2.1. İşlem Seçim İşlevleri

İşlev TransactionsTotal()

İşlev, işlem listesindeki toplam işlem sayısını verir. Bu, mevcut işlemleri aramak için temel işlevdir (bu makalenin 1.4 ve 1.11 bölümlerindeki örneğe bakın).

int TransactionsTotal(ENUM_MODE_TRADES pool = MODE_TRADES);

Parametreler

  • [in] pool=MODE_TRADES  – Seçim için veri kaynağının tanımlayıcısını belirtir. ENUM_MODE_TRADES numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

İşlev, işlem listesindeki toplam işlem sayısını verir.


TransactionType İşlevi()

İşlev, seçilen iki yönlü pozisyonun türünü verir.

ENUM_TRANS_TYPE TransactionType(void);

Dönüş Değeri

Dönüş türü. Değer, ENUM_TRANS_TYPE değerlerinden biri olabilir.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


TransactionSelect İşlevi()

Bu işlev, başka manipülasyon için bir işlem seçer. İşlev, işlem listesindeki indeksine veya benzersiz tanımlayıcısına göre bir işlemi seçer.

bool TransactionSelect(int index,
     ENUM_MODE_SELECT select = SELECT_BY_POS,
     ENUM_MODE_TRADES pool=MODE_TRADES
     );

Parametreler

  • [içinde] index – "Seç" parametresine bağlı olarak talimat listesindeki talimatın dizini veya işlemin benzersiz tanımlayıcısı.
  • [içinde] select=SELECT_BY_POS – Parametrenin "indeks" türünün tanımlayıcısı. Değer, ENUM_MODE_SELECT değerlerinden biri olabilir.
  • [içinde] pool=MODE_TRADES – Seçim için veri kaynağının tanımlayıcısını belirtir. ENUM_MODE_TRADES numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

Bir işlem başarıyla seçildiyse doğru değerini, aksi takdirde yanlış değerini verir. Hata ayrıntılarına erişmek için GetHedgeError() adresini arayın.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".

Not

Dizine göre bir işlem seçilirse işlemin karmaşıklığı O(1)'e karşılık gelir. Benzersiz tanımlayıcısına göre bir işlem seçilirse işlemin karmaşıklığı asimptotik olarak O(log2(n)) olma eğilimindedir.


İşlev HedgeOrderSelect()

İşlev, çift yönlü pozisyona dahil olan talimatlardan birini seçer. Gerekli talimatı içeren çift yönlü pozisyon, TransactionSelect () kullanılarak önceden seçilmelidir.

bool HedgeOrderSelect(ENUM_HEDGE_ORDER_SELECTED_TYPE type);

Parametreler

  • [içinde] tür – seçilecek talimat tanımlayıcısı. Değer ENUM_HEDGE_ORDER_PROP_DOUBLE numaralandırma değerlerinden herhangi biri olabilir.

Dönüş Değeri

Bir talimat başarıyla seçildiyse doğru, aksi takdirde yanlış dönüşür. Hata ayrıntılarına erişmek için GetHedgeError() adresini arayın.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


İşlev HedgeDealSelect()

İşlev, talimatı yürüten yatırımlardan birini seçer. Parçası seçilen yatırım olan talimat, HedgeOrderSelect() işlevi kullanılarak önceden seçilmelidir.

bool HedgeDealSelect(int index);

Parametreler

  • [içinde] index – Talimatı gerçekleştiren yatırım, yatırımlar listesinden seçilecek yatırımın dizini. Bir talimat içindeki toplam yatırım sayısını bulmak için HedgeOrderGetInteger() işlevini kullanarak uygun talimat özelliğini çağırın. Parametre için, HEDGE_ORDER_DEALS_TOTAL değerine eşit ENUM_HEDGE_ORDER_PROP_INTEGER değiştiricisini kullanın.

Dönüş Değeri

Bir yatırım başarıyla seçildiyse doğru değerini, aksi takdirde yanlış değerini verir. Hata ayrıntılarına erişmek için GetHedgeError() adresini arayın.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


2.2. Seçili Bir İşlemin Özelliklerini Sahip Olma İşlevleri

HedgePositionGetInteger İşlevi()

İşlev, seçilen iki yönlü pozisyonun özelliğini verir. Özellik, talep edilen özelliğin türüne bağlı oalrak int, long, datetime veya bool türünde olabilir. Çift yönlü pozisyon, TransactionSelect() işlevi kullanılarak önceden seçilmelidir.

ulong HedgePositionGetInteger(ENUM_HEDGE_POSITION_PROP_INTEGER property);

Parametreler

  • [içinde] özellik – Çift yönlü pozisyon özelliğinin tanımlayıcısı. Değer ENUM_HEDGE_ORDER_PROP_DOUBLE numaralandırma değerlerinden herhangi biri olabilir.

Dönüş Değeri

ulong türünün değeri. Değerin daha fazla kullanımı için, türü, istenen özelliğin türüne açıkça çevirilmelidir olmalıdır.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


HedgePositionGetDouble İşlevi()

İşlev, seçilen iki yönlü pozisyonun özelliğini verir. Verilen özelliğin türü çift şeklindedir. Özellik türü, ENUM_HEDGE_POSITION_PROP_DOUBLE numaralandırma yoluyla belirlenir. Çift yönlü pozisyon, TransactionSelect() kullanılarak önceden seçilmelidir.

ulong HedgePositionGetDouble(ENUM_HEDGE_POSITION_PROP_DOUBLE property);

Parametreler

  • [içinde] özellik – Çift yönlü pozisyon özelliğinin tanımlayıcısı. Değer, ENUM_HEDGE_DEAL_PROP_DOUBLE numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

çift türünde bir değer.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


HedgePositionGetString İşlevi()

İşlev, seçilen iki yönlü pozisyonun özelliğini verir. Özellik, dize türündedir. Özellik türü, ENUM_HEDGE_POSITION_PROP_STRING numaralandırma yoluyla belirlenir. Çift yönlü pozisyon, TransactionSelect() kullanılarak önceden seçilmelidir.

ulong HedgePositionGetString(ENUM_HEDGE_POSITION_PROP_STRING property);

Parametreler

  • [içinde] özellik – Çift yönlü pozisyon özelliğinin tanımlayıcısı. Değer, ENUM_HEDGE_POSITION_PROP_STRING numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

Dize türünde bir değer.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


HedgeOrderGetInteger İşlevi()

İşlev, çift yönlü pozisyonun bir parçası olan seçili düzenin özelliğini verir. Özellik, int, long, datetime veya bool türünde olabilir. Özellik türü, ENUM_HEDGE_ORDER_PROP_INTEGER numaralandırma yoluyla belirlenir. Talimat, HedgeOrderSelect() işlevi kullanılarak önceden seçilmelidir.

ulong HedgeOrderGetInteger(ENUM_HEDGE_ORDER_PROP_INTEGER property);

Parametreler

  • [içinde] özellik – İki yönlü pozisyonun bir parçası olan talimat özelliğinin tanımlayıcısı. Değer, ENUM_HEDGE_ORDER_PROP_INTEGER numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

ulong türünün değeri. Değerin daha fazla kullanımı için, türü, istenen özelliğin türüne açıkça çevirilmelidir olmalıdır.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


HedgeOrderGetDouble İşlevi()

İşlev, çift yönlü pozisyonun bir parçası olan seçili düzenin özelliğini verir. İstenen özellik çift türündedir. Özellik türü, ENUM_HEDGE_ORDER_PROP_DOUBLE numaralandırma yoluyla belirlenir. Talimat, HedgeOrderSelect() işlevi kullanılarak önceden seçilmelidir.

double HedgeOrderGetDouble(ENUM_HEDGE_ORDER_PROP_DOUBLE property);

Parametreler

  • [içinde] özellik – İki yönlü pozisyonun bir parçası olan talimat özelliğinin tanımlayıcısı. Değer ENUM_HEDGE_ORDER_PROP_DOUBLE numaralandırma değerlerinden herhangi biri olabilir.

Dönüş Değeri

çift türünde bir değer.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


İşlev HedgeDealGetInteger()

İşlev yürütülen talimatın bir parçası olan seçili yatırımın özelliğini döndürür. Özellik, int, long, datetime veya bool türünde olabilir. Özellik türü, ENUM_HEDGE_DEAL_PROP_INTEGER numaralandırma yoluyla belirlenir. Yatırım, HedgeDealSelect() işlevi kullanılarak önceden seçilmelidir.

ulong HedgeOrderGetInteger(ENUM_HEDGE_DEAL_PROP_INTEGER property);

Parametreler

  • [içinde] özellik – Yürütülen talimata dahil edilen seçili yatırımın özelliğinin tanımlayıcısı. Değer ENUM_HEDGE_ORDER_PROP_DOUBLE numaralandırma değerlerinden herhangi biri olabilir.

Dönüş Değeri

ulong türünün değeri. Değerin daha fazla kullanımı için, türü açıkça istenen özelliğin türüne çevrilmelidir.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


HedgeDealGetDouble İşlevi()

İşlev yürütülen talimatın bir parçası olan seçili yatırımın özelliğini döndürür. Özellik, double türünde olabilir. Özellik türü, ENUM_HEDGE_DEAL_PROP_DOUBLE numaralandırma yoluyla belirlenir. Yatırım, HedgeDealSelect() işlevi kullanılarak önceden seçilmelidir.

ulong HedgeOrderGetDouble(ENUM_HEDGE_DEAL_PROP_DOUBLE property);

Parametreler

  • [içinde] özellik – Yürütülen talimata dahil edilen seçili yatırımın özelliğinin tanımlayıcısı. Değer, ENUM_HEDGE_DEAL_PROP_DOUBLE numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

çift türünde bir değer.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


2.3. HedgeTerminal Özelliklerini Ayarlamak ve Sahip Olmak için Numaralandırmalar

HedgePropertySetInteger İşlevi()

İşlev, HedgeTerminal özelliklerinden birini ayarlar. Özellik, int, long, datetime veya bool türünde olabilir. Özellik türü, ENUM_HEDGE_PROP_INTEGER numaralandırma yoluyla belirlenir.

bool HedgePropertySetInteger(ENUM_HEDGE_PROP_INTEGER property, long value);

Parametreler

  • [içinde] özellik – HedgeTerminal için ayarlanması gereken özelliğin tanımlayıcısı. Değer, ENUM_HEDGE_PROP_INTEGER numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

bool türünde bir değer. Özellik başarıyla ayarlanmışsa işlev doğru değerini verir, aksi takdirde yanlış değerini verir.

Kullanım Örneği

Örnekte, işlev, eşzamansız bir istek gönderirken pozisyon kilitleme süresini ayarlamak için kullanılır. Eşzamansız bir istek gönderdikten sonra 30 saniye içinde sunucu yanıtı alınmazsa engellenen pozisyonun engellemesi kaldırılacaktır.

void SetTimeOut()
  {
   bool res=HedgePropertySetInteger(HEDGE_PROP_TIMEOUT,30);
   if(res)
      printf("The property is set successfully");
   else
      printf("Property is not set");
  }

HedgePropertyGetInteger İşlevi()

İşlev, HedgeTerminal özelliklerinden birini alır. Özellik, int, long, datetime veya bool türünde olabilir. Özellik türü, ENUM_HEDGE_PROP_INTEGER numaralandırma yoluyla belirlenir.

long HedgePropertyGetInteger(ENUM_HEDGE_PROP_INTEGER property);

Parametreler

  • [içinde] özellik – HedgeTerminal'den alınması gereken özelliğin tanımlayıcısı. Değer, ENUM_HEDGE_PROP_INTEGER numaralandırma değerlerinden biri olabilir.

Dönüş Değeri

uzun türünde bir değer.

Kullanım Örneği

İşlev, asenkron bir istek gönderirken pozisyon engelleme süresini alır ve bunu terminalde gösterir.

void GetTimeOut()
  {
   int seconds=HedgePropertyGetInteger(HEDGE_PROP_TIMEOUT);
   printf("Timeout is "+(string) seconds);
  }

2.4. Hata Kodlarına Sahip Olma ve İşleme İşlevleri

İşlev HedgeDealGetInteger()

İşlev son eylemden elde edilen hatanın tanımlayıcısını dönüştürür. Hata tanımlayıcısı, ENUM_HEDGE_ERR numaralandırmasına karşılık gelir.

ENUM_HEDGE_ERR GetHedgeError(void);

Dönüş Değeri

Pozisyon ID. Değer, ENUM_HEDGE_ERR numaralandırma türünden herhangi biri olabilir.

Not

Çağrıdan sonra GetHedgeError() işlevi hata kimliğini sıfırlamaz. Hata kimliğini sıfırlamak için ResetHedgeError() işlevini kullanın.

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


İşlev ResetHedgeError()

İşlev, alınan son hatanın tanımlayıcısını sıfırlar. Çağrıdan sonra GetHedgeError() tarafından dönüştürülen ENUM_HEDGE_ERR tanımlayıcısı, HEDGE_ERR_NOT_ERROR değerine eşit olacaktır.

void ResetHedgeError(void);

Kullanım Örneği

Bu makalenin 1.11 bölümündeki işlev kullanımı örneğine bakın: "Script Örneği ile İki Yönlü Pozisyon Özelliklerinin Yönetimi".


İşlev TotalActionsTask()

Pozisyon, HedgePositionSelect() işlevi kullanılarak seçildikten sonra, SendTradeRequest() işlevi kullanılarak değiştirilebilir. Örneğin, kapatılabilir veya giden yorumu değiştirilebilir. Bu değişiklik, özel bir alım satım görevi tarafından gerçekleştirilir. Her görev, birkaç alım satım faaliyetinden (alt görevler) oluşabilir. Bir görev başarısız olabilir. Bu durumda, ne tür alt görevlerin başarısız olduğunu görmek için göreve dahil edilen tüm alt görevlerin sonucunu analiz etmeniz gerekebilir.

TotalActionTask() işlevi, seçilen pozisyon için yürütülen son alım satım görevinde bulunan alt görevlerin sayısını verir. Alt görevlerin toplam sayısını bilerek, indekslerine göre tüm alt görevleri arayabilir ve GetActionResult() işlevini kullanarak yürütme sonuçlarını analiz edebilir ve böylece başarısızlığın koşullarını öğrenebilirsiniz.

uint TotalActionsTask(void);

Dönüş Değeri

Görev içindeki toplam alt görev sayısını verir.

Kullanım Örneği

Bu makalenin 1.6 bölümündeki kullanım örneğine bakın: "TotalActionsTask() ve GetActionResult() Kullanılarak Alım Satımın Ayrıntılı Analizi ve Hataların Belirlenmesi".


GetActionResult İşlevi()

İşlev, görev içindeki alt görevin indeksini alır (bkz. TotalActionTask()). Referans parametreleri aracılığıyla alt görevin türünü ve yürütme sonuçlarını verir. Alt görevin türü, ENUM_TARGET_TYPE numaralandırmasıyla tanımlanır. Alt görev yürütme sonucu, MetaTrader 5 alım satım sunucusu dönüş kodlarına karşılık gelir.

void GetActionResult(uint index, ENUM_TARGET_TYPE& target_type, uint& retcode);

Parametreler

  • [içinde] dizin – Alt görevler listesindeki alt görevin indeksi.
  • [dışında] target_type – Alt görevin türü. Değer, ENUM_TARGET_TYPE numaralandırma değerlerinden biri olabilir.
  • [dışında] retcode – Alt görevin yürütülmesi sonrasında alınan alım satım sunucusu dönüş kodu.

Kullanım Örneği

Bu makalenin 1.6 bölümündeki kullanım örneğine bakın: "TotalActionsTask() ve GetActionResult() Kullanılarak Alım Satımın Ayrıntılı Analizi ve Hataların Belirlenmesi".


2.5. Alım satım

SendTradeRequest İşlevi()

İşlev, HedgeTerminalAPI'de seçilen çift yönlü pozisyonu değiştirmek için bir istek gönderir. İşlev yürütme sonucu, üç eylemden biridir:

  1. Bir pozisyonu veya hacminin bir kısmını kapatmak;
  2. Zararı durdur ve karı al seviyelerinin tetiklenmesi;
  3. Giden yorumun modifikasyonu.

Eylem türü ve parametreleri, parametre olarak referans ile devreden HedgeTradeRequest yapısında belirtilir. Çift yönlü pozisyon, işlev çağrısından önce TransactionSelect() işlevi kullanılarak önceden seçilmelidir.

bool SendTradeRequest(HedgeTradeRequest& request);

Parametreler

[içinde] istek – Çift yönlü pozisyonu değiştirme isteğinin yapısı. Lütfen HedgeTradeRequest yapısının açıklamasında yapı açıklamasına ve alanlarının tanımlamasına bakın.

Dönüş Değeri

Pozisyon değiştirme isteği başarıyla yürütüldüyse doğru değerini verir. Aksi takdirde false değerini verir. İstek yürütme hatası durumunda, hatayı ve nedenlerini bulmak için TotalActionsTask() ve GetActionResult() işlevlerini kullanın.

Not

Eşzamansız istek gönderme modunda, bir görev başarıyla yerleştirilmiş ve başlatılmışsa dönüş bayrağı doğru değerini içerir. Ancak, bir görevin başarılı bir şekilde başlatılması durumunda bile, yerine getirilmesinin garanti edilemeyeceğini unutmamalıyız. Bu nedenle bu bayrak, eşzamansız modda görevin tamamlanmasını kontrol etmek için kullanılamaz. Eşzamanlı modda, bir görev tek bir iş parçacığında başlatılır ve yürütülür, bu nedenle eşzamanlı modda, bu bayrağı kullanarak alım satım isteği yürütme sonucunu kontrol edebilirsiniz.


HedgeTradeRequest Alım Satım İsteği Yapısı()

HedgeTerminal'deki iki yönlü pozisyonlar kapatılır ve alım satım isteğinin bir argüman olarak kullanıldığı SendTradeRequest() işlevinin çağrısı aracılığıyla değiştirilir. İstek, seçilen pozisyonu kapatmak veya değiştirmek için gerekli tüm alanları içeren önceden tanımlanmış özel bir HedgeTradeRequest yapısı ile temsil edilir:

struct HedgeTradeRequest
  {
   ENUM_REQUEST_TYPE action;             // type of action
   double            volume;             // volume of position
   ENUM_CLOSE_TYPE   close_type;         // Marker of closing order
   double            sl;                 // stop-loss level
   double            tp;                 // take-profit level
   string            exit_comment;       // outgoing comment
   uint              retcode;            // last retcode in executed operation
   bool              asynch_mode;        // true if the closure is performed asynchronously, otherwise false
   ulong             deviation;          // deviation in step price
                     HedgeTradeRequest() // default params
     {
      action=REQUEST_CLOSE_POSITION;
      asynch_mode=false;
      volume=0.0;
      sl = 0.0;
      tp = 0.0;
      retcode=0;
      deviation=3;
     }
  };

Alanların açıklaması

AlanAçıklama
 eylem Pozisyonla birlikte gerekli eylemin türü. Değer, ENUM_REQUEST_TYPE numaralandırma değerlerinden biri olabilir
 Hacim Kapatılacak hacim. Mevcut durumda aktif olan pozisyonun hacminden daha az olabilir. Hacim sıfır ise aktif pozisyon tamamen kapatılacaktır.
 sl Aktif pozisyon için yerleştirilecek zarar durdurma seviyesi.
 tp Aktif pozisyon için yerleştirilecek kar alma seviyesi.
 exit_comment  Aktif pozisyon için giden yorum.
 retcode Son yürütülen işlemin sonuç kodu.
 asynch_mode İstekleri göndermek için eşzamansız mod kullanılıyorsa doğru, değilse yanlış.
 sapma Kullanılan fiyattan maksimum sapma.


2.6. İşlem Seçim İşlevleriyle Çalışmak için Numaralandırmalar

ENUM_TRANS_TYPE

Bekleyen talimatlar ve çift yönlü pozisyonlar dahil olmak üzere analiz için mevcut tüm işlemler, etkin ve geçmiş işlemler listesindedir.

ENUM_TRANS_TYPE numaralandırması, seçilen her işlemin türünü içerir. Bu numaralandırma, TransactionType() işlevi tarafından verilir. Aşağıda numaralandırma alanları ve açıklamaları yer almaktadır:

AlanAçıklama
 TRANS_NOT_DEFINED İşlem, TransactionSelect() işlevi tarafından seçilmedi veya türü tanımsız.
 TRANS_HEDGE_POSITION İşlem çift yönlü bir pozisyondur.
 TRANS_BROKERAGE_DEAL  İşlem bir komisyoncu yatırımıdır (hesap işlemi). Örneğin hesaba para ekleme veya düzeltme.
 TRANS_PENDING_ORDER İşlem bekleyen bir talimattır.
 TRANS_SWAP_POS İşlem, net bir pozisyon için ücretlendirilen bir swaptır.


ENUM_MODE_SELECT

Numaralandırma, TransactionSelect() işlevinde ayarlanan indeks parametresinin türünü tanımlar.

AlanAçıklama
 SELECT_BY_POS İndeks parametresi, işlemin indeksini listede devretmek için kullanılır.
 SELECT_BY_TICKET Bilet numarası indeks parametresinde devredilir.


ENUM_MODE_TRADES

Numaralandırma, TransactionSelect() kullanılarak bir işlemin seçildiği veri kaynağını tanımlar.

AlanAçıklama
 MODE_TRADES İşlem, aktif işlemlerden seçilir.
 MODE_HISTORY İşlem, geçmiş işlemlerden seçilir.

2.7. İşlem Özelliklerini Sahip Olan İşlevlerle Çalışmak için Numaralandırmalar

Numaralandırma ENUM_TRANS_DIRECTION

Her işlemin, ister yatırım isterse çift yönlü bir pozisyon olsun, bir piyasa yönü vardır.

Bu piyasa yönü, ENUM_TRANS_DIRECTION numaralandırmasıyla tanımlanır. Aşağıda alanları ve açıklamaları yer almaktadır:

AlanAçıklama
 TRANS_NDEF Bir işlemin yönü tanımsız. Örneğin komisyoncunun hesaptaki işlemleri piyasa yönüne sahip değildir ve bu değiştirici ile birlikte gelir.
 TRANS_LONG İşlemin (talimat veya çift yönlü pozisyon) Satın Alma işlemi olduğunu gösterir.
 TRANS_SHORT  İşlemin (talimat veya çift yönlü pozisyon) Satış işlemi olduğunu gösterir.


NumaralandırmaENUM_HEDGE_ORDER_PROP_DOUBLE

Numaralandırma, iki yönlü bir pozisyonun statüsünü içerir.

AlanAçıklama
 HEDGE_POSITION_ACTIVE  Aktif bir pozisyon. Aktif pozisyonlar, HedgeTerminal panelinin Aktif sekmesinde görünür.
 >HEDGE_POSITION_HISTORY  Geçmişe yönelik bir pozisyon. Geçmişe yönelik pozisyonlar, HedgeTerminal panelinin Geçmiş sekmesinde görünür.


NumaralandırmaENUM_HEDGE_POSITION_STATE

Numaralandırma, iki yönlü bir pozisyonun durumunu içerir.

AlanAçıklama
 POSITION_STATE_ACTIVE Seçilen pozisyon aktiftir ve HedgeTradeRequest kullanılarak değiştirilebilir.
 POSITION_STATE_FROZEN  Seçilen pozisyon kilitlidir ve değiştirilemez. Bu değiştirici alınırsa, pozisyonun kilidi açılana kadar beklenmelidir.


NumaralandırmaENUM_HEDGE_POSITION_PROP_INTEGER

Numaralandırma, HedgePositionGetInteger() tarafından dönüştürülen özelliğin türünü ayarlar.

AlanAçıklama
 HEDGE_POSITION_ENTRY_TIME_SETUP_MSC Çift yönlü pozisyonu başlatan talimatın verildiği 01.01.1970 tarihinden itibaren milisaniye cinsinden süre.
 HEDGE_POSITION_ENTRY_TIME_EXECUTED_MSC  Çift yönlü pozisyonu başlatan talimatın yürütüldüğü 01.01.1970 tarihinden itibaren milisaniye cinsinden süre (pozisyon açma zamanı).
 HEDGE_POSITION_EXIT_TIME_SETUP_MSC Çift yönlü pozisyonu kapatma talimatının verildiği 01.01.1970 tarihinden itibaren milisaniye cinsinden süre.
 HEDGE_POSITION_EXIT_TIME_EXECUTED_MSC Çift yönlü pozisyonu kapatma talimatının yürütüldüğü 01.01.1970'den bu yana milisaniye cinsinden süre (pozisyon kapatma süresi).
 HEDGE_POSITION_TYPE Çift yönlü pozisyonun türü. Başlatma talimatının türüne eşittir. ENUM_ORDER_TYPE sistem numaralandırma değerlerinden birini içerir.
HEDGE_POSITION_DIRECTION Pozisyon yönü. ENUM_TRANS_DIRECTION numaralandırmasıyla tanımlanır.
 HEDGE_POSITION_MAGIC Seçilen pozisyonun ait olduğu Expert Advisor'ın sihirli numarası. Sıfır değeri, pozisyonun manuel olarak açıldığını gösterir.
HEDGE_POSITION_CLOSE_TYPE Pozisyonu kapatan talimatın işareti. ENUM_CLOSE_TYPE tarafından tanımlanır.
 HEDGE_POSITION_ID Pozisyon ID. Başlatma talimatının tanımlayıcısına eşittir.
 HEDGE_POSITION_ENTRY_ORDER_ID Başlatma talimatının tanımlayıcısı.
 HEDGE_POSITION_EXIT_ORDER_ID Geçmiş zamanlı pozisyonu kapatan talimat tanımlayıcısı.
 HEDGE_POSITION_STATUS Pozisyon statüsü. ENUM_HEDGE_POSITION_STATUS tarafından tanımlanır.
 HEDGE_POSITION_STATE Pozisyon durumu. ENUM_HEDGE_POSITION_STATE tarafından tanımlanır. 
 HEDGE_POSITION_USING_SL Zarar durdurma bayrağı. Zarar durdurma kullanılırsa, HedgePositionGetInteger() işlevi doğru, aksi takdirde yanlış dönüşür.
 HEDGE_POSITION_USING_TP Kullanılmış bir kar alma seviyesi bayrağı. Kar alma kullanılırsa, HedgePositionGetInteger() doğru, aksi takdirde yanlış dönüşür.
 HEDGE_POSITION_TASK_STATUS Seçilen pozisyon için gerçekleştirilmekte olan görevin statüsü. Pozisyon modifikasyon altında olabilir. Bu değiştirici, bu pozisyondaki değişiklikleri izlemek için kullanılır. Pozisyon durumu, ENUM_TASK_STATUS ile tanımlanır.
 HEDGE_POSITION_ACTIONS_TOTAL Bu pozisyonu değiştirmek için başlatılan toplam alt görevlerin sayısını verir.

 

Numaralandırma ENUM_HEDGE_POSITION_PROP_DOUBLE

Numaralandırma, HedgePositionGetDouble() işlevi tarafından dönüştürülen özelliğin türünü ayarlar.

AlanAçıklama
HEDGE_POSITION_HACİM Çift yönlü pozisyonun hacmi.
HEDGE_POSITION_PRICE_OPEN Pozisyonun ortalama ağırlıklı açılış fiyatı.
HEDGE_POSITION_PRICE_CLOSED Bir pozisyonun ortalama ağırlıklı kapanış fiyatı.
HEDGE_POSITION_PRICE_CURRENT Aktif pozisyonun mevcut fiyatı. Bu değiştirici geçmişe yönelik pozisyon için pozisyon kapanış fiyatını dönüştürür.
HEDGE_POSITION_SL Zarar durdurma seviyesini. Zarar durdurma kullanılmazsa sıfırdır.
HEDGE_POSITION_TP Kar alma seviyesi. Kar alma kullanılmazsa sıfırdır.
HEDGE_POSITION_COMMISSION Pozisyon için ödenen komisyon tutarı.
HEDGE_POSITION_SLIPPAGE Puanlarda mali kayma.
HEDGE_POSITION_PROFIT_CURRENCY  Pozisyonun karı veya kaybı. Değer, mevduat para biriminde belirtilir.
HEDGE_POSITION_PROFIT_POINTS Pozisyonun karı veya kaybı. Değer, pozisyonun finansal sembol noktalarında belirtilir.

Not

HEDGE_POSITION_SLIPPAGE mali kayması, en iyi pozisyon giriş yatırımı ile ortalama ağırlıklı giriş fiyatı arasındaki puan farkı olarak hesaplanır.

 

NumaralandırmaENUM_HEDGE_POSITION_PROP_STRING

Numaralandırma, HedgePositionGetString() işlevi tarafından dönüştürülen özelliğin türünü ayarlar.

AlanAçıklama
 HEDGE_POSITION_SYMBOL Geçerli pozisyonun sembolü.
HEDGE_POSITION_ENTRY_COMMENT Pozisyonun gelen yorumu.
 HEDGE_POSITION_EXIT_COMMENT Pozisyonun giden yorumu.

 

Numaralandırma ENUM_HEDGE_ORDER_STATUS

Numaralandırma, talimat türünü içerir.

AlanAçıklama
 HEDGE_ORDER_PENDING  Talimat beklemede ve MetaTrader 5'in Alım Satım sekmesinde mevcuttur.
 HEDGE_ORDER_HISTORY Talimat geçmişe yöneliktir ve MetaTrader 5'teki talimat geçmişinde mevcuttur.

NumaralandırmaENUM_HEDGE_ORDER_SELECTED_TYPE

Numaralandırma, HedgeOrderSelect() işlevi tarafından seçilen talimatın türünü tanımlar.

AlanDeğer
 ORDER_SELECTED_INIT Talimat çift yönlü bir pozisyon başlatır.
 ORDER_SELECTED_CLOSED  Talimat çift yönlü bir pozisyonu kapatır.
 ORDER_SELECTED_SL Talimat zarar durdurma seviyesi olarak hareket eder.


NumaralandırmaENUM_HEDGE_ORDER_PROP_INTEGER

Numaralandırma, HedgePositionGetInteger() işlevi tarafından dönüştürülen özelliğin türünü ayarlar.

AlanAçıklama
 HEDGE_ORDER_ID Benzersiz bir talimat tanımlayıcısı.
 HEDGE_ORDER_STATUS Talimat statüsü. Değer, ENUM_HEDGE_ORDER_STATUS numaralandırma değerlerinden biri olabilir.
 HEDGE_ORDER_DEALS_TOTAL Talimatı dolduran toplam yatırım sayısı. Bekleyen talimatlar için değer sıfırdır.
 HEDGE_ORDER_TIME_SETUP_MSC 01.01.1970 tarihinden bu yana milisaniye cinsinden bekleyen talimat verme süresi.
 HEDGE_ORDER_TIME_EXECUTED_MSC 01.01.1970'den beri yürütülen bir talimatın milisaniye cinsinden yürütme süresi.
 HEDGE_ORDER_TIME_CANCELED_MSC 01.01.1970 tarihinden bu yana yürütülen bir talimatın milisaniye cinsinden iptal süresi.

Not

Talimat yürütme süresi HEDGE_ORDER_TIME_EXECUTED_MSC, en son yatırım zamanına eşittir. 


NumaralandırmaENUM_HEDGE_ORDER_PROP_DOUBLE

Numaralandırma, HedgeOrderGetDouble() işlevi tarafından dönüştürülen özelliğin türünü ayarlar.

AlanAçıklama
 HEDGE_ORDER_VOLUME_SETUP Talimatta belirtilen talimat hacmi.
 HEDGE_ORDER_VOLUME_EXECUTED Gerçekleştirilen talimat hacmi. Beklemede olan bir talimat varsa, yürütülen hacim sıfırdır.
 HEDGE_ORDER_VOLUME_REJECTED Gerçekleştirilemeyen talimat hacmi. İlk hacim ile yürütülen hacim arasındaki farka eşittir.
 HEDGE_ORDER_PRICE_SETUP Talimat verme fiyatı.
HEDGE_ORDER_PRICE_EXECUTED Bir talimatın ortalama ağırlıklı yürütme fiyatı.
HEDGE_ORDER_COMMISSION Talimatın yürütülmesi için komisyoncuya ödenen komisyon tutarı. Mevduat para biriminde belirtilir.
 HEDGE_ORDER_SLIPPAGE Talimat kayması.

Not

HEDGE_ORDER_SLIPPAGE mali kayması, gerçekleştirilen en iyi yatırım ile talimatın ağırlıklı ortalama giriş fiyatı arasındaki puan farkı olarak hesaplanır.


Numaralandırma ENUM_HEDGE_DEAL_PROP_INTEGER

Numaralandırma, HedgeDealGetInteger() tarafından dönüştürülen özelliğin türünü ayarlar.

AlanAçıklama
 HEDGE_DEAL_ID Benzersiz bir yatırım tanımlayıcısı.
 HEDGE_DEAL_TIME_EXECUTED_MSC 01.01.1970 tarihinden bu yana milisaniye cinsinden yatırım yürütme süresi


Numaralandırma ENUM_HEDGE_DEAL_PROP_DOUBLE

Numaralandırma, HedgeDealGetDouble() tarafından dönüştürülen özelliğin türünü ayarlar.

AlanAçıklama
 HEDGE_DEAL_VOLUME_EXECUTED Bir yatırımın hacmidir.
 HEDGE_DEAL_PRICE_EXECUTED Yatırım yürütme modu.
 HEDGE_DEAL_COMMISSION Yatırımın yürütülmesi için komisyoncuya ödenen komisyon tutarı. Mevduat para biriminde belirtilir.

 

2.8. HedgeTerminal Özelliklerini Ayarlamak ve Almak için Numaralandırmalar

Numaralandırma ENUM_HEDGE_PROP_INTEGER

Numaralandırma HedgeTerminal'de almak veya ayarlamak istediğiniz özelliğin türünü ayarlar.

AlanAçıklama
 HEDGE_PROP_TIMEOUT HedgeTerminal'in değiştirilmekte olan bir pozisyonun kilidini açmadan önce sunucudan yanıt bekleyeceği saniye cinsinden süre.


2.9. Hata Kodları İşleme İşlevleriyle Çalışmak için Numaralandırmalar

Numaralandırma ENUM_TASK_STATUS

Çift yönlü her pozisyon modifikasyon altında olabilir. Bir pozisyon, bir alım satım görevi aracılığıyla değiştirilir.

Çalışan her alım satım görevinin ENUM_TASK_STATUS içinde tanımlanan yürütme durumu vardır. Aşağıda alanları ve açıklamaları yer almaktadır:

AlanAçıklama
 TASK_STATUS_WAITING Geçerli görev yoktur veya görev bekleniyor.
 TASK_STATUS_EXECUTING Alım satım görevi şu anda yürütülüyor.
 TASK_STATUS_COMPLETE Pozisyon için alım satım görevi başarıyla tamamlandı.
TASK_STATUS_FAILED Pozisyon için alım satım görevi başarısız oldu.


Numaralandırma ENUM_HEDGE_ERR

Numaralandırma, GetHedgeError() tarafından dönüştürülebilecek hatanın kimliğini içerir.

AlanAçıklama
 HEDGE_ERR_NOT_ERROR Hata yoktur.
 HEDGE_ERR_TASK_FAILED Seçilen pozisyon için görev başarısız oldu.
 HEDGE_ERR_TRANS_NOTFIND İşlem bulunamadı.
 HEDGE_ERR_WRONG_INDEX Yanlış endeks.
 HEDGE_ERR_WRONG_VOLUME Yanlış hacim.
 HEDGE_ERR_TRANS_NOTSELECTED  İşlem, TransactionSelect() kullanılarak önceden seçilmedi.
 HEDGE_ERR_WRONG_PARAMETER Geçen parametrelerden biri yanlış.
 HEDGE_ERR_POS_FROZEN Çift yönlü pozisyon şu anda modifikasyon altındadır ve yeni değişiklikler için kullanılamaz. Pozisyon serbest bırakılıncaya kadar bekleyin.
 HEDGE_ERR_POS_NO_CHANGES Alım satım talebinde değişiklik yok.

 

Numaralandırma ENUM_TARGET_TYPE

Numaralandırma, GetActionResult() işlevi tarafından seçilen görevin türünü tanımlar.

AlanAçıklama
 TARGET_NDEF Alt görev tanımsız.
 TARGET_CREATE_TASK Alt görev şimdi oluşturuluyor. Bu tür, HedgeTerminalAPI'nin dahili mantığında kullanılır.
 TARGET_DELETE_PENDING_ORDER Beklemede olan talimatı silme.
 TARGET_SET_PENDING_ORDER Beklemede olan talimatı yerleştirme.
 TARGET_MODIFY_PENDING_ORDER  Beklemede olan talimat fiyatının modifikasyonu.
 TARGET_TRADE_BY_MARKET Alım satım işlemi yapmak.


2.10. Hata Kodları İşleme İşlevleriyle Çalışmak için Numaralandırmalar

Numaralandırma ENUM_REQUEST_TYPE

Numaralandırma, çift yönlü pozisyona uygulanan HedgeTerminal eylemini açıklar.

AlanAçıklama
REQUEST_CLOSE_POSITION Pozisyonu kapatır. HedgeTradeRequest yapısının hacim alanı mevcut hacmin altında bir hacim içeriyorsa, pozisyonun sadece bir kısmı kapatılacaktır. Bu durumda, kapalı pozisyonun parçası hacim alanının değerine karşılık gelir.
 REQUEST_MODIFY_SLTP Mevcut zararı durdur ve kar al seviyelerini ayarlar veya değiştirir.
REQUEST_MODIFY_COMMENT Aktif bir pozisyonun giden yorumunu değiştirir.


Numaralandırma ENUM_CLOSE_TYPE

Numaralandırma, çift yönlü pozisyonu kapatan talimat için özel bir işaret tanımlar. İşaret, pozisyonun kapanma nedenini gösterir. Aşağıdaki nedenlerden biri olabilir:

  • Pozisyon maksimum zarar seviyesine ulaştı veya zarar durduruldu;
  • Pozisyon belirli bir kar seviyesine ulaştı veya kar alındı;
  • Pozisyon piyasa tarafından kapatıldı. Zararı durdur ve kar al seviyeleri yerleştirilmedi veya ulaşılmadı.
AlanAçıklama
 CLOSE_AS_MARKET Pozisyonun piyasa tarafından kapatıldığını gösterir. Zararı durdur ve kar al seviyeleri yerleştirilmedi veya ulaşılmadı.
 CLOSE_AS_STOP_LOSS Zarar durdur seviyesine ulaşıldığı için pozisyonun kapatıldığını gösterir.
 CLOSE_AS_TAKE_PROFIT  Kar alma seviyesine ulaşıldığı için pozisyonun kapatıldığını gösterir.

 

Bölüm 3. Asenkron Alım Satım Temelleri

Asenkron işlemler konusu karmaşıktır ve ayrı şekilde ayrıntılı makale gerektirir. Ancak HedgeTerminal'in asenkron operasyonları aktif olarak kullanması nedeniyle, bu tür istek gönderimini kullanan Expert Advisors'ın organizasyon prensiplerini kısaca açıklamak yerinde olacaktır. Ek olarak, konuyla ilgili neredeyse hiç materyal yoktur.

3.1. Senkronize İşlem Talimatı Gönderme Organizasyonu ve Şeması

MetaTrader 5, alım satım isteklerini sunucuya göndermek için iki işlev sağlar:

OrderSend() işlevi, isteği doldurulmuş bir MqlTradeRequest yapısı olarak kabul eder ve yapının doğruluğunun temel doğrulamasını gerçekleştirir. Temel doğrulama başarılı olursa, isteği bir sunucuya gönderir, sonucunu bekler ve ardından sonucu MqlTradeResult yapısı ve dönüş bayrağı aracılığıyla özel iş parçacığına gönderir. Temel doğrulama başarısız olursa, işlev negatif bir değer verir.

İsteğin doğrulanamamasının nedeni de MqlTradeResult'da yer almaktadır.

Aşağıdaki şema, OrderSend() işleviyle özel bir MQL5 programının iş parçacığının yürütülmesini içerir:

Şek. 6. Eşzamanlı bir alım satım isteğinin düzenlemesi ve gönderilmesi

Şek. 6. Eşzamanlı bir alım satım isteğinin düzenlemesi ve gönderilmesi.

Şemadan görüldüğü üzere, MQL5 programının iş parçacığı, sunucuya bir istek gönderen ve borsada alım satım işlemlerini yürüten ortak sistem iş parçacığından ayrılamaz.

Bu nedenle OrderSend() tamamlandıktan sonra alım satım isteğinin gerçek sonucunu analiz edebiliriz. Özel iş parçacığı kırmızı oklarla işaretlenmiştir. Neredeyse anında yürütülür. Çoğu zaman borsada alım satım işlemleri yapmak için alınır. İki iş parçacığı bağlı olduğundan, OrderSend() işlevinin başlangıcı ve bitişi arasında önemli miktarda zaman geçer. Alım satım işlemlerinin tek bir iş parçacığında yürütülmesi nedeniyle MQL5 programlarının mantığı sıralı olabilir.


3.2. Asenkron İşlem Talimatı Gönderme Organizasyonu ve Şeması

OrderSendAsync() işlevi farklıdır. OrderSend() gibi, MqlTradeRequest alım satım isteğini kabul eder ve sonucunu gösteren bir bayrak verir.

Ancak, ilk örnekten farklı olarak, alım satım isteğinin sunucu tarafından yürütülmesini beklemez, sadece alım satım ​​isteği değerlerinin temel doğrulama modülünden elde edilen değerleri verir (Terminal içinde temel doğrulama). Aşağıdaki şema, OrderSendAsync() işlevini kullanırken özel iş parçacığı yürütme prosedürünü gösterir:

Şek. 7. Eşzamansız bir alım satım isteğinin organizasyonu ve gönderilmesi şeması

Şek. 7. Eşzamansız bir alım satım isteğinin düzenlemesi ve gönderilmesi şeması.

Bir alım satım isteği başarıyla doğrulandıktan sonra, ana iş parçacığına paralel olarak alım satım sunucusuna gönderilir. İlk durumda olduğu gibi, bir alım satım isteğinin ağ üzerinden iletilmesi ve borsada yürütülmesi biraz zaman alır. Ancak özel iş parçacığı, OrderSendAsync() işlevinden neredeyse anında sonuç alacaktır.

Yukarıdaki şema, OrderSendAsync() öğesinin bir alım satım sunucusu tarafından yürütülen yeni bir paralel iş parçacığı oluşturduğunu ve yürütme sonucunun OnTradeTransaction() veya OnTrade() işlevine girdiğini gösterir. Bu işlevler yeni bir özel iş parçacığı başlatır. Bir alım satım isteği göndermenin sonucu bu yeni iş parçacığında işlenmelidir. Bu, Expert Advisor'ın mantığını büyük ölçüde karmaşıklaştırır, çünkü eşzamansız talimat gönderiminde, isteğin gönderilmesini ve kontrolünü tek bir iş parçacığında organize etmek imkansızdır. Örneğin, bir istek gönderme ve kontrol etme kodunu OnTick()'e sırayla yerleştiremezsiniz.

Yukarıdakileri örneklendirme için basit bir test EA yazalım:

//+------------------------------------------------------------------+
//|                                                    AsynchExp.mq5 |
//|                           Copyright 2014, Vasiliy Sokolov (C-4). |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
input bool UsingAsynchMode=true;
bool sendFlag=false;
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(sendFlag)return;
   printf("Formation of order and send to the server...");
   MqlTradeRequest request={0};
   request.magic=12345;
   request.symbol = Symbol();
   request.volume = 0.1;
   request.type=ORDER_TYPE_BUY;
   request.comment= "asynch test";
   request.action = TRADE_ACTION_DEAL;
   request.type_filling=ORDER_FILLING_FOK;
   MqlTradeResult result;
   uint tiks= GetTickCount();
   bool res = false;
   if(UsingAsynchMode)
      res=OrderSendAsync(request,result);
   else
      res=OrderSend(request,result);
   uint delta=GetTickCount()-tiks;
   if(OrderSendAsync(request,result))
     {
      printf("The order has been successfully"+
             "sent to the server.");
     }
  else
     {
     printf("The order is not shipped."+
             " Reason: "+(string)result.retcode);
     }
   printf("Time to send a trade request: "+(string)delta);
   sendFlag=true;
//---
  }

UseAsynchMode = false ile başlatarak EA'nın çalıştığından emin olalım.

EA 0.1 lotluk uzun bir pozisyon açar. Alım satım isteği, OrderSend() işlevi kullanılarak eşzamanlı olarak gerçekleştirilir. İşte örnek günlüğü:

2014.11.06 17:49:28.442 AsynchExp (AUDCAD,H1)   Time to send a trade request: 94
2014.11.06 17:49:28.442 AsynchExp (AUDCAD,H1)   The order has been successfullysent to the server.
2014.11.06 17:49:28.345 AsynchExp (AUDCAD,H1)   Formation of order and send to the server...

Alım satım isteği 94 milisaniye içinde tamamlandı. Bu sefer bize isteğin temel doğrulamayı geçtiğini, sunucuya gönderildiğini ve ardından doldurulduğunu söylüyor.

Şimdi işlem hacmini mümkün olan maksimum DBL_MAX değerine dönüştürerek EA kodunu değiştiriyoruz:

request.volume = DBL_MAX;

Belli ki, bu değer gerçek aralığın dışındadır. Bu isteği eşzamanlı modda yürütmeyi deneyelim:

2014.11.06 17:54:15.373 AsynchExp (AUDCAD,H1)   Time to send a trade request: 0
2014.11.06 17:54:15.373 AsynchExp (AUDCAD,H1)   The order is not shipped. Reason: 10014
2014.11.06 17:54:15.373 AsynchExp (AUDCAD,H1)   Formation of order and send to the server...

İstek gönderme başarısız oldu. Başarısız olmasının nedeni hata 10014 (Geçersiz istenen hacim). İstek, temel doğrulama sırasında başarısız oldu ve 0 milisaniyelik istek yürütme süresinden anlaşılacağı üzere sunucuya bile gönderilmedi.

Yine, talebi değiştirelim. Bu sefer yeterince büyük bir hacim belirledik, ekstrem bir değer değil – 15 lot. EA'nın test edildiği 1000 dolarlık hesap için çok fazla. Bu hesapta böyle bir pozisyon açılamaz.

OrderSend()'in ne dönüştürdüğünü görelim:

2014.11.06 17:59:22.643 AsynchExp (AUDCAD,H1)   Time to send a trade request: 78
2014.11.06 17:59:22.643 AsynchExp (AUDCAD,H1)   The order is not shipped. Reason: 10019
2014.11.06 17:59:22.550 AsynchExp (AUDCAD,H1)   Formation of order and send to the server...

Hata bu sefer farklıdır: 10019 (Doğru olan talebin yürütülmesi için yetersiz fon). Talep yürütme süresinin artık 79 milisaniye olduğunu unutmayın. Talebin sunucuya gönderildiğini ve sunucunun bir hata dönüştürdüğünü gösterir.

Şimdi aynı italebi OrderSendAsync() işlevini kullanarak 15 lotluk hacimle gönderelim. OrderSend() ile olduğu gibi, hiçbir pozisyon açılmaz. Ancak günlüğü analiz edelim:

2014.11.06 18:03:58.106 AsynchExp (AUDCAD,H1)   Time to send a trade request: 0
2014.11.06 18:03:58.106 AsynchExp (AUDCAD,H1)   The order has been successfully sent to the server.
2014.11.06 18:03:58.104 AsynchExp (AUDCAD,H1)   Formation of order and send to the server...

Günlük hata olmadığını söylüyor! 10019 hatası alım satım sunucusu tarafından algılandığından, eşzamansız talimat gönderme modundaki güncel iş parçacığı için mevcut değildir. Dönen değeri yalnızca isteğin temel doğrulamayı geçtiğini gösterir. Gerçek hata 10019'u almak için, sonuçları EA'mıza eklenmesi gereken OnTradeTransaction() sistem işlevinde yeni bir özel iş parçacığında analiz etmemiz gerekiyor:

void  OnTradeTransaction(const MqlTradeTransaction    &trans,
                         const MqlTradeRequest        &request,
                         const MqlTradeResult         &result)
  {
   uint delta = GetTickCount() - tiks;
   printf("Server answer: " + (string)result.retcode + "; Time: " + (string)delta);
  }

EA'yı tekrar çalıştıralım ve günlükleri görelim:

2014.11.06 18:17:00.943 AsynchExp (AUDCAD,H1)   Server answer: 10019; Time: 94
2014.11.06 18:17:00.854 AsynchExp (AUDCAD,H1)   Time to send a trade request: 0
2014.11.06 18:17:00.854 AsynchExp (AUDCAD,H1)   The order has been successfully sent to the server.
2014.11.06 18:17:00.851 AsynchExp (AUDCAD,H1)   Formation of order and send to the server...

Hata 10019 alındı, ancak gönderildikten hemen sonra değil. OnTradeTransaction() içinde çalışan yeni özel iş parçacığında alındı.


3.3. Eşzamansız Talimat Yürütme Hızı

Yatırımcılar hatalı şekilde eşzamansız bir isteğin yürütme hızının sıfıra yakın olduğuna inanırlar.

Kural olarak bir milisaniyeden daha kısa sürede tamamlanan OrderSendAsync() gözleminden kaynaklanır. Oysa yukarıda gösterildiği gibi, alım satım işleminin gerçek yürütme süresi, OnTradeTransaction() veya OnTrade() işlevleri içinde sunucudan bir yanıt alındığında ölçülmelidir. Bu ölçüm, tek bir alım satım için eşzamanlı yürütmenin hızına eşit olan gerçek hızı gösterir. Yürütme süresindeki gerçek avantajlar, bir işlem grubu gönderirken hissedilir. Birden çok istek göndermeniz gereken en az üç durum vardır:

  • Ardışık iki istek arasındaki gereken süre o kadar küçüktür ki, bir sonrakini göndermeden önce istek sonucunu kontrol etme imkanı yoktur. Bir sonraki istek gönderildiğinde, bir öncekinin yerine getirilmiş olması umulmaktadır. Benzer taktikler yüksek frekanslı alım satımda kullanılır;
  • Aynı anda birden fazla sembol için birden fazla pozisyon açmanız gerekir. Örneğin arbitraj stratejileri ve bileşik sentetik pozisyonlar, cari fiyatlardaki çeşitli enstrümanlar için aynı anda pozisyon açılmasını gerektirir. Bu tür taktiklerde kademeli pozisyon oluşumu istenmeyen bir durumdur;
  • İş parçacığını mümkün olan en kısa sürede tamamlamak ve sonraki olayları ve kullanıcı komutlarını beklemek gerekir. Bu gereksinim, çok iş parçacıklı ve altyapı çözümleri için önemlidir. HedgeTerminal'in eşzamansız istekleri kullanmasının ana nedeni budur. HT eşzamanlı istek göndermeyi kullansaydı, kullanıcı her kapattığında veya pozisyonu değiştirdiğinde sürekli 1-2 saniye boyunca donardı, ki bu durum kabul edilemez.

Birden fazla talimat verirken istek gönderme sınırını dikkate almayı unutmayın.

MetaTrader 5 build 1010 ve üzeri sürümlerde limit 64 işlemdir, bunların 4'ü kullanıcılar için ayrılmıştır ve diğerleri Expert Advisors tarafından kullanılabilir. Sınır, acemi yatırımcıları programlarındaki ciddi hatalardan korumanın yanı sıra bir alım satım işlemi sunucusundaki spam yükünü azaltmayı hedefler.

Bu, aynı zamanda, örneğin for döngüsünde, uygun bir alım satım isteğiyle SendOrderAsync()'i çağırarak 60'a kadar alım satım talimatı gönderebileceğiniz anlamına gelir. 60 işlemin tamamı gönderildikten sonra işlem arabelleği dolacaktır. İşlemlerden birinin sunucu tarafından işlendiğine dair sunucudan onay beklememiz gerekiyor.

İşlendikten sonra, bir işlemin işlem arabellekteki yeri serbest bırakılır ve yerine yeni bir alım satım isteği geçebilir. Arabellek dolduğunda, yeni işlemler için alan yavaşça serbest bırakılır, çünkü işlem sunucusunun her işlemi işlemesi için zamana ihtiyaç vardır ve işlemenin başladığını bildiren TradeTransaction() etkinliği ağ üzerinden iletilir, bu da ek gecikmelere neden olur.

Böylece, istek göndermek için gereken süre, istek sayısındaki artışa kıyasla doğrusal olmayan bir şekilde artacaktır. Aşağıdaki tablo, asenkron moddaki talimat gönderme oranlarını tahmini olarak göstermektedir. Testler birkaç kez gerçekleştirildi ve gösterilen oran ortalama değerdir:

Talep sayısıZaman, milisaniye
5050
100180
2002100
5009000
100023000

Talep sayısının 60'tan az olduğu durumda script sunucu yanıtını beklemez, bu yüzden süre çok azdır. Yaklaşık olarak tek bir talep göndermek için gereken süreye eşittir. Aslında, yaklaşık bir gerçek yürütme süresi elde etmek için, tabloda belirtilen istek yerleştirme süresine ortalama istek yürütme süresini ekleyin.

 

Bölüm 4. MetaTrader 5 IDE'de Çok İş Parçacıklı Programlamanın Temelleri

MQL5 programcıları, iş parçacıklarının doğrudan MQL programlarından kontrol edilemeyeceğini bilir. Bu kısıtlama acemi programcıların iyiliği içindir, çünkü iş parçacıklarının kullanımı program algoritmalarını büyük ölçüde karmaşıklaştırır. Ancak bazı durumlarda, iki veya daha fazla EA birbiriyle iletişim kurmalı, örneğin küresel verileri oluşturmalı ve okumalıdır.

HedgeTerminal bu tür EA'lardan biridir. HedgeTerminalAPI kitaplığını kullanan her EA'yı diğer Expert Advisor'ların eylemleri hakkında bilgilendirmek için HT, ActivePositions.xml dosyasının çok iş parçacıklı okunması ve yazılması yoluyla veri alışverişini düzenler. Bu çözüm önemsiz değildir ve MQL programcıları tarafından nadiren kullanılır. Bu nedenle HedgeTerminal'e benzer bir algoritma ile çok iş parçacıklı bir EA oluşturacağız. Bu, çok iş parçacıklı programlamayı daha iyi anlamaya yardımcı olacak ve böylece HedgeTerminal'in nasıl çalıştığını daha iyi anlamayı sağlayacaktır.


4.1. Kotasyon Toplayıcı Örneği UnitedExchangeQuotes ile Çok İş Parçacıklı Programlama

Belirli bir örnek üzerinden çok iş parçacıklı programlamanın temellerini öğreneceğiz: farklı sağlayıcılardan (komisyonculardan) bir kotasyon toplayıcı yazacağız.

Fikir şöyle: Diyelim ki aynı enstrüman için kotasyon veren 6-7 komisyoncumuz var. Doğal olarak, farklı brokerlerin teklifleri biraz değişken olabilir. Bu farklılıkların analizi, arbitraj stratejilerinin yolunu açar. Ek olarak, teklif dinamiklerinin karşılaştırılması en iyi ve en kötü sağlayıcının belirlenmesine yardımcı olacaktır. Örneğin, bir komisyoncu daha iyi fiyatlar sağlıyorsa alım satım işlemi yapmak için bu komisyoncuyu tercih ederiz. Sonuçların pratik değerini aramıyoruz, bunun yerine sadece bu sonuçların elde edilebileceği mekanizmayı tanımlıyoruz.

İşte bu bölümün sonunda yazmamız gereken EA'nın bir ekran görüntüsü:

Şek. 8 Teklif toplayıcı UnitedExhangesQuotes'un görünümü.

Şek. 8. Teklif toplayıcı UnitedExhangesQuotes'un görünümü.

Expert Advisor, sonuçları dört sütun ve sınırsız sayıda satırdan oluşan basit bir tabloda görüntüler.

Her satır, sembol teklifleri sağlayan bir komisyoncuyu temsil eder (bu durumda EURUSD). Satış ve Teklif, komisyoncunun en iyi teklifi ve talebidir. Ekran görüntüsü fiyatların biraz farklı olduğunu gösteriyor. Mevcut komisyoncunun teklifi ile diğerinin teklifi arasındaki fark D-ASK (Delta Satış) sütununda görünür. Benzer şekilde, talep değerleri arasındaki fark D-BID'de (Delta Teklif) görüntülenir. Örneğin ekran görüntüsü alındığında en iyi Satış "Alpari Limited" tarafından sağlandı ve en pahalısı "Bank VTB 24" idi.

MQL programları, diğer MetaTrader terminallerinin ortamına erişemez. Başka bir deyişle, bir program bir terminalde çalışıyorsa diğerinden veri alamaz. Ancak, tüm MQL programları MetaTrader terminallerinin paylaşılan dizinindeki dosyalar aracılığıyla iletişim kurabilir. Herhangi bir program, örneğin geçerli kotasyon gibi bilgileri bir dosyaya yazarsa, MQL programı bunu başka bir terminalden okuyabilir. MQL'nin harici DLL'ler olmadan başka bir yolu yoktur. Bu nedenle, bu yöntemi kullanacağız.

En büyük zorluk, bu tür erişimi organize etmektir. Bir yandan, EA diğer sağlayıcılardan kotasyonları okumak ve diğer yandan, sağlayıcısının fiyat teklifini aynı dosyaya yazmak zorundadır. Başka bir sorun, kotasyonları okurken başka bir EA'nın bu dosyaya yeni bir fiyat teklifi yazabilmesidir. Bu tür paralel çalışmanın sonucu tahmin edilemez. En iyi ihtimalle, bunu bir çökme ve program kesintisi takip edecek ve en kötü ihtimalle bu, kotasyonların görüntülenmesiyle bağlantılı garip yakalaması güç hataların ara sıra ortaya çıkmasına yol açacaktır.

Bu hataları ortadan kaldırmak veya en azından oluşma olasılığını en aza indirmek için net bir plan geliştireceğiz.

İlk olarak, tüm bilgiler XML formatında saklanacaktır. Bu format, beceriksiz ini dosyasının yerini aldı. XML, düğümlerinin sınıflar gibi karmaşık veri yapılarına esnek şekilde yerleştirilmesine izin verir. Ardından, genel okuma ve yazma algoritmasını belirleyelim. İki temel işlem vardır: veri okuma ve veri yazma. Herhangi bir MQL programı okurken veya yazarken, başka hiçbir program bu dosyaya erişemez. Böylece bir programın verileri okuduğu ve ikincisinin bunları değiştirdiği bir durumu ortadan kaldırıyoruz. Bu nedenle, verilere erişim her zaman mümkün olmayacaktır.

XML erişim algoritmalarını ve bu dosyadaki tüm kotasyonların verilerini içerecek özel bir CQuoteList sınıfı oluşturalım.

Bu sınıfın işlevlerinden biri TryGetHandle()'dir, dosyaya erişmeye çalışır ve başarılı olması durumunda tanıtıcısını verir. İşlevin uygulanması şu şekildedir:

int CQuoteList::TryGetHandle(void)
{
   int attempts = 10;
   int handle = INVALID_HANDLE;
   // We try to open 'attemps' times
   for(att = 0; att < attempts; att++)
   {
      handle = FileOpen("Quotes.xml", FILE_WRITE|FILE_READ|FILE_BIN|FILE_COMMON);
      if(handle == INVALID_HANDLE)
      {
         Sleep(15);
         continue;
      }
      break;
   }
   return handle;
}

Dosyayı birleşik okuma/yazma modunda açmak için birkaç girişimde bulunur. Varsayılan deneme sayısı on'dur.

Bir deneme başarılı olmazsa işlev 15 milisaniye donar ve dosyayı açmayı yeniden dener, bu şekilde en fazla 10 deneme yapar.

Dosya açıldığında, tanıtıcı LoadQuotes() işlevine devredilir. Bu işlevin tam listesi ve CQuoteList sınıfı, makaleye ek olarak mevcuttur. Yani burada sadece işlevdeki eylemlerin sıralamasını tanımlıyoruz:

  1. TryGetHandle(), okumak ve yazmak için dosyayı açar;
  2. XML belgesi, XML Ayrıştırıcı kitaplığı kullanılarak EA belleğine yüklenir;
  3. Yüklenen XML belgesine dayalı olarak, gerekli bilgileri depolayan yeni bir dizi kotasyon oluşturulur;
  4. Oluşturulan dizi, mevcut EA'ya ait bir kotasyon içerir. Değerleri ​​güncellenir;
  5. Kotasyon dizisi tekrar bir XML belgesine dönüştürülür. Açık XML dosyasının içeriği bu XML belgesiyle değiştirilir;
  6. Kotasyonların XML dosyası kapatılır.

LoadQuotes() işlevi harika bir iş çıkarır, ancak çoğu durumda 1 milisaniyeden az sürer.

Veri okuma ve veri güncelleme, bunların daha fazla kaydedilmesiyle tek bir blokta birleştirilir. Bu, okuma ve yazma işlemleri arasında dosyaya erişim kontrolünü kaybetmemek için bilerek yapılır.

Kotasyonlar yüklendikten ve bir sınıfa girdikten sonra, MetaTrader 5'teki diğer veriler gibi bunlara da erişilebilir. Bu, CQuotesList sınıfında uygulanan özel bir MetaTrader 5 stili program arabirimi aracılığıyla yapılır.

İşlev çağrısı ve veri işleme, OnTick() bloğu içinde gerçekleştirilir. İçerikler şöyledir:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
      return;
   if(!QuotesList.LoadQuotes())    
      return;   
   PrintQuote quote = {0};
   Panel.DrawAccess(QuotesList.CountAccess());
   double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
   double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
   string brokerName = AccountInfoString(ACCOUNT_COMPANY);
   for(int i = 0; i < QuotesList.BrokersTotal(); i++)
   {
      if(!QuotesList.BrokerSelect(i))
         continue;
      if(!QuotesList.SymbolSelect(Symbol()))
         continue;
      quote.ask = QuotesList.QuoteInfoDouble(QUOTE_ASK);
      quote.bid = QuotesList.QuoteInfoDouble(QUOTE_BID);
      quote.delta_ask = ask - quote.ask;
      quote.delta_bid = quote.bid - bid;
      quote.broker_name = QuotesList.BrokerName();
      quote.index = i;
      Panel.DrawBroker(quote);
   }
  }

Örnek kodun hem MetaTrader 4'te hem de MetaTrader 5'te herhangi bir ek değişiklik yapmadan çalışıyor olması önemlidir!

Panellerin, terminalin farklı versiyonlarındaki görüntülenme biçiminde yalnızca küçük kozmetik farklılıklar vardır. Kuşkusuz bu, platformlar arasında kod taşımayı kolaylaştıran dikkat çekici bir undurdur.

EA'nın çalışması en iyi şekilde dinamiklerde gözlenir. Aşağıdaki video, farklı hesaplardaki EA işlemini göstermektedir:

 

Bir dosyayı okumanın ve yazmanın önemli avantajları bulunur ancak bazı dezavantajlar da vardır.

Başlıca avantajları şunlardır:

  1. Esneklik. Herhangi bir veriyi, hatta tüm sınıfları depolayabilir ve yükleyebilirsiniz;
  2. Nispeten yüksek hız. Tüm okuma ve yeniden yazma döngüsü neredeyse her seferinde 1 milisaniyeden fazla sürmez; bu, 80 - 150 milisaniye veya bazen daha da fazla süren görece yavaş alım satım işlemleriyle karşılaştırıldığında iyi bir süredir;
  3. DLL çağırmadan MQL5 dilinin standart araçlarına dayanmaktadır.

Böyle bir çözümün ana dezavantajı, depolama sistemi üzerindeki ciddi yüktür. Bir kotasyon ve iki komisyoncu olduğunda, yeniden yazma işlemlerinin sayısı nispeten küçüktür, ancak yoğun bir kotasyon akışı ve çok sayıda komisyoncu/sembol ile yeniden yazma işlemlerinin sayısı çok büyük olur. Demo EA, bir saatten kısa bir sürede 90.000'den fazla Quotes.xml dosya yeniden yazma işlemi üretti. Bu istatistikler, EA panelinin en üstünde gösterilir: "G/Ç Yeniden Yazma", toplam dosya yeniden yazma sayısını gösterir, "fps", son iki yeniden yazma işlemi arasındaki oranı belirtir ve "Ortalama", saniye başına ortalama yeniden yazma hızını gösterir.

Dosyaları SSD veya HDD'de saklarsanız bu işlemlerin disk ömrü üzerinde olumsuz bir etkisi olacaktır. Bu nedenle, böyle bir veri alışverişi için sanal bir RAM disk kullanmak daha iyidir.

Yukarıdaki örnekten farklı olarak, HedgeTerminal ActivePositions.xml öğresini tedbirli şekilde kullanır ve yalnızca global bağlamda erişilemeyen önemli pozisyon değişikliklerini yazar. Bu nedenle, yukarıdaki örneğe kıyasla çok daha az okuma/yazma işlemi üretir ve dolayısıyla RAM diskleri gibi herhangi bir özel koşul gerektirmez.


4.2. Expert Advisors Arasında Çok Yönlü Etkileşimin Kullanımı

Bağımsız MQL programları arasındaki gerçek zamanlı etkileşim, karmaşık ama ilgi çekici bir konudur. Makale bunun hakkında yalnızca çok kısa bir açıklama içeriyor, ancak yine de ayrı bir makaleye değer. Çoğu durumda, Expert Advisors arasında çok yönlü etkileşim gerekli değildir. Bununla birlikte, bu tür bir etkileşim organizasyonunun gerekli olduğu görevlerin ve çeşitli programların bir listesi:

  • Alım satım kopyalayıcı. Herhangi bir alım satım kopyalayıcı, biri alım satım işlemi sağlamak, diğeri de bunları kopyalamak üzere en az iki EA'nın aynı anda başlatma eylemini içerir. Bu durumda, ortak bir veri dosyasının alım satım işlemlerinin sağlanması ve kopyalanması için çok yönlü okuma/yazma eylemi düzenlenmesi gerekir;
  • EA'lar ve global değişkenler arasındaki global veri alışverişinin organizasyonu. MetaTrader 5'teki standart global değişkenler, Expert Advisors tarafından yalnızca bir terminal seviyesinde kullanılabilir. Bir terminalde bildirilen global değişken diğerinde mevcut değildir. Ancak farklı sürümleri olsa bile tüm terminaller için mevcut olabilecek karmaşık global değişkenleri ortak verileri kullanarak düzenleyebilirsiniz;
  • Arbitraj stratejileri. Farklı likidite sağlayıcılarından alınan kotasyonların analizcileri. Farklı brokerler tarafından sağlanan fiyatlar arasındaki fark önemliyse, yatırımcılar arbitraj stratejileri oluşturarak bundan faydalanabilirler. Ayrıca analizörler en iyi fiyat istatistiklerini toplamaya ve en iyi likidite sağlayıcısını objektif olarak belirlemeye izin verirler.


Eklerin Açıklaması

Burada makaleye ekli dosyaların kısa bir açıklaması ve veri derleme prosedürü yer almaktadır.

Prototypes.mqh HedgeTerminalAPI kitaplığı işlevlerinin açıklamasını içeren bir dosyadır. Bu dosya HedgeTerminalAPI kitaplığındaki işlevlerin açıklamasını ve prototiplerini içerir. EA'nıza kitaplıkta hangi işlevlerin ve değiştiricilerin bulunduğunu, işlevlerin nasıl çağrılacağını ve hangi değerleri verdiklerini bildirir.

Bu dosyayı, MetaTrader 5 terminalinizin kurulu olduğu dizin adının "C:\Program Files\MetaTrader 5\" olduğu C:\Program Files\MetaTrader 5\MQL5\Include konumuna kaydedin. Dosya doğruca dizine kopyalandığında, MQL programınızda ona başvurabilirsiniz. Bu HedgeTerminalAPI kitaplığını kullanmanız gerektiğinde yapılmalıdır. Prototypes.mqh dosyasına başvurmak için özel dosya içerme dizinini kodunuza ekleyin:

#include <Prototypes.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   //...
   // Here is the content of your program.
   //...
  }

Yukarıdaki örnekte, bu yönerge sarı ile işaretlenmiştir ve "#include <Ptototypes.mqh>" olarak adlandırılır. Artık yukarıdaki script kitaplık işlevlerine başvurabilir ve işlevlerini kullanabilir.

HedgeTerminalAPI kitaplığı geliştirme sürecinde prototiplerin dosyasının küçük değişiklikler geçirebileceğini lütfen unutmayın. Çoğu zaman kitaplık sürümünün güncellenmesi ile birlikte, değişiklikleri açıklayacak olan prototip dosyasını güncellemeniz gerekecektir. Lütfen bu rahatsız edici faktörü anlayışla karşılayın. Her durumda, prototip dosyasının en son sürümü her zaman kitaplıktan manuel olarak yüklenebilir (kurulum prosedürü bölüm 1.1'de açıklanmıştır) veya bu makalenin ekinden indirilebilir (ekler için düzenli güncellemeler beklenir).

Chaos2.mqh Chaos2 EA'nın kaynak kodudur. Çalışma şekli bölüm 1.12'de açıklanmıştır: "Chaos II EA örneği üzerinden SendTradeRequest işlevi ve HedgeTradeRequest işlevi örneği. Kodu başarılı bir şekilde derlemek için fonksiyon prototipleri dosyasını ilgili \Include dizinine kaydedin ve HedgeTerminalAPI kitaplığını da şuraya kaydedin: C:\Program Files\MetaTrader 5\MQL5\Market\hedgeterminalapi.ex5. MetaTrader 5 terminalinizin kurulu olduğu dizin (terminal veri klasörü) adının "C:\Program Files\MetaTrader 5\" olduğu yer.

UnitedExchangeQuotes kaynak kodu, 4. bölümde ayrıntılı olarak açıklanan projeyi içeren özel (unitedexchangequotes.zip) zip arşividir: "MetaTrader 5 IDE'de çok iş parçacıklı programlamanın temelleri". Bu zip aşağıdaki dosyaları içerir:

  • UnitedExchangeQuotes.mq5 - EA'nın merkezi dosyası. Uzmanlar klasörüne kaydedin: \MetaTrader 5\MQL5\Experts. Bu dosyayı MetaEditor'da derleyin.
  • MultiThreadXML.mqh, XML dosyasına çoklu iş parçacıklı erişim algoritmalarını içeren ana dosyadır. Bağımsız iş parçacıkları arasındaki bilgi alışverişini düzenler. \MetaTrader 5\MQL5\Include konumuna kaydedin. Bu dosyadaki algoritmalar, ya-sha tarafından geliştirilen ve CodeBase'de bulunan özel kitaplığa dayanmaktadır. Ancak, çok iş parçacıklı işlem için biraz değiştirilmiştir. Ek, bu değiştirilmiş sürümü içerir. Aşağıdaki dosyalardan oluşur:
    • XmlBase.mqh;
    • XmlDocument.mqh;
    • XmlAttribute.mqh;
    • XmlElement.mqh.
    Bu dosyaları \\Include klasörüne kaydedin.
  • Panel.mqh Örnekte açıklanan panel sınıfını içerir. Bu dosyayı, UnitedEchangesQuotes.mqh öğesini kaydettiğiniz dizine, yani \Experts klasörüne kaydedin.

Arşivdeki tüm dosyalar göreceli yollar içerir. Örneğin UnitedExchangeQuotes.mq5 dosyası \MQL5\Experts klasöründe bulunur. Bu, C:\Program Files\MetaTrader 5\MQL5\Experts\UnitedExchangeQuotes.mq5 gibi MetaTrader 5 terminal veri klasörünün aynı alt dizinine yerleştirilmesi gerektiği anlamına gelir.


Sonuç

HedgeTerminal program arayüzü ile çalışmanın detaylarını değerlendirdik.

Bu kitaplığın ilkelerinin MetaTrader 4 API'ye çok benzediği gösterilmiştir. MetaTrader 4 API'sinde olduğu gibi, bir işlemle (MetaTrader 4'teki "talimat" kavramının bir benzeri) çalışmaya başlamadan önce, onu TransactionSelect() kullanarak seçmelisiniz. Hedge Terminal'de bir işlem, kural olarak çift yönlü bir pozisyondur. Bir pozisyon seçildikten sonra, özelliklerini alabilir veya ona bir alım satım eylemi uygulayabilirsiniz, örneğin bir zararı durdurma seviyesi belirleyebilir veya kapatabilirsiniz. Bu eylem sıralaması, MetaTrader 4'teki talimatlarla çalışma algoritmasıyla neredeyse aynıdır.

HedgeTerminal, çift yönlü pozisyonların sayısı ve özellikleri hakkında temel bilgilere ek olarak, doğrudan ​​MetaTrader 5'te bulunmayan ve karmaşık analitik hesaplamalar gerektiren değerlere erişim sağlar. Örneğin özelliklerinden yalnızca birini isteyerek her iki yönlü pozisyonun da mali kayma miktarını görebilirsiniz. Seçili bir pozisyondaki yatırımların sayısını kontrol edebilirsiniz. Tüm bu hesaplamalar ve yatırımların gereken eşleştirmesi, HedgeTerminal'in başlatılması sırasında "perde arkasında" gerçekleştirilir. Alım satım Expert Advisor'ının herhangi bir şey hesaplamasını gerektirmemesi sebebiyle pratiktir. Gerekli tüm bilgiler önceden hesaplanmıştır ve basit ve sezgisel bir API aracılığıyla erişilebilir durumdadır.

HedgeTerminal API ve panel tarafından ortak algoritmaların kullanılması, birleşik veri sunumu sağlar. Dolayısıyla, EA'ları HedgeTerminal panelinden kontrol edebilirsiniz, EA tarafından yapılan değişiklikler de bu sırada doğrudan panelde görüntülenecektir.


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

Ekli dosyalar |
Prototypes.mqh (15.3 KB)
Chaos2.mq5 (23.56 KB)
MQL5 Cookbook: Hızlı Veri Erişimi için İlişkisel Dizi veya Sözlük Uygulama MQL5 Cookbook: Hızlı Veri Erişimi için İlişkisel Dizi veya Sözlük Uygulama
Bu makale, benzersiz anahtarlarıyla öğelere erişim elde etmeyi sağlayan özel bir algoritmayı açıklar. Herhangi bir temel veri türü anahtar olarak kullanılabilir. Örneğin bir dize veya bir tamsayı değişkeni olarak temsil edilebilir. Bu tür bir veri taşıyıcısına genellikle sözlük veya ilişkisel dizi denir. Problem çözme için daha kolay ve daha verimli bir yol sağlar.
MetaTrader 5'te HedgeTerminal Panelini Kullanarak İki Yönlü Alım Satım ve Pozisyonların Korunması, Bölüm 1 MetaTrader 5'te HedgeTerminal Panelini Kullanarak İki Yönlü Alım Satım ve Pozisyonların Korunması, Bölüm 1
Bu makale, pozisyonların korunmasına yönelik yeni bir yaklaşım açıklar ve MetaTrader 4 ile MetaTrader 5 kullanıcıları arasında gerçekleşen konu hakkındaki tartışmalarda çizgiyi çizer. Bu gibi korunmayı güvenilir kılan algoritmalar, herkesin anlayabileceği şekilde açıklanmış ve basit grafiklerle ve diyagramlarla gösterilmiştir. Bu makale esasen, MetaTrader 5 içinde tam özellikli yeni bir alım satım terminali olan panel HedgeTerminal'e ayrılmıştır. HedgeTerminal'in ve sunduğu alım satım işleminin sanallaştırılması kullanılarak, pozisyonlar MetaTrader 4'e benzer şekilde yönetilebilir.
CCanvas Sınıfını incelemek. Şeffaf Nesneler Nasıl Çizilir CCanvas Sınıfını incelemek. Şeffaf Nesneler Nasıl Çizilir
Hareketli ortalamaların garip grafiklerinden daha fazlasına mı ihtiyacınız var? Terminalinizde basit ve içi dolu bir dikdörtgenden daha güzel bir şey çizmek ister misiniz? Terminalde etkileyici grafikler çizilebilir. Bu, özel grafikler oluşturmak için kullanılan CСanvas sınıfı aracılığıyla uygulanabilir. Bu sınıfla, saydamlığı uygulayabilir, renkleri karıştırabilir ve üst üste binen ve karışan renkler aracılığıyla saydamlık yanılsaması oluşturabilirsiniz.
Moskova Borsası Vadeli İşlemler Piyasası Örneği ile Değişim Fiyatlandırma Esasları Moskova Borsası Vadeli İşlemler Piyasası Örneği ile Değişim Fiyatlandırma Esasları
Bu makale, Moskova Borsası Vadeli İşlemler Piyasasının değişim fiyatlandırması teorisini ve takas özelliklerini açıklamaktadır. Bu, türev alım satım işlemlerinde ilk takas deneyimini edinmek isteyen yeni başlayanlar ve merkezi bir takas platformunda alım satım yapmayı düşünen deneyimli forex yatırımcıları için kapsamlı bir makaledir.