
Delphi'de MQL5 için DLL yazma kılavuzu
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
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ı
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





- Ücretsiz alım-satım uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Gizlilik ve Veri Koruma Politikasını ve MQL5.com Kullanım Şartlarını kabul edersiniz