English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Delphi'de MQL5 için DLL yazma kılavuzu

Delphi'de MQL5 için DLL yazma kılavuzu

MetaTrader 5Örnekler | 15 Aralık 2021, 09:59
99 0
Andriy Voitenko
Andriy Voitenko

Giriş

DLL yazma mekanizması, Delphi 2009 geliştirme ortamının bir örneği kullanılarak ele alınacaktır. Bu sürüm, MQL5'te tüm satırların Unicode biçiminde saklanması nedeniyle seçildi. Delphi'nin eski sürümlerinde, SysUtils modülünde Unicode biçimindeki satırlarla çalışma işlevi yoktur.

Herhangi bir nedenle daha önceki bir sürümü kullanıyorsanız (Delphi 2007 ve daha eski), o zaman ANSI biçiminde satırlarla çalışmanız ve MetaTrader 5 ile veri alışverişi yapmak için Unicode'a doğrudan ve ters dönüştürmeler üretmeniz gerekir. Bu tür zorlukları önlemek için MQL5 için DLL modülünü Delphi 2009'dan daha eski olmayan bir ortamda geliştirmenizi tavsiye ederim. Delphi'yi tanımak için 30 günlük deneme sürümü http://embarcadero.com resmi web sitesinden indirilebilir.

1. Proje Oluşturma

Projeyi oluşturmak için menü öğesini seçerek DLL Sihirbazını çalıştırmamız gerekir: 'Dosya -> Yeni -> Diğer ... -> DLL Sihirbazı' (Şekil 1'de gösterildiği gibi.)

Şekil 1. DLL Sihirbazını kullanarak proje oluşturma

Sonuç olarak, Şekil 2'de gösterildiği gibi boş bir DLL projesi oluşturacağız.


Şekil 2. Boş DLL projesi

Projenin başlığındaki uzun açıklamanın özünde, size dinamik olarak ayrılmış bellekle çalışırken doğru bir bağlantı ve bir bellek yöneticisinin kullanımı hatırlatılmıştır. Bu, dizelerle ilgili bölümde daha ayrıntılı olarak ele alınacaktır.

Yeni DLL'yi işlevlerle doldurmaya başlamadan önce projeyi yapılandırmak önemlidir.

Menüden proje özellikleri penceresini açın: 'Proje -> Seçenekler ...' veya klavye 'Shift + Ctrl + F11' aracılığıyla.

Hata ayıklama sürecini basitleştirmek için, DLL dosyasının doğrudan '.. \\MQL5\\Libraries' Alım Satım Terminali MetaTrtader5 klasöründe oluşturulması gerekir. Bunu yapmak için, DelphiCompiler sekmesinde, Şekil 3'te gösterildiği gibi ilgili özellik değeri Çıktı dizinini ayarlayın. Bu, DLL tarafından oluşturulan dosyayı proje klasöründen terminal klasörüne sürekli kopyalama ihtiyacını ortadan kaldıracaktır.

 Şekil 3. Ortaya çıkan DLL dosyasını depolamak için klasörü belirtin

Derleme sırasında BPL modüllerinin Windows sistem klasöründe bulunmadan bağlanmasını önlemek için, oluşturulan DLL gelecekte çalışmayacaktır, Paketler sekmede Şekil 4'te gösterildiği gibi Çalıştırma zamanı paketleri ile derle bayrağının işaretli olmadığını kontrol etmek önemlidir.

 Şekil 4. BPL modüllerini derlemeden hariç tutma

Proje yapılandırmasını tamamladıktan sonra, onu çalışma klasörünüze kaydedin, belirtilen proje adı, derlenen DLL dosyasının gelecekteki adıdır.

2. Yordamları ve işlevleri ekleme 

Parametresiz bir yordam örneğinde, DLL modülünde dışa aktarılan yordamları ve işlevleri yazarken genel durumu ele alalım. Parametrelerin bildirilmesi ve aktarılması bir sonraki bölümde tartışılacaktır.

Küçük bir arasöz. Programcı, yordamları ve işlevleri Object Pascal dilinde yazarken, bu ortam için geliştirilmiş sayısız bileşenden bahsetmek yerine, yerleşik Delphi işlevlerini kullanma fırsatına sahiptir. Örneğin, bir metin mesajı ile kalıcı bir pencerenin görüntüsünü getirmek gibi aynı eylemin performansı için, bir API işlevi - MessageBox ve VCL kitaplığından bir yordam - ShowMessage olarak kullanabilirsiniz.

İkinci seçenek, İletişim Kutuları modülünün dahil edilmesine yol açar ve standart Windows iletişim kutularıyla kolay çalışma avantajı sağlar. Ancak, ortaya çıkan DLL dosyasının boyutu yaklaşık olarak 500 KB artacaktır. Dolayısıyla, çok fazla disk alanı kaplamayan küçük DLL dosyaları oluşturmayı tercih ediyorsanız, VCL bileşenlerini kullanmanızı tavsiye etmem.

Örnek bir test projesi açıklamaları ile birlikte aşağıda verilmiştir:

library dll_mql5;

uses
  Windows, // necessary for the work of the MessageBox function
  Dialogs; // necessary for the work of the ShowMessage procedure from the Dialogs module

var   Buffer: PWideChar;
//------------------------------------------------------+
procedure MsgBox(); stdcall; // 
//to avoid errors, use the stdcall (or cdecl) for the exported functions
//------------------------------------------------------+
begin
    {1} MessageBox(0,'Hello World!','terminal', MB_OK);
    {2} ShowMessage('Hello World!');// alternative to the MessageBox function 
end;

//----------------------------------------------------------+
exports
//----------------------------------------------------------+
  {A} MsgBox,
  {B} MsgBox name 'MessageBox';// renaming of the exported function


//----------------------------------------------------------+
procedure DLLEntryPoint(dwReason: DWord); // event handler
//----------------------------------------------------------+
begin
    case dwReason of

      DLL_PROCESS_ATTACH: // DLL attached to the process;
          // allocate memory
          Buffer:=AllocMem(BUFFER_SIZE);

      DLL_PROCESS_DETACH: // DLL detached from the process;
          // release memory
          FreeMem(Buffer);

    end;
end;

//----------------------------------------------------------+
begin
    DllProc := @DLLEntryPoint; //Assign event handler
    DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
//----------------------------------------------------------+

Dışa aktarılan tüm işlevler, stdcall veya cdecl değiştiricisiyle bildirilmelidir. Bu değiştiricilerin hiçbiri belirtilmezse, Delphi varsayılan olarak fastcall sözleşmesini kullanır; bu, öncelikle parametreleri iletmek için yığın yerine CPU kayıtlarını kullanır. DLL. harici işlevlerin çağrılması aşamasında, iletilen parametrelerle çalışırken kesinlikle bir hataya yol açacaktır.

"Begin end" bölümü, bir DLL olay işleyicisinin standart başlatma kodunu içerir. DLLEntryPoint geri çağrı yordamı, kendisini çağıran sürece bağlanırken ve bağlantıyı keserken çağrılacaktır. Bu olaylar, örnekte gösterildiği gibi kendi ihtiyaçlarımız için ayrılmış doğru dinamik bellek yönetimi için kullanılabilir.

MQL5 için Çağrı:

#import "dll_mql5.dll"
    void MsgBox(void);
    void MessageBox(void);
#import

// Call of procedure
   MsgBox();
// If the names of the function coincide with the names of MQL5 standard library function
// use the DLL name when calling the function
   dll_mql5::MessageBox();

3. İşleve Parametre İletme ve Döndürülen Değerler

Parametrelerin iletilmesini düşünmeden önce MQL5 ve Object Pascal için veri uygunluk tablosunu analiz edelim.

MQL5 için veri türü
Object Pascal (Delphi) için veri türü
Not
karakter ShortInt
uchar
Byte
kısa
SmallInt
ushort
Word

int
Tamsayı
 
uint Kardinal
long Int64
ulong
UInt64

float Tek
çift Çift

ushort (символ) WideChar
dize PWideChar  
bool Boolean  
datetime TDateTime dönüştürme gereklidir (bu bölümde aşağıya bakınız)
renk TColor  

Tablo 1. MQL5 ve Object Pascal için veri uygunluk tablosu

Tablodan da görebileceğiniz gibi, datetime dışındaki tüm veri türleri için Delphi'nin tam bir analogu vardır.

Şimdi parametre iletiminin iki yolunu göz önünde bulundurun: Değere göre ve referansa göre. Her iki sürüm için parametre bildiriminin biçimi Tablo 2'de verilmiştir.

Parametreleri aktarma yöntemi
MQL5 için Bildirim
Delphi için Bildirim
Not 
değere göre
int func (int a); func (a:Integer): Integer;  correct

int func (int a);
func (var a: Integer): Integer;
 Hata: <Bellek adresine> erişim ihlali yazma
bağlantıya göre
int func (int &a);
func (var a: Integer): Integer;
 doğru, ancak satırlar bir değiştirici değişkeni olmadan iletilir!
  int func (int &a);  func (a: Integer): Integer;  hata: değişkenin değeri yerine bellek hücresinin adresini içeriyor

Tablo 2. Parametre iletme yöntemleri

Şimdi iletilen parametreler ve döndürülen değerlerle çalışma örneklerini ele alalım.

3.1 Tarih ve saati dönüştürme

İlk olarak, dönüştürmek istediğiniz tarih ve saat türüne değinelim; zira datetime türü yalnızca boyutunda TDateTime'a karşılık gelir, ancak biçim olarak karşılık gelmez. Dönüştürme kolaylığı için, alınan veri türü olarak TDateTime yerine Int64'ü kullanın. Aşağıda doğrudan ve ters dönüşüm için işlevler verilmiştir:

uses 
    SysUtils,  // used for the constant UnixDateDelta 
    DateUtils; // used for the function IncSecon, DateTimeToUnix

//----------------------------------------------------------+
Function MQL5_Time_To_TDateTime(dt: Int64): TDateTime;
//----------------------------------------------------------+
begin
      Result:= IncSecond(UnixDateDelta, dt);
end;

//----------------------------------------------------------+
Function TDateTime_To_MQL5_Time(dt: TDateTime):Int64;
//----------------------------------------------------------+
begin
      Result:= DateTimeToUnix(dt);
end;

3.2 Basit veri türleri ile çalışma

Örnekte verilmiş olan en sık kullanılan basit veri türlerinin (int, double, bool ve datetime) nasıl aktarılacağını inceleyelim.

Object Pascal için Çağrı:

//----------------------------------------------------------+
function SetParam(var i: Integer; d: Double; const b: Boolean; var dt: Int64): PWideChar; stdcall;
//----------------------------------------------------------+
begin
  if (b) then d:=0;                   // the value of the variable d is not changed in the calling program
  i:= 10;                             // assign a new value for i
  dt:= TDateTime_To_MQL5_Time(Now()); // assign the current time for dt
  Result:= 'value of variables i and dt are changed';
end;

MQL5 için Çağrı:

#import "dll_mql5.dll"
    string SetParam(int &i, double d, bool b, datetime &dt);
#import

// initialization of variables
   int i = 5;
   double d = 2.8;
   bool b = true;
   datetime dt= D'05.05.2010 08:31:27';
// calling the function
   s=SetParam(i,d,b,dt);
// output of results
   printf("%s i=%s d=%s b=%s dt=%s",s,IntegerToString(i),DoubleToString(d),b?"true":"false",TimeToString(dt));
Sonuç: 
The values of variables i and dt are changed i =  10  d =  2.80000000  b = true dt =  2009.05 .  05  08 :  42 

d'nin değeri, değere göre aktarıldığından beri değişmemiştir. Bir değişkenin değerinde değişiklikler meydana gelmesini önlemek için, bir DLL işlevi içinde b değişkeninde bir const. değiştiricisi kullanılmıştır.

3.3 Yapılar ve dizilerle çalışma

Birçok durumda, farklı türlerdeki parametreleri yapılarda ve bir türdeki parametreleri dizilerde gruplandırmak yararlıdır. SetParam işlevinin aktarılan tüm parametreleriyle, önceki örnekten bunları bir yapıya entegre ederek çalışmayı düşünün.

Object Pascal için Çağrı: 

type
StructData = packed record
    i: Integer;
    d: Double;
    b: Boolean;
    dt: Int64;
  end;

//----------------------------------------------------------+
function SetStruct(var data: StructData): PWideChar; stdcall;
//----------------------------------------------------------+
begin
  if (data.b) then data.d:=0;
  data.i:= 10;                                 // assign a new value for i
  data.dt:= TDateTime_To_MQL5_Time(Now()); // assign the current time for dt
  Result:= 'The values of variables i, d and dt are changed';
end

MQL5 için Çağrı:  

struct STRUCT_DATA
  {
   int i;
   double d;
   bool b;
   datetime dt;
  };

#import "dll_mql5.dll"
    string SetStruct(STRUCT_DATA &data);
#import

   STRUCT_DATA data;
   
   data.i = 5;
   data.d = 2.8;
   data.b = true;
   data.dt = D'05.05.2010 08:31:27';
   s = SetStruct(data);
   printf("%s i=%s d=%s b=%s dt=%s", s, IntegerToString(data.i),DoubleToString(data.d), 
             data.b?"true":"false",TimeToString(data.dt));
Sonuç:
The values of variables i,  d  and dt are changed i =  10  d =  0.00000000  b = true dt =  2009.05 .  05  12 :  19 

Önceki örneğin sonucundan önemli bir fark olduğunu belirtmek gerekir. Yapı bir referans üzerinden aktarıldığı için, seçilen alanları çağrılan işlevde düzenlemekten korumayı imkansız hale getirir. Bu durumda verilerin bütünlüğünü izleme görevi tamamen programcıya aittir.

Diziyi Fibonacci sayıları dizisiyle doldurma örneğinde, dizilerle çalışmayı düşünün:

Object Pascal için Çağrı:

//----------------------------------------------------------+
function SetArray(var arr: IntegerArray; const len: Cardinal): PWideChar; stdcall;
//----------------------------------------------------------+
var i:Integer;
begin
  Result:='Fibonacci numbers:';
  if (len < 3) then exit;
  arr[0]:= 0;
  arr[1]:= 1;
  for i := 2 to len-1 do
    arr[i]:= arr[i-1] + arr[i-2];
end;

MQL5 için Çağrı: 

#import "dll_mql5.dll"
    string SetArray(int &arr[],int len);
#import
   
   int arr[12];
   int len = ArraySize(arr);
// passing the array by reference to be filled by data in DLL
   s = SetArray(arr,len);
//output of result
   for(int i=0; i<len; i++) s = s + " " + IntegerToString(arr[i]);
   printf(s);
Sonuç:  
Fibonacci numbers 0 1 1 2 3 5 8 13 21 34 55 89

3.4 Dizelerle çalışma

Bellek yönetimine dönelim. DLL içinde kendi bellek yöneticinizi çalıştırmanız mümkündür. Ancak, DLL ve onu çağıran program genellikle farklı programlama dillerinde yazıldığı ve çalışmada genel sistem belleği yerine kendi bellek yöneticileri kullanıldığı için, DLL bağlantısında belleğin çalışma ve uygulama doğruluğunun tüm sorumluluğu programlayıcıya aittir.

Bellekle çalışmak için, kulağa şunun gibi gelen altın kurala uymak önemlidir: "Belleği tahsis edenler, onu serbest bırakanlar olmalıdır." Yani mql5- programındaki, DLL'de ayrılmış ve bunun tersi de geçerli olan belleği serbest bırakmaya çalışmamalısınız.

Windows API işlev çağrıları tarzında bir bellek yönetimi örneğini ele alalım. Bizim durumumuzda, mql5-programı, belleği arabellek için ayırır, DLL'ye PWideChar olarak iletilen arabelleğe bir işaretçi ve DLL, yalnızca bu arabellekte istenen değerlerle doldurulur; bu, aşağıdaki örnekte gösterilmiştir:

Object Pascal için Çağrı:

//----------------------------------------------------------+
procedure SetString(const str:PWideChar) stdcall;
//----------------------------------------------------------+
begin
  StrCat(str,'Current time:');
  strCat(str, PWideChar(TimeToStr(Now)));
end;

MQL5 için Çağrı: 

#import "dll_mql5.dll"
    void SetString(string &a);
#import

// the string must be initialized before the use
// the size of the buffer must be initially larger or equal to the string length
   StringInit(s,255,0); 
//passing the buffer reference to DLL 
   SetString(s);
// output of result 
   printf(s);

Sonuç:

Current Time: 11: 48:51 

Satır arabelleği için bellek, aşağıdaki örnekte görüldüğü gibi DLL'de çeşitli şekillerde seçilebilir:

Object Pascal için Çağrı: 

//----------------------------------------------------------+
function GetStringBuffer():PWideChar; stdcall;
//----------------------------------------------------------+
var StrLocal: WideString;
begin
     // working through the dynamically allocated memory buffer
     StrPCopy(Buffer, WideFormat('Current date and time: %s', [DateTimeToStr(Now)]));
     // working through the global varialble of WideString type
     StrGlobal:=WideFormat('Current time: %s', [TimeToStr(Time)]);
     // working through the local varialble of WideString type
     StrLocal:= WideFormat('Current data: %s', [DateToStr(Date)]);

{A}  Result := Buffer;

{B}  Result := PWideChar(StrGlobal);
     // it's equal to the following
     Result := @StrGlobal[1];

{С}  Result := 'Return of the line stored in the code section';

     // pointer to the memory, that can be released when exit from the function
{D}  Result := @StrLocal[1];
end;
MQL5 için Çağrı: 
#import "dll_mql5.dll"
    string GetStringBuffer(void);
#import

   printf(GetStringBuffer());

 Sonuç: 

Current Date: 19.05.2010

Önemli olan, dört seçeneğin de işe yaramasıdır. İlk iki seçenekte, satır ile çalışma, genel olarak tahsis edilmiş bir bellek üzerinden yapılır.

A seçeneğinde bellek bağımsız olarak ayrılır ve B seçeneğinde bellek yönetimi ile çalışma bellek yöneticisi tarafından üstlenir.

C seçeneğinde, satır sabiti bellekte değil, kod bölütünde saklanır; bu nedenle bellek yöneticisi, depolaması için dinamik bellek ayırmaz. D Seçeneği, programlamada çarpıcı bir hatadır; zira yerel değişken için ayrılan bellek, işlevden çıktıktan hemen sonra serbest bırakılabilir.

Ve bellek yöneticisi bu belleği anında serbest bırakmasa ve bunu çöple doldurması için zaman olmasa da, ikinci seçeneği kullanımdan çıkarmanızı öneririm.

3.5 Varsayılan parametreleri kullanma

İsteğe bağlı parametrelerin kullanımından söz edelim. Bunlar ilginçtir; zira yordamları ve işlevleri çağırırken değerlerinin belirtilmesine gerek yoktur. Aynı zamanda, aşağıdaki örnekte gösterildiği gibi, yordam ve işlev bildirimindeki tüm zorunlu parametrelerden sonra kesinlikle tanımlanmaları gerekir:

Object Pascal için Çağrı: 

//----------------------------------------------------------+
function SetOptional(var a:Integer; b:Integer=0):PWideChar; stdcall;
//----------------------------------------------------------+
begin
    if (b=0) then Result:='Call with default parameters'
    else          Result:='Call without default parameters';
end;
MQL5 için Çağrı:
#import "dll_mql5.dll"
    string SetOptional(int &a, int b=0);
#import

  i = 1;
  s = SetOptional(i); // second parameter is optional
  printf(s);

Sonuç: 

Call with default parameters

Hata ayıklamayı kolaylaştırmak için, yukarıdaki örneklerdeki kod, script dosyası olarak düzenlenmiştir; bu, Testing_DLL.mq5 dosyasında bulunur.

4. Tasarım aşamasında olası hatalar

Hata: DLL Yüklemesine izin verilmiyor.

Çözüm: ' Araçlar-Seçenekler' menüsünden MetaTrader 5 ayarlarına gidin ve Şekil 5'te gösterildiği gibi DLL işlevinin içe aktarılmasına izin verin.

  Şekil 5. DLL işlevlerini içe aktarma izni

Şekil 5. DLL işlevlerini içe aktarma izni

Hata: 'DLL adı' içinde 'işlev adı' bulunamıyor.
Çözüm: DLL projesinin Dışa Aktarmalar bölümünde callback işlevinin belirtilip belirtilmediğini kontrol edin. Öyleyse, karaktere duyarlı olduğunu göz önünde bulundurarak, DLL ve mql5 programında işlevin adının tam eşleşmesini kontrol etmeniz gerekir!

Hata: [Bellek adresine] erişim ihlali yazma
Çözüm: İletilen parametrelerin açıklamasının doğruluğunu kontrol etmeniz gerekir (bkz. tablo 2). Genellikle bu hata satırların işlenmesiyle ilişkili olduğu için, bu makalede paragraf 3.4'te belirtilen satırlarla çalışma önerilerini takip etmek önemlidir.

5. DLL kodu örneği

DLL kullanımının görsel bir örneği olarak, üç satırdan oluşan regresyon kanalı parametrelerinin hesaplamalarını göz önünde bulundurun. Kanalın yapısının doğruluğunu doğrulamak için yerleşik "Kanal regresyonu" nesnesini kullanacağız. LS için yaklaşık çizgi hesaplama (en küçük kareler yöntemi) veri işleme için bir algoritma koleksiyonunun bulunduğu http://alglib.sources.ru/ sitesinden alınmıştır. Algoritmaların kodu, Delphi dahil olmak üzere çeşitli programlama dillerinde sunulur.

a ve b'nin katsayılarını y = a + b * x yaklaşık çizgisiyle hesaplamak için, LRLine linreg.pas dosyasında açıklanan yordamı kullanın.

 procedure  LRLine (  const  XY: TReal2DArray;  / / Two-dimensional array of real numbers for X and Y coordinates 
                           N : AlglibInteger;  // number of points
                     var Info : AlglibInteger; // conversion status
                       var  A: Double;  / / Coefficients of the approximating line 
                        var  B: Double);
  

Kanalın parametrelerini hesaplamak için CalcLRChannel işlevini kullanın.

Object Pascal için Çağrı:  

//----------------------------------------------------------+
function CalcLRChannel(var rates: DoubleArray; const len: Integer;
                          var A, B, max: Double):Integer; stdcall;
//----------------------------------------------------------+
var arr: TReal2DArray;
    info: Integer;
    value: Double;
begin

    SetLength(arr,len,2);
    // copy the data to a two-dimensional array
    for info:= 0 to len - 1 do
    begin
      arr[info,0]:= rates[info,0];
      arr[info,1]:= rates[info,1];
    end;

    // calculation of linear regression coefficients
    LRLine(arr, len, info, A,  B);

    // find the maximal deviation from the approximation line found
    // and determine the width of the channel 
    max:= rates[0,1] - A;
    for info := 1 to len - 1 do
    begin
      value:= Abs(rates[info,1]- (A + B*info));
      if (value > max) then max := value;
    end;

    Result:=0;
end;

MQL5 için Çağrı:

#import "dll_mql5.dll"
    int CalcLRChannel(double &rates[][2],int len,double &A,double &B,double &max);
#import

   double arr[][2], //data array for processing in the ALGLIB format
              a, b,  // Coefficients of the approximating line  
              max; // maximum deviation from the approximating line is equal to half the width of the channel
   
   int len = period; //number of points for calculation
   ArrayResize(arr,len);

// copying the history to a two-dimensional array
   int j=0;
   for(int i=rates_total-1; i>=rates_total-len; i--)
     {
      arr[j][0] = j;
      arr[j][1] = close[i];
      j++;
     }

// calculation of channel parameters
   CalcLRChannel(arr,len,a,b,max);

Hesaplamalar için CalcLRChannel işlevini kullanan gösterge kodu, LR_Channel.mq5 dosyasında ve aşağıda yer alır: 

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

#include <Charts\Chart.mqh>
#include <ChartObjects\ChartObjectsChannels.mqh>

#import "dll_mql5.dll"
int CalcLRChannel(double &rates[][2],int len,double &A,double &B,double &max);
#import

input int period=75;

CChart               *chart;
CChartObjectChannel  *line_up,*line_dn,*line_md;
double                arr[][2];
//+------------------------------------------------------------------+
int OnInit()
//+------------------------------------------------------------------+
  {

   if((chart=new CChart)==NULL)
     {printf("Chart not created"); return(false);}

   chart.Attach();
   if(chart.ChartId()==0)
     {printf("Chart not opened");return(false);}

   if((line_up=new CChartObjectChannel)==NULL)
     {printf("Channel not created"); return(false);}

   if((line_dn=new CChartObjectChannel)==NULL)
     {printf("Channel not created"); return(false);}

   if((line_md=new CChartObjectChannel)==NULL)
     {printf("Channel not created"); return(false);}

   return(0);
  }
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
//+------------------------------------------------------------------+
  {

   double a,b,max;
   static double save_max;
   int len=period;

   ArrayResize(arr,len);

// copying of history to a two-dimensional array
   int j=0;
   for(int i=rates_total-1; i>=rates_total-len; i--)
     {
      arr[j][0] = j;
      arr[j][1] = close[i];
      j++;
     }

// procedure of calculating the channel parameters
   CalcLRChannel(arr,len,a,b,max);

// if the width of the channel has changed
   if(max!=save_max)
     {
      save_max=max;

      // Delete the channel
      line_md.Delete();
      line_up.Delete();
      line_dn.Delete();

      // Creating a channel with new coordinates
      line_md.Create(chart.ChartId(),"LR_Md_Line",0, time[rates_total-1],     a, time[rates_total-len], a+b*(len-1)    );
      line_up.Create(chart.ChartId(),"LR_Up_Line",0, time[rates_total-1], a+max, time[rates_total-len], a+b*(len-1)+max);
      line_dn.Create(chart.ChartId(),"LR_Dn_Line",0, time[rates_total-1], a-max, time[rates_total-len], a+b*(len-1)-max);

      // assigning the color of channel lines     
      line_up.Color(RoyalBlue);
      line_dn.Color(RoyalBlue);
      line_md.Color(RoyalBlue);

      // assigning the line width
      line_up.Width(2);
      line_dn.Width(2);
      line_md.Width(2);
     }

   return(len);
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
//+------------------------------------------------------------------+
  {
// Deleting the created objects
   chart.Detach();

   delete line_dn;
   delete line_up;
   delete line_md;
   delete chart;
  }

Göstergenin çalışmasının sonucu, Şekil 6'da gösterildiği gibi mavi bir regresyon kanalının oluşturulmasıdır. Kanalın yapısının doğruluğunu doğrulamak için grafik, MetaTrader 5 teknik analiz enstrümanlarının personel cephaneliğinden kırmızı ile işaretlenmiş bir "Regresyon Kanalı" göstermektedir.

Şekilde görüldüğü gibi, kanalın merkez çizgileri birleşmektedir. Bu arada, hesaplamasındaki farklı yaklaşımlardan dolayı kanalın genişliğinde (birkaç nokta) küçük bir fark vardır. 

 Şekil 6. Regresyon kanallarının karşılaştırması

Şekil 6. Regresyon kanallarının karşılaştırması

Sonuç

Bu makalede, Delphi uygulama geliştirme platformu kullanılarak bir DLL yazmanın özellikleri açıklanmıştır.

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

Ekli dosyalar |
mql5_sources.zip (276.43 KB)
dll_mql5_sources.zip (453.47 KB)
Mum Grafik Formasyonlarını Analiz Etme Mum Grafik Formasyonlarını Analiz Etme
Japon mum grafiğinin oluşturulması ve mum grafik formasyonlarının analizi, teknik analizin muhteşem bir alanını teşkil eder. Mum grafiklerin avantajı, verileri, verilerin içindeki dinamikleri takip edebileceğiniz şekilde temsil etmeleridir. Bu makalede mum grafik türlerini, mum grafik formasyonlarının sınıflandırılmasını analiz edecek ve mum grafik formasyonlarını belirleyebilecek bir gösterge sunacağız.
Heiken-Ashi Göstergesine Dayalı Bir Alım Satım Sistemi Örneği Heiken-Ashi Göstergesine Dayalı Bir Alım Satım Sistemi Örneği
Bu makalede, alım satım işleminde bir Heiken-Ashi göstergesi kullanma sorusunu inceleyeceğiz. Bu göstergeye dayalı olarak basit bir alım satım sistemi göz önünde bulundurulur ve bir MQL5 Expert Advisor yazılır. Alım satım işlemleri, Standart sınıf kitaplığının sınıfları temel alınarak gerçekleştirilir. Bu makalede sunulan incelenen alım satım stratejisinin test sonuçları, geçmişe dayanmaktadır ve yerleşik MetaTrader 5 strateji test cihazı kullanılarak elde edilmiştir.
Çok Sayıda Enstrüman Üzerinde Alım Satım Yapan bir Expert Advisor Oluşturma Çok Sayıda Enstrüman Üzerinde Alım Satım Yapan bir Expert Advisor Oluşturma
Finansal piyasalarda varlıkların çeşitlendirilmesi kavramı oldukça eskiye dayanır ve her zaman yeni başlayan yatırımcıları cezbetmiştir. Bu makalede, yazar, alım satım stratejilerinin bu yönüne bir başlangıç girişi yapmak için, çok para birimli bir Expert Advisor oluşturulmasına azami ölçüde basit bir yaklaşım önermektedir.
Pozisyon odaklı MetaTrader 5 ortamındaki talimatları takip etmek için Sanal Talimat Yöneticisi Pozisyon odaklı MetaTrader 5 ortamındaki talimatları takip etmek için Sanal Talimat Yöneticisi
Bu sınıf kitaplığı, MetaTrader 5'in pozisyon tabanlı yaklaşımına kıyasla, MetaTrader 4'e genel olarak benzer talimat odaklı bir yaklaşımla yazılmasını sağlamak için bir MetaTrader 5 Expert Advisor'ına eklenebilir. Bunu, MetaTrader 5 istemci terminalinde sanal talimatları takip ederken, olağanüstü durum koruması için her pozisyon için koruyucu bir aracı durdurması sağlayarak yapar.