English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MetaTrader 5 ve MATLAB Etkileşimi

MetaTrader 5 ve MATLAB Etkileşimi

MetaTrader 5Örnekler | 10 Aralık 2021, 17:17
294 0
Andrey Emelyanov
Andrey Emelyanov

Giriş

MetaTrader 4 ve MATLAB Engine (Sanal MATLAB Makinesi) Arasındaki Etkileşim başlıklı ilk makalem MQL topluluğu tarafından fark edildi. Hatta bazı okuyucular (1Q2W3E4R5T) bu projeyi Borland'den VS2008'e taşıyabildi. Ancak zaman durmaksızın ilerliyor ve (acı ama gerçek) MetaTrader 4 yok oluyor; yerini, işaretçiler ve dinamik bellek sunan MQL5'i içeren mirasçıcı MetaTrader 5'e bırakıyor. 

Bu yenilikler sayesinde MATLAB Engine sanal makinesi ile evrensel bir etkileşim kitaplığı yazma ve MATLAB tarafından oluşturulan kitaplıkları doğrudan MetaTrader 5 ile bağlama imkanına sahibiz. Bu makale bu tip bir işlevselliği içermektedir. Bu makale mantıksal olarak öncekinin devamı niteliğinde olup MetaTrader 5 ile MATLAB arasındaki etkileşim sorununu daha kapsamlı bir şekilde ele almaktadır.

Bu makalenin kapsamını hazırlıksız okuyucular için daha anlaşılır hale getirmek için onu üç bölüme ayıracağız: Teori, referans ve uygulama. Teori bölümü, MQL5 ve MATLAB'da kullanılan veri türlerini ve bunların karşılıklı dönüşümlerini kapsayacaktır. Referans bölümünde, bir DLL oluşturmak için gerekli olan dil yapılarını ve işlevlerin sözdizimini öğreneceksiniz. Ve Uygulama bölümünde bu etkileşimin "tuzaklarını" analiz edeceğiz.

Deneyimli okuyucular Teori ve Referans'ı atlayarak Uygulama bölümünden başlayabilir. Diğer okuyucuların, Teori ve Referans bölümünü okumaları ve ancak ondan sonra Uygulama bölümüne geçmeleri tavsiye edilir. Ayrıca "Literatür" bölümünde adı geçen kitaplar okunmaya değerdir.

1. Teori

1.1 MATLAB ve MQL5'teki Veri Türleri

1.1.1 Basit Veri Türleri

Devam edelim.

İlk olarak, MQL5 ve MATLAB'ın iç dünyaları hakkında bilgi sahibi olmamız gerekiyor. Değişken türlerinin üstünkörü incelemesinden sonra, bunların hemen hemen aynı olduğu sonucuna varırız:

MQL5
Bayt cinsinden boyut
Minimum değer
Maksimum değer
 MATLAB
karakter
1
-128
127
Dizi int8/char
uchar
1
0
255
Dizi int8/char
bool
1
0(false)
1(true)
Dizi mantıksal
kısa
2
-32768
32767
Dizi int16
ushort
2
0
65535
Dizi int16
int
4
-2147483648
2147483647
Dizi int32
uint
4
0
4294967295
Dizi int32
long 8
-9223372036854775808
9223372036854775807 Dizi int64
ulong 8
0
18446744073709551615
Dizi int64
float 4
1.175494351e-38
3.402823466e+38
Dizi tek
çift
8
2.225073858507201e-308
1.7976931348623158e+308
Dizi çift

Tablo 1. MATLAB ve MQL5'teki Veri Türleri

Büyük bir fark vardır: MQL5'teki değişkenler basit veya bileşik (karmaşık) olabilir, MATLAB'da ise tüm değişkenler çok boyutludur (karmaşık); yani matris. Bu farkı her zaman göz önünde bulundurmalısınız!

1.1.2 Karmaşık Veri Türleri

MQL5'te 4 karmaşık veri türü vardır: Diziler, dizeler, yapılar ve sınıflar. Karmaşık veri türü, belirli bir uzunluktaki bellek bloğunda birleştirilen birkaç basit veri türü kümesidir. Bu tür verilerle ilgilenirken, her zaman bayt cinsinden bellek blok boyutunu veya öğe sayısını (sınıflar hariç) bilmeniz gerekir. Yalnızca diziler ve dizelerle ilgileniyoruz; zira sınıfları ve MQL5 yapılarını MATLAB'a göndermek herhangi bir anlam ifade etmiyor.

Herhangi bir türden dizileri iletirken bilmeniz gerekenler şu şekildedir: ArraySize() işlevini kullanan tür (boyut) ve öğe sayısı. MetaTrader 5'te indekslemeye özellikle dikkat edilmelidir; bu, genellikle geriye doğrudur (yani ilk öğe bir sonrakinden daha yeni veriler içerir). Bunu, ArrayIsSeries() işlevini kullanarak kontrol edin. Ve MATLAB aşağıdaki indekslemeye sahiptir: İlk öğe bir sonrakinden daha eski verileri içerir; bu nedenle, AS_SERIES = TRUE bayrağı varsa dizilerinizi MATLAB'a göndermeden önce "tersine çevirmeniz" gerekir. Yukarıdakilere dayanarak, aşağıdakilere riayet edelim:

  • char türü diziler ve 2 boyutlu diziler hariç, dizileri MQL5-programlarına "görünmez olarak" ters çevirin - bunları değiştirmeden bırakın.
  • char türündeki diziler ve 2 boyutlu diziler hariç MATLAB'daki tüm dizileri "görünmez olarak" ters çevirin ve AS_SERIES bayrağını TRUE ile atayın - bunları değiştirmeden bırakın.
  • MQL5 programında "geriye doğru" indekslemeye göre oluşturulan her dizide, AS_SERIES bayrağı, char türündeki diziler ve 2 boyutlu diziler hariç TRUE olmalıdır - bunları değiştirmeden bırakın.  

Ancak dizilerle çalışırken tek kısıtlama bu değildir. Çok boyutlu dizilerle veya daha doğru olması için matrislerle çalıştığınızda, özellikle MATLAB'dan, kısıtlamayı en fazla 2 boyutlu diziler için getiriyoruz. Burada AS_SERIES bayrağı TRUE olamaz ve bu nedenle bu tür diziler "ters çevrilmez".

MQL5'teki dizelerin char türü öğelerin dizileri olmadığını unutmayın. Bu nedenle, dizeler iletilirken küçük bir sorun ortaya çıkar: Unicode kullanılarak kodlanan MQL5 dizelerinde ve MATLAB ANSI kodlamasını kullanır. Dolayısıyla, bir dize iletilmeden önce, StringToCharArray() işlevi kullanılarak ANSI karakter dizisine dönüştürülmesi gerekir. Ve aksine, MATLAB'dan bir karakter dizisi aldığınızda, onu CharArrayToString() işlevini kullanarak dönüştürün (bkz. Tablo 2). Karışıklığı önlemek için, şu yolu takip edin: Tüm dizeleri char türünde diziler olmadan Unicode kullanarak MQL5 programlarında saklayın.

1.2 MQL5 ve MATLAB Veri Türlerinin Karşılaştırması

İşlevlerin miktarını azaltmak ve kitaplık algoritmasını basitleştirmek için, veri bütünlüğünü etkilememesi gereken otomatik dönüştürme yoluyla türlerin miktarını azaltacağız. Aşağıdaki tabloda, MQL5'ten MATLAB'a veri türü dönüştürme kuralı gösterilmektedir:

 MQL5 
MatLab eşdeğeri
karakter 
uchar
char dizisi
bool
Dizi mantıksal
kısa
ushort
int
uint
Dizi int32
long
ulong
Dizi int64*
float
çift
Dizi çift
dize
StringToCharArray() <=> CharArrayToString() işlevlerini kullanan char dizisi

* Bu dönüştürme türünde doğruluk kaybı olur. Biz bunu kullanmayacağız ama bu tür bir dönüştürmeyi programlarınızda kullanabilirsiniz.

Tablo 2. MQL5 ve MATLAB Veri Türlerini Karşılaştırma

Artık MQL5 ve MATLAB'da kullanılan veri türleri hakkında bilgi sahibisiniz. Veri iletiminde sizi hangi "tuzakların" beklediğini ve bunları yetkin bir şekilde nasıl atlatacağınızı biliyorsunuz. Yine de MATLAB Engine API'yi bilmeniz ve MATLAB Derleyici 4'e aşina olmanız gerekir.

2. MATLAB Engine API Referansı, MATLAB Derleyici 4 Referansı ve C++ Giriş/Çıkış Kitaplığı Referansı

Bu bölümde size MATLAB Engine API'ın en önemli işlevleri, MATLAB Derleyici 4'ün özellikleri ve C++ standart giriş/çıkış kitaplığının yararlı işlevlerinin sayısı tanıtılmaktadır. O halde başlayalım.

2.1 MATLAB Engine API ve MCR İşlevleri

MATLAB Engine - Diğer programların MATLAB masaüstünü kullanmasına olanak tanıyan harici arayüzdür. Tüm MATLAB paketlerinin herhangi bir kısıtlama olmaksızın tamamen işlevsel bir şekilde çalışmasını sağlar.

Her ne kadar belgelerde belirtilmemiş olsa da, sistem programcısı açısından MetaTrader 4/5 ve MATLAB arasında veri alışverişi için basit ve nispeten hızlı bir yolu destekleyen PHP, MySQL vb. gibi bir sanal makinedir.  

Bu harici programları MATLAB paketi ile bağlama yöntemi, geliştiriciler tarafından tavsiye edilir. Arayüz altı işlevden meydana gelir:

Engine *pEng = engOpen(NULL) — Bu işlev MATLAB masaüstünü çağırır, parametre her zaman NULL'dur, masaüstü tanımlayıcısına bir işaretçi döndürür.

int exitCode = engClose(Engine *pEng) — Bu işlev masaüstünü kapatır, MATLAB masaüstünün kalan kullanıcı sayısını döndürür; burada:

  • Engine *pEng — Masaüstü tanımlayıcısına işaretçi.  

mxArray *mxVector = mxCreateDoubleMatrix(int m, int n, int ComplexFlag) — Bu işlev MATLAB masaüstünde bir değişken (matris) oluşturur, değişkene (matris) bir işaretçi döndürür; burada:

  • mxArray *mxVector — Matris değişkenine işaretçi.  
  • int m — Satırların sayısı.  
  • int n — Sütunların sayısı  
  • ComplexFlag — MetaTrader 4/5 mxREAL için karmaşık sayı türü.
void = mxDestroyArray(mxArray *mxVector) — Bu işlev MATLAB matrisini yok eder, belleği temizlemek için gereklidir; burada:
  • mxArray *mxVector — Matris değişkenine işaretçi.  
int = engPutVariable(Engine *pEng, char *Name, mxArray *mxVector) — Bu işlev masaüstüne değişken gönderir. Yalnızca mxArray türünde değişkenler oluşturmanız değil, aynı zamanda bunları MATLAB'a göndermeniz gerekir; burada:
  • Engine *pEng — Masaüstü tanımlayıcısına işaretçi.  
  • char *Name — MATLAB masaüstündeki char türünün değişken adı.  
  • mxArray *mxVector — Matris değişkenine işaretçi.  
mxArray *mxVector = engGetVariable(Engine *pEng, char *Name) — Bu işlev masaüstünden değişken alır - önceki işlevin tersi. Yalnızca mxArray türündeki değişkenler alınır; burada:
  • mxArray *mxVector — Matris değişkenine işaretçi.  
  • Engine *pEng — Masaüstü tanımlayıcısına işaretçi.  
  • char *Name — MATLAB masaüstündeki char türünün değişken adı.  
double *p = mxGetPr(mxArray *mxVector) — Bu işlev, değerler dizisine işaretçi alır, memcpy() ile birlikte verileri kopyalamak için kullanılır (bkz. 2.3 C++ Standart Giriş/Çıkış Kitaplığı); burada:
  • double *p — double türündeki diziye işaretçi.  
  • mxArray *mxVector — Matris değişkenine işaretçi.  
int = engEvalString(Engine *pEng, char *Command) — Bu işlev MATLAB masaüstüne komutlar gönderir; burada:
  • Engine *pEng — Masaüstü tanımlayıcısına işaretçi.  
  • char *Command — MATLAB için komut, char türünün dizesi.  

MATLAB Engine API'ının yalnızca double türü için mxArray yapısı oluşturmanıza izin verdiğini muhtemelen fark etmişsinizdir. Ancak bu kısıtlama, olasılıklarınızı etkilemez fakat kitaplığınızın algoritmasını etkiler.

MCR (MCR örneği) — MATLAB ortamı tarafından oluşturulan bağımsız uygulamaların/genel kitaplıkların herhangi bir bilgisayarda çalıştırılmasına olanak tanıyan MATLAB paketinin özel kitaplığıdır. Eksiksiz bir MATLAB paketine sahip olsanız dahi, yine de MCR kitaplığını, içinde bulunan <MATLAB>\Toolbox\compiler\deploy\win32 klasöründe bulunan MCRInstaller.exe dosyasını çalıştırarak yüklemeniz gerektiğine dikkat edin. Bu nedenle, MATLAB ortamı tarafından oluşturulan herhangi bir genel kitaplık işlevini çağırmadan önce, MCR başlatma işlevini çağırmanız gerekir:
 
bool = mclInitializeApplication(const char **option, int count) – MCR başarıyla başlatılırsa TRUE değerini, aksi taktirde FALSE değerini döndürür; burada:

  • const char **option — mcc - R gibi seçenekler dizesi; genellikle NULL'dur  
  • int count — boyut seçenekleri dizesi, genellikle 0.

Genel kitaplığın çalışmasını sonlandırırken şunu çağırmanız gerekir:
bool = mclTerminateApplication(void) — MCR başarıyla kapatılırsa TRUE değerini döndürür.

2.2 MATLAB Derleyici 4

MATLAB Derleyici, M-işlevlerinden aşağıdakileri oluşturmanıza olanak tanır:  

  • MATLAB yüklü olmasa dahi çalışan bağımsız uygulamalar.
  • Son kullanıcı sistemlerinde MATLAB olmadan kullanılabilen C/C++ paylaşım kitaplıkları.

Derleyici, MATLAB'ın komutlarının ve paketlerinin çoğunu destekler, ancak tamamını desteklemez. Kısıtlamaların tam listesi MATLAB web sitesinde bulunabilir. Bu yöntem, MetaTrader 5 ve MATLAB'ın "yazılımdan bağımsız paketini" oluşturmanıza olanak tanır, ancak MATLAB Engine'in aksine, iyi eğitimli bir programcı ve derin bir derleme bilgisi birikimi gerektirir.

MATLAB Derleyici, aşağıdaki C/C++ derleyicilerinden en az birini gerektirir:

  • Lcc C (genellikle MATLAB ile birlikte gelir). Yalnızca C derleyicisidir.  
  • Borland C++ sürüm 5.3, 5.4, 5.5, 5.6.
  • Microsoft Visual C/C++ sürüm 6.0, 7.0, 7.1.

MATLAB Derleyici 4, öncekilerin aksine, yalnızca arayüz kodunu (sarmalayıcı) üretir; yani m-işlevlerini ikili veya C/C++ koduna dönüştürmez, ancak m-işlevlerini desteklemek için gerekli olan çeşitli paketlerin entegrasyonlarını içeren Bileşen Teknoloji Dosyası (CTF) teknolojisine dayalı özel bir dosya oluşturur. MATLAB Derleyici ayrıca bu dosyayı benzersiz (tekrarlanmayan) 1024-bit anahtarla şifreler.

Şimdi MATLAB Derleyici 4'ün çalışma algoritmasını ele alalım; zira bu konu hakkında bilgi eksikliği derleme zamanında birçok saçma hataya yol açacaktır:

  1. Bağımlılık analizi — Bu aşamada, derlenmiş m-işlevlerinin bağlı olduğu tüm işlevleri, MEX-dosyalarını ve P-dosyalarını belirleyin.  
  2. Arşiv oluşturma - CTF-dosyası oluşturulur, şifrelenir ve sıkıştırılır.  
  3. Sarmalayıcının nesne kodunu oluşturma – Bu aşamada bileşen için gerekli olan tüm kaynak kodları oluşturulur:
    • Komut satırında belirtilen m-işlevleri için C/C++ arayüz kodu (NameFile_main.c).
    • m-kodunun yürütülmesi için gereken tüm bilgileri içeren bileşen dosyası (NameFile_component.dat) (CTF dosyasında saklanan şifreleme anahtarları ve yolları dahil).  
  4. C/C++ dönüştürme. Bu aşamada C/C++ kaynak kod dosyaları nesne dosyalarına derlenir.
  5. Bağlama. Proje oluşturmanın son aşaması.

MATLAB Derleyici algoritmasının davranışına aşina olduğunuzda, derleyici (mcc) kullanırken ayrıntılı bir eylem planına sahip olmak için anahtarlar hakkında daha fazla bilgi edinmelisiniz:   

Anahtar
Amaç
    filename
 Arşivlenecek <filename> dosyasını ekleyin, CTF arşivine hangi dosyaların ekleneceğini belirleyin
     l
 Bir işlev kitaplığı oluşturan makro
    N
 Gerekli minimum dizin kümesi dışındaki tüm yolları temizleyin
    p <dizin>
 Prosedüre göre dönüştürme yolunu ekleyin. -N anahtarını gerektirir.
    R -nojvm
 MCR seçeneğini iptal edin (MATLAB Bileşen Çalışma Zamanı, MATLAB Yardımı bölümüne bakınız)
    W
 İşlev sarmalayıcılarını oluşturma işlemini yönetin
    lib
 Başlatma ve tamamlama işlevleri oluşturun
    ana
 main() işlevinin POSIX kabuğunu oluşturun
    T
 Çıkış aşamasını belirtin
    codegen
 Bağımsız uygulama için sarmalayıcı kodu oluşturun
    compile:exe
 Codegen ile aynı
    compile:lib
 Genel DLL için sarmalayıcı kodu oluşturun
    link:exe
 compile:exe ile aynı; ayrıca bağlama
    link:lib
 compile:exe ile aynı; ayrıca bağlama

Tablo 3. Matlab mcc Derleyicinin Anahtarları (sürüm 4)

Tablo 3, tipik sorunların çözümünde yararlı olabilecek temel anahtarları içerir. Daha fazla yardım için help mcc veya doc mcc MATLAB komutlarını kullanın.

MATLAB bağlayıcıyı bilmemiz gerekiyor, aşağıda ana anahtarlar (mbuild) verilmiştir:

 Anahtar
Amaç
 -setup
 Etkileşimli modda, gelecekteki mbuild çağrılarında varsayılan olarak kullanılacak derleyici seçenekleri dosyasının tanımı
 -g
 Hata ayıklama bilgileriyle program oluşturun. DEBUGFLAGS'ı dosyanın sonuna ekleyin.
 -O
 Nesne kodunun optimizasyonu

Tablo 4. Matlab mbuild Bağlayıcı (sürüm 4) anahtarları

Tablo 4'te ana tuşlar listelenmiştir. Daha fazla bilgi için help mbuild veya doc mbuild komutlarını kullanın.

2.3 C++ Standart Giriş/Çıkış Kitaplığı

Standart Giriş/Çıkış Kitaplığının kullanılması doğru veri kopyalama sağlar. Kullanımı sizi program tasarımı aşamasında ortaya çıkan "saçma" hatalardan kurtaracaktır (örneğin: birçok acemi programcı tüm bellek bloğunu kopyalamak yerine yalnızca işaretçiyi bellek bloğuna kopyalar). Giriş/Çıkış Kitaplığının tamamından yalnızca bir işlevle ilgileniyoruz:

void *pIn = memcpy(void *pIn, void *pOut, int nSizeByte) – Bu işlev, değişkeni/diziyi pOut'tan pIn'ye nSizeByte bayt boyutuyla kopyalar (klonlar); burada:

  • void *pIn — Diziye işaretçi, kopyalanacak yer.  
  • void *pOut — Kopyalamanın yapıldığı diziye işaretçi.  
  • int nSizeByte — Kopyalanan verinin boyutu, pIn dizisinin boyutunu aşmamalıdır; aksi takdirde bellek erişim hatası oluşur.  

3. Uygulama

Artık teori ile işimiz bitti; MetaTrader 5 ve MATLAB etkileşiminin gerçekleştirilmesine geçebiliriz.

Muhtemelen tahmin ettiğiniz gibi, bu iki şekilde yapılacaktır: MATLAB Engine sanal makinesi kullanılarak ve MATLAB Derleyici tarafından oluşturulan kitaplıklar kullanılarak. İlk olarak, MATLAB Engine aracılığıyla basit, hızlı ve çok yönlü bir etkileşim yolu düşünün.

Etkileşim yöntemleri arasındaki görünen farklılığa rağmen, tek bir felsefeleri ve dil yapılarına ilişkin bilinen sözdizimi olduğu ve basit örneklerle yeni bir şey öğrenmek daha kolay olduğu için makalenin bu kısmı baştan sona okunmalıdır.

3.1 MetaTrader 5 ve MATLAB Engine Etkileşiminin Evrensel Kitaplığını Geliştirme

Bu etkileşim yöntemi mükemmel ve hızlı olarak adlandırılamaz, ancak en güvenilir olanıdır ve tüm MATLAB paketini kapsar. Tabii ki, nihai model geliştirme hızından da söz etmeliyiz. Geliştirmenin özü, MetaTrader 4/5 ve MATLAB Engine etkileşimi için evrensel bir kitaplık sarmalayıcı yazmaktır. Bundan sonra MetaTrader 4/5 script dosyası/göstergesi/expert'i MATLAB sanal masaüstünü yönetebilir. Ve tüm matematiksel algoritma, MQL-programında dizeler olarak saklanabilir; böylece fikri mülkiyetinizi korumak için kullanabilirsiniz (daha fazla ayrıntı için "Geliştiriciler, Kendinizi Koruyun!" makalesine bakınız). Ayrıca, <MetaTrader 5>\MQL5\Libraries klasöründe ayrı m-işlevleri veya P-işlevleri dosyalarında saklanabilir.  

Bu tür etkileşimin olası uygulama alanları şu şekildedir:

  • Karmaşık programlar yazmak zorunda kalmadan "matematiksel modelleri/fikirleri" test etmek veya göstermek (fikri mülkiyetin korunması, MQL-programında olduğu gibi ve MATLAB paketi aracılığıyla P-işlevleri kullanılarak düzenlenebilir).  
  • MATLAB'ın tüm özelliklerini kullanarak karmaşık matematiksel modeller yazmak.
  • Script dosyalarını/göstergelerini/expert'lerini dağıtmayacak herkese.

Devam edelim. Umarım 1.1 MATLAB ve MQL5'teki Veri Türleri, 1.2 MQL5 ve MATLAB Veri Türlerini Karşılaştırma, 2.1 MATLAB Engine API ve MCR İşlevleri ve 2.3 C++ Standart Giriş/Çıkış Kitaplığı bölümlerini okumuşsunuzdur; zira artık onların üzerinde durmayacak ve analiz etmeyeceğiz. Gelecekteki kitaplık algoritmasını gösteren aşağıdaki blok şemasını dikkatli bir şekilde okuyun:  

Şekil 1. Kitaplık Algoritmasının Blok Şeması

Şekil 1. Kitaplık Algoritmasının Blok Şeması

Şekil 1'de görüldüğü gibi kitaplık üç ana bloktan oluşur. Gördükleri işlevleri göz önünde bulundurun:

  • MQL5 bloğu, gönderilen/alınan verilerin ön hazırlığı:  
    • Ters diziler.
    • Tür dönüştürme.
    • Dizeler kodlama dönüştürme.
  • C/C++ bloğu:
    • Diziyi mxArray yapısına dönüştürür.
    • MATLAB Engine komutlarını iletir.
  • MATLAB Engine bloğu — Hesaplama sistemi.  

Şimdi algoritmaları ele alalım. MQL5 bloğu ile başlayacağız. Dikkatli okuyucular, MATLAB ve MQL5'teki Veri Türleri bölümünde yazılanların uygulanmasına odaklanacağını zaten fark etmiştir. Bunu kaçırdıysanız, tüm bunların neden gerekli olduğunu anlamanız zor olacaktır.

mlInput <variable_type> işlevlerinin algoritması hemen hemen aynıdır. MATLAB sanal makinesine double türündeki değişkenlerin girişini sağlayan mlInputDouble() işlevini kullanarak çalışmasını ele alalım.

Prototip şu şekildedir:

bool mlInputDouble(double &array[],int sizeArray, NameArray dizesi); burada:

  • arraydouble türündeki değişkene veya diziye başvuru
  • sizeArray — Dizi boyutu (bayt değil, öğe sayısı!). 
  • NameArray — MATLAB sanal makinesi için benzersiz değişken adını içeren dize (ad, MATLAB gerekliliklerine karşılık gelmelidir).

Algoritma:

  1. StringToCharArray() işlevini kullanarak NameArray dizesini char dizisine dönüştürün.
  2. ArrayIsSeries() işlevini kullanarak indeksleme türünü kontrol edin. İndeksleme türü normalse — değeri mlxInputDouble() işlevine iletin.
    Zaman serisi dizisinin ELSE indekslemesi:
    Diziyi "ters çevirin" ve değeri mlxInputDouble() işlevine iletin.
  3. Son işlevi, döndürülen değeri mlxInputDouble() işlevine iletin.

mlGet <variable_type> işlevlerinin algoritması da hemen hemen aynıdır. MATLAB sanal makinesinden double türündeki değişkeni döndüren mlGetDouble() işlevini kullanarak çalışmasını ele alalım.

Prototip şu şekildedir:

int mlGetDouble(double &array[],int sizeArray, NameArray dizesi); burada:

  • arraydouble türündeki değişkene veya diziye başvuru.
  • sizeArray — Dizi boyutu (bayt değil, öğe sayısı!). 
  • NameArray — MATLAB sanal makinesi için benzersiz değişken adını içeren dize.

Algoritma:

  1. StringToCharArray() işlevini kullanarak NameArray dizesini char dizisine dönüştürün.   
  2. mlxGetSizeOfName() işlevini kullanarak dizinin boyutunu bulun.
    • Boyutu SIFIRDAN FAZLAİSE, ArrayResize() işlevini kullanarak gerekli boyutta alıcı dizisini ayırın, mlxGetDouble()) verilerini alın, dizi boyutunu döndürün.
    • EĞERboyut SIFIRise hata yani boş değer döndür.  

Hepsi bu kadar! mlGetInt() ve mlGetLogical() işlevleri, double ->; int/bool türlerinin "shadow" dönüşümünü üretir. Bu amaçla bu işlevler, gövdelerinde geçici bir bellek arabelleği oluşturur. Bu zorunlu bir önlemdir; zira ne yazık ki MATLAB API, double dışındaki veri türleri için mxArray yapılarının oluşturulmasına izin vermez. Ancak bu, MATLAB'ın yalnızca double türlerini çalıştırdığı anlamına gelmez.

C/C++ bloğu çok daha kolaydır - double türünden mxArray yapısına veri dönüştürme sağlamalıdır. Bu, mxCreateDoubleMatrix(), mxGetPr() ve memcpy() işlevleri kullanılarak yapılır. Ardından, engPutVariable() işlevini kullanarak verileri MATLAB sanal makinesine iletir ve verileri çıkarmak için engGetVariable() işlevini kullanır. Yine, Int ve Logical öneklerine sahip işlevlere dikkat edin — Blok şemasında görüldüğü gibi, MATLAB ile doğrudan etkileşime girmezler, ancak mlxInputDouble/mlxGetDouble ve mlxInputChar() işlevlerini kullanırlar. Davranışlarının algoritması basittir: mlxInputDouble/mlxGetDouble işlevinin çağrılması — double(!) olarak giriş/çıkış değerleri ve mlxInputChar() işlevi aracılığıyla veri türünü dönüştürmek için "shadow" MATLAB komutunu gönderin.

MATLAB Engine bloğu daha da kolaydır. Yalnızca matematiksel işlevler sağlar. Davranışı, komutlarınıza ve m/p-işlevlerinize bağlıdır.  

Projenin tüm "ayrıntıları" netleştiğine göre, proje oluşturmayı ele alma zamanı.

Bu tür herhangi bir yapı, ana kitaplığın oluşturulmasıyla başlar; bizim durumumuzda bu, C/C++ bloğudur. Bu amaçla, herhangi bir ANSI-metin düzenleyicisinde (Notepad, Bred vb.) DEF uzantılı bir dosya oluşturun. Bu dosyanın adının boşluk ve noktalama işaretleri içermeyen Latin alfabesi karakterlerinden oluşması arzu edilir; aksi takdirde derleyicinizden birçok gurur verici "sözcük" duyarsınız... Bu dosya, işlevlerinizin kalıcılığını sağlar. Bu dosya yoksa, C/C++ derleyicisi, işlevleri dışa aktarmak için kendi "tuhaf adlarını" icat edecektir.

Bu dosya şunları içerir: KİTAPLIK — kontrol sözcüğü, LibMlEngine — kitaplığın adı ve DIŞA AKTARMALAR — ikinci kontrol sözcüğü, ardından işlevlerin adları gelir. Muhtemelen bildiğiniz gibi, dışa aktarma işlevlerinin adlarında boşluk ve noktalama işareti olamaz. MATLABEngine.zip arşivindeki DllUnit.def dosyasının metni şu şekildedir:  

KİTAPLIK LibMlEngine
DIŞA AKTARMALAR
mlxClose
mlxInputChar
mlxInputDouble
mlxInputInt
mlxInputLogical
mlxGetDouble
mlxGetInt
mlxGetLogical
mlxGetSizeOfName
mlxOpen

Böylece, projenin ilk dosyasına sahibiz. Şimdi Windows Gezgini'ni açın ve '<MATLAB>\Extern\include' klasörüne gidin. engine.h dosyasını (MATLAB sanal makinesinin üst bilgi dosyası) projenizin oluşturulduğu klasöre kopyalayın (bunu yapmayacaksanız, dosyanın yolunu derleme aşamasında manuel olarak belirtmeniz gerekecektir).

Şimdi C/C++ bloğu oluşturma zamanı. Bu dosya MATLABEngine.zip dosyasında DllUnit.cpp olarak bulunabileceği için ve tam olarak açıklanmış olduğu için, programın tüm kaynak kodunu makaleye dahil etmeyeceğiz. __stdcall kuralını kullanarak işlevler oluşturmanın daha iyi olduğunu unutmayın — yani parametreler yığından iletilir ve işlev yığını temizler. Bu standart, Win32/64 API için "yereldir".

Bir işlevi nasıl bildireceğinizi düşünün:

extern "C" __declspec(dllexport) <variable_type> __stdcall Function(<type> <name>)

  1. extern "C" __declspec(dllexport) — C++ derleyicisine işlevin harici olduğunu bildirir.  
  2. <variable_type> — Döndürülen değişken türü, şunlar olabilir: void, bool, int, double, bileşik türler (yalnızca Dll tarafından değil, aynı zamanda çağıran program tarafından da bilinir) ve işaretçiler.
  3.  __stdcall — Parametreleri işleve iletme ve geri alma hakkında bildirim; bu, Win32/64 API için bir standarttır.  
  4. İşlev — İşlev adınız.  
  5. <tür> <adı> — Giriş değişkeninin türü ve adı; maksimum değişken sayısı 64'tür.

Bu konu, Veri Değişimi Nasıl Yapılır: 10 Dakikada MQL5 için bir DLL makalesinde ayrıntılı olarak ele alınmıştır.

C/C++ blok oluşturma: Bunun için standart giriş/çıkış kitaplığı eklemeniz ve aşağıdaki dosyaları projeye eklemeniz gerekir (derleyicinizde: Proje->Proje Ekle):

  1. DllUnit.def
  2. <MATLAB>\Extern\lib\<win32/64>\<compiler>\ klasöründe:
    <MATLAB> — MATLAB ana klasörü.
    <win32/64> — 32-bit işletim sistemi için win32 klasörü veya 64-bit işletim sistemi için win64 klasörü.
    <compiler>— Borland C/C++ ver için "borland" klasörü. 5-6, Microsoft Visual C++ için "microsoft" klasörü:  
    • libeng.lib
    • libmx.lib

Bunun gibi yaygın bir soru ortaya çıkabilir: "Derleyicinin farklı sürümleri var veya listede böyle bir derleyici yok! (Bu tip dosyalar çok nadiren yoktur)". Şimdi bir genel kitaplığı manuel olarak nasıl oluşturacağımızı görelim. Visual C++ ve Borland C++'da nasıl yapıldığını ele alacağız:

  1. FAR'de, açık <MATLAB>\Bin\<win32/64> klasöründe; burada:
    <MATLAB> — MATLAB ana klasörü.
    <win32/64> — 32-bit işletim sistemi için win32 klasörü veya 64-bit işletim sistemi için win64 klasörü.  
  2. Borland C++ içinşunu girin: implib libeng.lib libeng.dll. Aynısı libmx.dll için de geçerlidir.
  3. Visual C++için şunu girin: lib libeng.dll. Aynısı libmx.dll için de geçerlidir.
  4. Diğer derleyici ise: Herhangi bir programlama dilinin herhangi bir derleyicisinde bu yardımcı program bulunmalıdır - Kitaplık Yöneticisi, genellikle bu bir konsol programıdır <compiler _folder>\bin\*lib*.exe.

Bu arada, sizi uyarmayı unuttum - 32-bit derleyici için 64-bit LIB oluşturmaya çalışmayın. İlk olarak, derleyici yardımında 64-bitlik adresleme desteği olup olmadığını öğrenin. Yoksa, ya 32-bit MATLAB DLL'sini arayın ya da başka bir C/C++ derleyicisi seçin. Derleme işlemine başlıyoruz, ardından terminal_folder\MQL5\Libraries klasörüne yerleştirilmesi gereken bir kitaplık alıyoruz.

Şimdi MQL bloğu ile başlayalım. MetaEditor'u çalıştırın, "Yeni"ye tıklayın ve işlemleri aşağıdaki şekillerde gösterildiği gibi gerçekleştirin:  

Şekil 2. MQL5 Sihirbazı: Kitaplık Oluşturma

Şekil 2. MQL5 Sihirbazı: Kitaplık Oluşturma

Şekil 3. MQL5 Sihirbazı: Kitaplığın Genel Özellikleri

Şekil 3. MQL5 Sihirbazı: Kitaplığın Genel Özellikleri

MQL5 Sihirbazı bir şablon oluşturduğunda, onu düzenlemeye devam edin:

1. İşlevlerin içe aktarılmasını açıklayın:

//+------------------------------------------------------------------+
//| DECLARATION OF IMPORTED FUNCTIONS                                |
//+------------------------------------------------------------------+
#import "LibMlEngine.dll"
void   mlxClose(void);                        //void – means: don't pass any parameters!
bool   mlxOpen(void);                         //void – means: don't pass and don't receive any parameters!
bool   mlxInputChar(char &CharArray[]);       //char& CharArray[] – means: pass a reference!
bool   mlxInputDouble(double &dArray[],
                      int sizeArray,
                      char &CharNameArray[]);
bool   mlxInputInt(double &dArray[],
                   int sizeArray,
                   char &CharNameArray[]);
bool   mlxInputLogical(double &dArray[],
                       int sizeArray,
                       char &CharNameArray[]);
int    mlxGetDouble(double &dArray[],
                    int sizeArray,
                    char &CharNameArray[]);
int    mlxGetInt(double &dArray[],
                 int sizeArray,
                 char &CharNameArray[]);
int    mlxGetLogical(double &dArray[],
                     int sizeArray,
                     char &CharNameArray[]);
int    mlxGetSizeOfName(char &CharNameArray[]);
#import    

MQL 5'te "işaretçileri" iki şekilde iletebileceğinizi unutmayın:

  • void NameArray[] ; // Bu diziden iletme yöntemi yalnızca veri okumaya izin verir. Ancak, bu referansı "içeriğini düzenlemek" için kullanmaya çalışırsanız, bellek erişim hatası alırsınız (sizin için en iyi ihtimalle, MetaTrader 5, SEH-çerçevesindeki hatayı sessizce halledecektir, ancak biz bir SEH çerçevesi YAZMADIK, bu nedenle hatanın nedenini dahi gözden kaçırabiliriz).
  • void& NameArray[] ; // Bu iletme yöntemi, dizi içeriğini okumanıza ve düzenlemenize olanak tanır, ancak dizi boyutunu korumanız gerekir.

İşlev parametreleri kabul etmez veya iletmezse her zaman void türünü belirtin.

2. MatlabEngine.mq5 kaynak kodunu MATLABEngine.zip içinde bulabileceğiniz için MQL bloğunun tüm işlevlerini açıklamayacağız.

Dolayısıyla, MQL5'te harici işlevlerin bildirimi ve tanımının ayrıntılarını ele alacağız:

bool mlInputChar(string array)export
{
//... body of function
}

Örnekte görüldüğü gibi, işlevin bildirimi ve tanımı birleştirilmiştir. Bu durumda, bool türünün değerini döndüren ve dizi dizesini parametre olarak alan mlInputChar() adlı bir işlevi harici (dışa aktarma) olarak bildiririz. Şimdi derleyelim...

Kitaplığın son bloğunu da tamamlayıp derlediğimize göre artık gerçek koşullarda test etme zamanı.

Bunu yapmak için basit bir test dizesi yazın (veya MATLABEngine.zip dosya: TestMLEngine.mq5 dizininden alın).

Script dosyası kodu basit ve tam olarak açıklanmıştır:

#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/ru"
#property version   "1.00"
#import "MatlabEngine.ex5"
bool mlOpen(void);
void mlClose(void);
bool mlInputChar(string array);
bool mlInputDouble(double &array[],
                   int sizeArray,
                   string NameArray);
bool mlInputInt(int &array[],
                int sizeArray,
                string NameArray);
int mlGetDouble(double &array[],
                string NameArray);
int mlGetInt(int &array[],
             string NameArray);
bool mlInputLogical(bool &array[],
                    int sizeArray,
                    string NameArray);
int mlGetLogical(bool &array[],
                 string NameArray);
int mlGetSizeOfName(string strName);
#import
void OnStart()
  {
// Dynamic buffers for MATLAB output
   double dTestOut[];
   int    nTestOut[];
   bool   bTestOut[];
// Variables for MATLAB input
   double dTestIn[] = {   1,     2,    3,     4};
   int    nTestIn[] = {   9,    10,   11,    12};
   bool   bTestIn[] = {true, false, true, false};
   int nSize=0;
// Variables names and command line
   string strComm="clc; clear all;"; // command line - clear screen and variables
   string strA     = "A";            // variable A
   string strB     = "B";            // variable B
   string strC     = "C";            // variable C
/*
   ** 1. RUNNING DLL
   */
   if(mlOpen()==true)
     {
      printf("MATLAB has been loaded");
     }
   else
     {
      printf("Matlab ERROR! Load error.");
      mlClose();
      return;
     }
/*
   ** 2. PASSING THE COMMAND LINE
   */
   if(mlInputChar(strComm)==true)
     {
      printf("Command line has been passed into MATLAB");
     }
   else printf("ERROR! Passing the command line error");
/*
   ** 3. PASSING VARIABLE OF THE DOUBLE TYPE
   */
   if(mlInputDouble(dTestIn,ArraySize(dTestIn),strA)==true)
     {
      printf("Variable of the double type has been passed into MATLAB");
     }
   else printf("ERROR! When passing string of the double type");
/*
   ** 4. GETTING VARIABLE OF THE DOUBLE TYPE
   */
   if((nSize=mlGetDouble(dTestOut,strA))>0)
     {
      int ind=0;
      printf("Variable A of the double type has been got into MATLAB, with size = %i",nSize);
      for(ind=0; ind<nSize; ind++)
        {
         printf("A = %g",dTestOut[ind]);
        }
     }
   else printf("ERROR! Variable of the double type double hasn't ben got");
/*
   ** 5. PASSING VARIABLE OF THE INT TYPE
   */
   if(mlInputInt(nTestIn,ArraySize(nTestIn),strB)==true)
     {
      printf("Variable of the int type has been passed into MATLAB");
     }
   else printf("ERROR! When passing string of the int type");
/*
   ** 6. GETTING VARIABLE OF THE INT TYPE
   */
   if((nSize=mlGetInt(nTestOut,strB))>0)
     {
      int ind=0;
      printf("Variable B of the int type has been got into MATLAB, with size = %i",nSize);
      for(ind=0; ind<nSize; ind++)
        {
         printf("B = %i",nTestOut[ind]);
        }
     }
   else printf("ERROR! Variable of the int type double hasn't ben got");
/*
   ** 7. PASSING VARIABLE OF THE BOOL TYPE
   */
   if(mlInputLogical(bTestIn,ArraySize(bTestIn),strC)==true)
     {
      printf("Variable of the bool type has been passed into MATLAB");
     }
   else printf("ERROR! When passing string of the bool type");
/*
   ** 8. GETTING VARIABLE OF THE BOOL TYPE
   */
   if((nSize=mlGetLogical(bTestOut,strC))>0)
     {
      int ind=0;
      printf("Variable C of the bool type has been got into MATLAB, with size = %i",nSize);
      for(ind=0; ind<nSize; ind++)
        {
         printf("C = %i",bTestOut[ind]);
        }
     }
   else printf("ERROR! Variable of the bool type double hasn't ben got");
/*
   ** 9. ENDING WORK
   */
   mlClose();
  }

Script dosyasından görüldüğü gibi, değerleri giriyoruz ve ardından değerleri alıyoruz. Ancak, tasarım aşamasında arabellek boyutunu bilmemiz gereken MetaTrader 4'ün aksine, MetaTrader 5'te dinamik arabellekler kullandığımız için buna gerek yoktur.

MATLAB sanal makinesini anladığınıza göre, MATLAB ortamında yerleşik DLL kullanmaya başlayabilirsiniz.

3.2 MATLAB Derleyici 4 tarafından oluşturulan DLL oluşturma/kullanma teknik talimatları

Bir önceki bölümde MATLAB paketi ile evrensel etkileşim için bir kitaplığın nasıl oluşturulacağını öğrendiniz. Ancak, bu yöntemin bir dezavantajı vardır; son kullanıcıdan MATLAB paketi gerektirir. Bu kısıtlama, bitmiş yazılım ürününün dağıtımında bazı zorluklar yaratır. Bu nedenle MATLAB matematiksel paketi, MATLAB paketinden ayrı "bağımsız uygulamalar" oluşturmanıza olanak tanıyan yerleşik bir derleyici içerir. Buna bir göz atalım.

Örneğin, basit bir gösterge - hareketli ortalama (SMA) düşünün. "Beyaz gürültünün" (rastgele patlamalar) yumuşatılmasını sağlayan bir Sinir Ağı Filtresi (GRNN) ekleyerek bunu biraz yükseltin. Yeni göstergeyi NeoSMA olarak adlandırın ve GRNNFilter olarak filtreleyin.  

Böylece, MetaTrader 5'ten çağrılabilecek bir DLL oluşturmak istediğimiz iki m-işlevimiz var.

MetaTrader 5'in aşağıdaki klasörlerdeki DLL'leri aradığını unutmayın:

  • <terminal_dir>\MQL5\Libraries  
  • <terminal_dir>  
  • Mevcut klasör
  • Sistem klasörü <windows_dir>\SYSTEM32,  
  • <windows_dir>  
  • PATH sistem ortamı değişkeninde listelenen dizinler.

Dolayısıyla, DLL'yi oluşturacağımız iki m-işlevini (NeoSMA.m ve GRNNFilter.m) bu dizinlerden birine yerleştirin. Dikkatinizi bu yerleştirme gerçeğine çekiyorum; zira bu tesadüfen yapılmadı. Dikkatli okuyucular, MATLAB derleyici özelliği hakkında zaten bilgi sahibidir; bu, derleme sırasında yolları korur (bkz. "2.2 MATLAB Derleyici 4").

  Projeyi derlemeye başlamadan önce derleyiciyi yapılandırmanız gerekir. Bunu yapmak için şu adımları takip edin:   

  1. MATLAB komut satırına şunu girin: mbuild -setup
  2. Sisteminizde yüklü C/C++ uyumlu derleyicilerin bulunduğunu onaylamak için 'y' tuşuna basın.
  3. Standart Lcc-win32 C derleyicisini seçin.
  4. Seçilen derleyiciyi onaylamak için 'y' tuşuna basın.

Şekil 4. Projeyi derleme

Şekil 4. Projeyi derleme


Artık m-işlevlerini derleme işlemine geçmeye hazırız.

Bunun için şunu girin:

mcc -N -W lib:NeoSMA -T link:lib  NeoSMA.m GRNNFilter.m

Anahtarları açıklayın:

-N                                     —  tüm gereksiz yolları atlamak için
-W lib:NeoSMA                   —  derleyiciye kitaplığın adının NeoSMA olduğunu bildirir
-T link:lib                           —  derleyiciye, bağlantıyla ortak kitaplık oluşturmasını bildirir
NeoSMA.m ve GRNNFilter.m  —  m-işlevlerinin adları

Şimdi derleyicinin ne oluşturduğunu görelim:

  • mccExcludedFiles.log  —  derleyici eylemlerini içeren günlük dosyası
  • NeoSMA.c  —  kitaplığın C sürümü (sarmalayıcının С-kodunu içerir)  
  • NeoSMA.ctf  —  CTF dosyası (bkz. 2.2 MATLAB Derleyici 4) bölümü  
  • NeoSMA.h — üst bilgi dosyası (kitaplıkların, işlevlerin, sabitlerin bildirimlerini içerir)  
  • NeoSMA.obj — nesne dosyası (makine ve sözde kodu içeren kaynak dosya)  
  • NeoSMA.exports — dışa aktarılan işlev adları  
  • NeoSMA.dll — Daha fazla bağlantı için Dll  
  • NeoSMA.lib — C/C++ projelerinde kullanılacak Dll  
  • NeoSMA_mcc_component_data.c — bileşen üzerindeki C sürümü (CTF dosyasıyla uyumluluk için kullanılır, yolları vb.'yi içerir)  
  • NeoSMA_mcc_component_data.obj — bileşenin nesne sürümü (makine ve sözde kodu içeren kaynak dosya),

O halde DLL'nin tam olarak iç yapısını ele alalım. Şunlardan oluşur (yalnızca temel işlevler):

  1. Herhangi bir DLL'nin ana işlevi - DLL'de meydana gelen olayları işleyen (Microsoft belirtimine göre) BOOL WINAPI DllMain(): DLL'yi işlemenin adres alanına yükelme, yeni bir akış oluşturma, akışı silme ve Dll'yi bellekten kaldırma.  
  2. DLL başlatma/başlatmayı geri alma hizmet işlevleri: BOOL <NameLib>Initialize(void)/void <NameLib>Terminate(void) — Kitaplık işlevlerini kullanmadan önce ve kullandıktan sonunda Math Work ortamını başlatmak/kaldırmak için gereklidir.
  3. Dışa aktarılan m-işlevleri – void mlf<NameMfile>(int <number_of_return_values>, mxArray **<return_values>, mxArray *<input_values>, ...); burada:
    • <number_of_return_values> — döndürülen değişkenlerin sayısı (dizi boyutu vb. ile karıştırmayın).
    • mxArray **<return_values> — m-işlevinin çalışma sonuçlarının döndürüleceği mxArray yapısının adresi.
    • mxArray *<input_values> — m-işlevi giriş değişkeninin mxArray yapısına işaretçi.
     

Gördüğünüz gibi, dışa aktarılan m-işlevleri, mxArray yapısına adresler ve işaretçiler içerir ve bu tür verileri anlamayacağı için bu işlevleri doğrudan MetaTrader 5'ten çağıramazsınız. MetaTrader 5'te mxArray yapısını açıklamayacağız; zira MATLAB geliştiricileri, ürünün aynı sürümü içinde dahi zamanla değişmeyeceğini garanti etmiyor; bu nedenle basit bir DLL bağdaştırıcısı yazmanız gerekir.

Blok şeması aşağıda gösterilmiştir:

Şekil 5. DLL bağdaştırıcısı Blok Şeması

Şekil 5. DLL Bağdaştırıcısı Blok Şeması

Bu, MATLAB Engine için DLL'nin sağ tarafına çok benzer; bu nedenle algoritmasını ayrıştırıp doğrudan koda geçmeyeceğiz. Bunu yapmak için C/C++ derleyicinizde iki küçük dosya oluşturun:  

nSMA.cpp (DllMatlab.zip dosyasından):  

#include <stdio.h>
#include <windows.h>
/* Include MCR header file and library header file */
#include "mclmcr.h"
#include "NEOSMA.h"
/*---------------------------------------------------------------------------
** DLL Global Functions (external)
*/
extern "C" __declspec(dllexport) bool __stdcall IsStartSMA(void);
extern "C" __declspec(dllexport) bool __stdcall nSMA(double *pY,  int  nSizeY,
                                                     double *pIn, int nSizeIn,
                                                     double   dN, double dAd);
/*---------------------------------------------------------------------------
** Global Variables
*/
mxArray *TempY;
mxArray *TempIn;
mxArray *TempN;
mxArray *TempAd;
bool bIsNeoStart;
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    switch(reason)
    {
        case DLL_PROCESS_ATTACH:
         bIsNeoStart = false;
         TempY  = 0;   //Nullify pointers to buffers
         TempN  = 0;
         TempIn = 0;
         TempAd = 0;
         break;
        case DLL_PROCESS_DETACH:
         NEOSMATerminate();
         //Delete old data before exiting from Dll
         if(TempY  != NULL) mxDestroyArray(TempY);
         if(TempN  != NULL) mxDestroyArray(TempN);
         if(TempIn != NULL) mxDestroyArray(TempIn);
         if(TempAd != NULL) mxDestroyArray(TempAd);
         mclTerminateApplication();
    }
    return 1;
}
//---------------------------------------------------------------------------
bool __stdcall IsStartSMA(void)
{
 if(bIsNeoStart == false)
 {
  if(!mclInitializeApplication(NULL,0) )
  {
   MessageBoxA(NULL, (LPSTR)"Can't start MATLAB MCR!",
               (LPSTR) "MATLAB DLL: ERROR!", MB_OK|MB_ICONSTOP);
   return false;
  }else
   {
    bIsNeoStart = NEOSMAInitialize();
   };
 };
 return bIsNeoStart;
}
//---------------------------------------------------------------------------
bool __stdcall nSMA(double *pY, int nSizeY, double *pIn, int nSizeIn, double dN, double dAd)
{
   /*
   ** Create buffers
   */
   if(TempN == NULL){ TempN = mxCreateDoubleMatrix(1, 1, mxREAL);}
   else
   {
     mxDestroyArray(TempN);
     TempN= mxCreateDoubleMatrix(1, 1, mxREAL);
   };
   if(TempIn == NULL){ TempIn = mxCreateDoubleMatrix(1, nSizeIn, mxREAL);}
   else
   {
     mxDestroyArray(TempIn);
     TempIn= mxCreateDoubleMatrix(1, nSizeIn, mxREAL);
   };
   if(TempAd == NULL){ TempAd = mxCreateDoubleMatrix(1, 1, mxREAL);}
   else
   {
     mxDestroyArray(TempAd);
     TempAd= mxCreateDoubleMatrix(1, 1, mxREAL);
   };
   /*
   ** Creating data for processing
   */
   memcpy((char *)mxGetPr(TempIn), (char *) pIn, (nSizeIn)*8);
   memcpy((char *)mxGetPr(TempN), (char *) &dN, 8);
   memcpy((char *)mxGetPr(TempAd), (char *) &dAd, 8);
   /*
   ** Send and receive a response from the m-function
   */
   if(mlfNeoSMA(1, (mxArray **)TempY, (mxArray *)TempIn, (mxArray *)TempN
      , (mxArray *)TempAd) == false) return false;
   /*
   ** Return calculated vector from the m-function and clear buffers
   */
   memcpy((char *) pY, (char *)mxGetPr(TempY), (nSizeY)*8);
   mxDestroyArray((mxArray *)TempY);  TempY  = 0;
   mxDestroyArray((mxArray *)TempN);  TempN  = 0;
   mxDestroyArray((mxArray *)TempIn); TempIn = 0;
   mxDestroyArray((mxArray *)TempAd); TempAd = 0;
   return true;
}

nSMA.def (DllMatlab.zip dosyasından):

KİTAPLIK nnSMA
DIŞA AKTARMALAR
IsStartSMA
nSMA


Projeyi C/C++ derleyicinizde oluşturun: Bunun için, standart giriş/çıkış kitaplığını eklemeniz ve aşağıdaki dosyaları projeye eklemeniz gerekir (derleyicinizde: Proje->Proje Ekle):

  1. nSMA.def
  2. <MATLAB>\Extern\lib\<win32/64>\<compiler>\ klasöründe:
    <MATLAB> — MATLAB ana klasörü.
    <win32/64> — 32-bit işletim sistemi için win32 klasörü veya 64-bit işletim sistemi için win64 klasörü.
    <compiler>— Borland C/C++ ver için "borland" klasörü. 5-6, Microsoft Visual C++ için "microsoft" klasörü (sürüm 6 için dosyalarım var):  
    • libmx.lib
    • mclmcr.lib
  3. NeoSMA.lib — Manuel olarak oluşturun (bkz. 3.1 MetaTrader 5 ve MATLAB Engine Etkileşiminin Evrensel Kitaplığını Geliştirme).  

Bu bölümde anlatmak istediğim son şey MATLAB'ın yüklü olmadığı başka bir bilgisayara proje taşırken ihtiyaç duyulan dosyalar hakkındadır.

Hedef makinedeki dosyaların ve yolların listesi şu şekildedir:

  • MCRInstaller.exe                    herhangi bir klasör (MCR yükleyicisi için)
  • extractCTF.exe                      herhangi bir klasör (MCR yükleyicisi için)
  • MCRRegCOMComponent.exe  herhangi bir klasör (MCR yükleyicisi için)
  • unzip.exe                              herhangi bir klasör (MCR yükleyicisi için)
  • NeoSMA.dll                           <terminal_dir>\MQL5\Libraries
  • NeoSMA.ctf                           <terminal_dir>\MQL5\Libraries
  • nnSMA.dll                             <terminal_dir>\MQL5\Libraries

Birçok ileri düzey programcı, bir yükleyici programı (KURULUM) kullanılmasının tavsiye edildiğini zaten tahmin etmiştir. Ücretsiz ürünler de dahil olmak üzere bunların birçoğu internetten bulunabilir.

Şimdi bu DLL'yi MetaTrader 5'te test etmemiz gerekiyor. Bunu yapmak için basit bir script dosyası yazacağız (DllMatlab.zip'ten TestDllMatlab.mq5):

#property copyright "2010, MetaQuotes Software Corp."
#property link      "nav_soft@mail.ru"
#property version   "1.00"
#import "nnSMA.dll"
bool  IsStartSMA(void);
bool  nSMA(double &pY[],
           int nSizeY,
           double &pIn[],
           int nSizeIn,
           double dN,
           double dAd);
#import
datetime    Time[];    // dynamic array of time coordinates
double      Price[];   // dynamic array of price
double      dNeoSma[]; // dynamic array of price
void OnStart()
  {
   int ind=0;
// run Dll
   if(IsStartSMA()==true)
     {
      //--- create and fill arrays
      CopyTime(Symbol(),0,0,301,Time);   // time array + 1
      ArraySetAsSeries(Time,true);       // get the time chart
      CopyOpen(Symbol(),0,0,300,Price);  // price array
      ArraySetAsSeries(Price,true);      // get the open prices
      ArrayResize(dNeoSma,300,0);        // reserve space for function response
                                         // get data
      if(nSMA(dNeoSma,300,Price,300,1,2)==false) return;
      // specify array orientation
      ArraySetAsSeries(dNeoSma,true);
      // plot data on chart
      for(ind=0; ind<ArraySize(dNeoSma);ind++)
        {
         DrawPoint(IntegerToString(ind,5,'-'),Time[ind],dNeoSma[ind]);
        }
     }
  }
//+------------------------------------------------------------------+
void DrawPoint(string NamePoint,datetime x,double y)
  {  // 100% ready. Plot data on chart. Drawing using arrows.
// Main properties of chart object
   ObjectCreate(0,NamePoint,OBJ_ARROW,0,0,0);
   ObjectSetInteger(0, NamePoint, OBJPROP_TIME, x);        // time coordinate x
   ObjectSetDouble(0, NamePoint, OBJPROP_PRICE, y);        // price coordinate y
// Additional properties of chart object
   ObjectSetInteger(0, NamePoint, OBJPROP_WIDTH, 0);       // line width
   ObjectSetInteger(0, NamePoint, OBJPROP_ARROWCODE, 173); // arrow type
   ObjectSetInteger(0, NamePoint, OBJPROP_COLOR, Red);     // arrow color
  }
//+------------------------------------------------------------------+

Sonuç

Artık, MetaTrader 5 ve MATLAB etkileşimi için evrensel bir kitaplığın nasıl oluşturulacağını ve MATLAB ortamında yerleşik DLL'nin nasıl bağlanacağını biliyorsunuz. Ancak yine de MetaTrader 5 ve MATLAB etkileşiminin tanımlanacak arayüzleri var, ancak bu, bu makalenin kapsamı dışındadır. Bu makalenin konusu ayrıntılı olarak ele alınmıştır. Özel bir "bağdaştırıcı" türü gerektirmeyen en etkili etkileşim yollarını seçtim. .NET teknolojisi - WCF Hizmetlerini Kullanarak MetaTrader 5'ten .NET Uygulamalarına Fiyat Tekliflerini Dışa Aktarma gibi "başka bir yoldan" gidebilirsiniz.

Birçok okuyucu şu soruyu soruyor olabilir: Hangi yöntemi seçmemiz gerekiyor? Yanıt basit: Her ikisi de; zira matematiksel modelin tasarımı/hata ayıklaması sırasında hıza ihtiyaç duyulmaz. Ancak programlama için "özel üretim maliyetleri" olmadan MATLAB'ın tam gücüne ihtiyacınız olacak. MATLAB Engine burada elbette yardımcı olacaktır. Ancak, matematiksel modelde hata ayıklandığında ve kullanıma hazır olduğunda, hıza, çoklu göreve (birkaç fiyat grafiğinde gösterge ve/veya alım satım sisteminin çalışması) ihtiyacınız olacak; burada şüphesiz MATLAB ortamında yerleşik bir DLL'ye ihtiyaç duyacaksınız.

Ancak tüm bunlar sizi onu takip etmeye zorunlu kılmaz. Herkes, öncelikli olarak "programlama maliyetinin" proje ölçeğine oranına (gösterge ve/veya alım satım sistemi kullanıcılarının sayısı) dayanarak bu sorunun yanıtını kendisi verecektir. MATLAB ortamında bir veya iki kullanıcı için Dll oluşturmak bir anlam ifade etmez (MATLAB'ı iki bilgisayara yüklemek daha kolaydır).  

MATLAB hakkında bilgi sahibi olmayan birçok okuyucunun muhtemelen şöyle bir sorusu vardır: Neden MATLAB kullanalım? MQL5 zaten matematiksel işlevlere sahip! Yanıt, MATLAB kullanımının matematiksel fikirlerinizi fazla çaba göstermeden uygulamanıza olanak tanımasıdır; olasılıkların yalnızca kısmi bir listesi şu şekildedir:  

  • Gösterge ve/veya mekanik alım satım sisteminde bulanık mantığın dinamik algoritması  
  • Mekanik alım satım sisteminde dinamik genetik algoritma (dinamik strateji test cihazı)
  • Gösterge ve/veya mekanik alım satım sisteminde dinamik sinir ağı algoritması  
  • Üç boyutlu göstergeler
  • Doğrusal olmayan yönetim sistemlerinin simülasyonu

Yani, her şey sizin elinizde; şunu unutmayın: "Matematik her zaman bilimlerin kraliçesi olmuştur" ve MATLAB paketi — bilimsel hesap makinenizdir.

Literatür

  1. MATLAB yerleşik yardımı.
  2. MQL5 yerleşik yardımı.
  3. Jeffrey Richter. Microsoft Windows için Programlama Uygulamaları.

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

Ekli dosyalar |
dllmatlab_en.zip (955.7 KB)
matlabengine_en.zip (670.57 KB)
Yeni Başlayanlar için Çoklu Gösterge Arabelleği ile Bir Gösterge Oluşturma Yeni Başlayanlar için Çoklu Gösterge Arabelleği ile Bir Gösterge Oluşturma
Karmaşık kodlar bir dizi basit koddan meydana gelir. Bu kodlar hakkında bilgi sahibiyseniz, bu, o kadar karmaşık görünmez. Bu makalede, çoklu gösterge arabelleği ile bir göstergenin nasıl oluşturulacağını ele alacağız. Örnek olarak Aroon göstergesi ayrıntılı olarak analiz edilmiş ve kodun iki farklı sürümü sunulmuştur.
Grafik Kontrol Seçenekleri ile Gösterge Oluşturma Grafik Kontrol Seçenekleri ile Gösterge Oluşturma
Piyasa duyarlılığına aşina olanlar MACD göstergesi hakkında bilgi sahibidir (tam adı Hareketli Ortalama Yakınsama/Iraksama'dır) - Bu, yatırımcılar tarafından bilgisayar analiz yöntemlerinin ortaya çıktığı ilk anlardan itibaren kullanılan fiyat hareketini analiz etmek için güçlü bir araçtır. Bu makalede, MACD'ye ilişkin olası değişiklikleri ele alacağız ve bunları, değişiklikler arasında grafiksel olarak geçiş yapma imkanıyla tek bir göstergede uygulayacağız.
"Yeni Başlayanlar" için MQL: Nesne Sınıfları Nasıl Tasarlanır ve Oluşturulur? "Yeni Başlayanlar" için MQL: Nesne Sınıfları Nasıl Tasarlanır ve Oluşturulur?
Örnek bir görsel tasarım programı oluşturarak, MQL5'te sınıfların nasıl tasarlanacağını ve oluşturulacağını gösteriyoruz. Makale, MT5 uygulamaları üzerinde çalışan yeni başlayan programcılara yönelik olarak yazılmıştır. Nesne yönelimli programlama teorisine derinlemesine dalmaya gerek kalmadan sınıflar oluşturmak için basit ve kolay kavranabilen bir teknoloji öneriyoruz.
MQL5'te olay işleme: MA dönemini anında değiştirme MQL5'te olay işleme: MA dönemini anında değiştirme
13. dönemli basit MA (Hareketli Ortalama) göstergesinin bir grafiğe uygulandığını varsayalım. Ve dönemi 20 olarak değiştirmek istiyoruz, ancak gösterge özellikleri iletişim kutusuna gidip 13 ila 20 sayısını düzenlemek istemiyoruz: Fare ve klavyeyi kullanarak bu sıkıcı işlemleri yapmaktan sıkıldık. Ve özellikle gösterge kodunu açıp değiştirmek istemiyoruz. Tüm bunları tek bir düğmeye basarak yapmak istiyoruz; sayısal tuş takımının yanındaki "yukarı oklara" basarak. Bu makalede bunun nasıl yapılacağını anlatacağım.