English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Interazione MetaTrader 5 e MATLAB

Interazione MetaTrader 5 e MATLAB

MetaTrader 5Esempi | 15 dicembre 2021, 17:13
309 0
Andrey Emelyanov
Andrey Emelyanov

Introduzione

Il mio primo articolo Interazione tra MetaTrader 4 e MATLAB Engine (Virtual MATLAB Machine) è stato notato dalla comunità MQL. Alcuni lettori (1Q2W3E4R5T) sono stati persino in grado di spostare questo progetto da Borland a VS2008. Ma il tempo scorre inesorabilmente e (triste ma vero) MetaTrader 4 sta scomparendo, lasciando il posto al suo successore MetaTrader 5 con MQL5, che ha introdotto i puntatori e la memoria dinamica. 

Grazie a queste innovazioni, abbiamo la possibilità di scrivere una libreria universale di interazione con la macchina virtuale MATLAB Engine, e di collegare direttamente le librerie, generate da MATLAB, con MetaTrader 5. Questo articolo tratta tale funzionalità. Questo articolo continua logicamente il precedente e tratta in modo più approfondito il problema dell'interazione tra MetaTrader 5 e MATLAB.

Per rendere lo scopo di questo articolo più comprensibile ai lettori impreparati, lo divideremo in tre parti: teoria, riferimento e pratica. La teoria riguarderà i tipi di dati utilizzati in MQL5 e MATLAB, nonché la loro conversione reciproca. In Riferimenti imparerai le strutture linguistiche e la sintassi delle funzioni necessarie per creare una DLL. E in Pratica analizzeremo le "insidie" di questa interazione.

I lettori esperti possono saltare la teoria e il riferimento e iniziare con la pratica. Altri sono invitati a leggere Teoria e Riferimenti e solo allora procedere alla Pratica. Vale anche la pena leggere i libri citati nella sezione "Letteratura".

1. Teoria

1.1 Tipi di Dati in MATLAB e MQL5

1.1.1 Tipi di Dati Semplici

Procediamo.

Prima di tutto, dobbiamo familiarizzare con i mondi interiori di MQL5 e MATLAB. Dopo un'ispezione superficiale dei tipi delle variabili, concludiamo che sono quasi identici:

MQL5
Dimensione in byte
Valore minimo
Valore massimo
 MATLAB
char
1
-128
127
Array int8/char
uchar
1
0
255
Array int8/char
bool
1
0(false)
1(true)
Array logico
short
2
-32768
32767
Array int16
ushort
2
0
65535
Array int16
int
4
-2147483648
2147483647
Array int32
uint
4
0
4294967295
Array int32
long 8
-9223372036854775808
9223372036854775807 Array int64
ulong 8
0
18446744073709551615
Array int64
float 4
1.175494351e-38
3.402823466e+38
Array singolo
double
8
2.225073858507201e-308
1.7976931348623158e+308
Array doppio

Tabella 1. Tipi di Dati in MATLAB e MQL5

C'è una grande differenza: le variabili in MQL5 possono essere semplici o composite (complesse) e in MATLAB tutte le variabili sono multidimensionali (complesse) - cioè la matrice. Devi sempre ricordare questa differenza!

1.1.2 Tipi di Dati Complessi

In MQL5 ci sono 4 tipi complessi di dati: array, stringhe, strutture e classi. Il tipo di dati complessi è un insieme di diversi tipi di dati semplici, combinati in blocchi di memoria di una certa lunghezza. Quando si tratta di tali dati è sempre necessario conoscere la dimensione del blocco di memoria in byte o il numero di elementi (eccetto le classi). Siamo interessati solo agli array e alle stringhe, perché inviare classi e strutture MQL5 a MATLAB non ha senso.

Quando si passano array di qualsiasi tipo è necessario conoscere: tipo (dimensione) e numero di elementi utilizzando la funzione ArraySize(). Particolare attenzione dovrebbe essere data all'indicizzazione in MetaTrader 5 - di solito è all'indietro (cioè il primo elemento contiene dati più recenti rispetto al successivo). Controlla questo usando la funzione ArrayIsSeries(). E MATLAB ha la seguente indicizzazione: il primo elemento contiene i dati più vecchi del successivo, quindi devi "invertire" i tuoi array prima di inviarli a MATLAB, se flag AS_SERIES = TRUE. Sulla base di quanto sopra, concordiamo con quanto segue:

  • "Invertire" gli array "invisibilmente" ai programmi MQL5, ad eccezione degli array del tipo char e degli array bidimensionali, lasciarli invariati.
  • Inverti "invisibilmente" tutti gli array da MATLAB e assegna il flag AS_SERIES con TRUE, ad eccezione degli array del tipo char e degli array bidimensionali: lasciali invariati.
  • In ogni array nel programma MQL5, creato in base all'indicizzazione "all'indietro", il flag AS_SERIES deve essere TRUE, ad eccezione degli array di tipo char e degli array bidimensionali - lasciarli invariati.  

Ma questa non è l'unica limitazione quando si lavora con gli array. Quando lavori con array multidimensionali, o matrici per essere più corretti, specialmente da MATLAB, introduciamo la restrizione per non più di 2 array bidimensionali. Qui il flag AS_SERIES non può essere TRUE e quindi tali array non sono "invertiti".

Non dimenticare che le stringhe in MQL5 non sono array degli elementi di tipo char. Quindi, quando si passano le stringhe si presenta un piccolo problema: nelle stringhe MQL5 codificate utilizzando Unicode e MATLAB utilizza la codifica ANSI. Quindi, prima di passare una stringa, dovrebbe essere convertita in un array di caratteri ANSI utilizzando la funzione StringToCharArray(). E viceversa, quando ottieni un array di caratteri da MATLAB, convertilo usando la funzione CharArrayToString() (vedi Tabella 2). Per evitare confusione, concorda: memorizza tutte le stringhe nei programmi MQL5 utilizzando Unicode, nessun array del tipo char.

1.2 Confronto tra Tipi di Dati MQL5 e MATLAB

Al fine di ridurre la quantità di funzioni e semplificare l'algoritmo della libreria, ridurremo la quantità di tipi mediante conversione automatica che non dovrebbe influire sull'integrità dei dati. La tabella seguente illustra la regola di conversione del tipo di dati da MQL5 a MATLAB:

 MQL5 
Equivalente MatLab
char 
uchar
Char dell’array
bool
Array logico
short
ushort
int
uint
Array int32
long
ulong
Array int64*
float
double
Array doppio
string
Char dell’array utilizzando le funzioni StringToCharArray() <=> CharArrayToString()

* Con questo tipo di conversione c'è una perdita di precisione. Non lo useremo, ma puoi usare tale conversione nei tuoi programmi.

Tabella 2 Confronto tra Tipi di Dati MQL5 e MATLAB

Ora hai familiarità con i tipi di dati utilizzati in MQL5 e MATLAB. Sapete quali "insidie" attendono il passaggio dei dati e come aggirarli con competenza. Devi ancora conoscere MATLAB Engine API e acquisire familiarità con MATLAB Compiler 4.

2. Riferimento API MATLAB Engine, Riferimento MATLAB Compiler 4 e Riferimento libreria C++ Input/Output

Questa sezione ti introduce alle funzioni più importanti dell'API MATLAB Engine, alle caratteristiche di MATLAB Compiler 4 e al numero di funzioni utili della libreria di input/output standard C++. Quindi, cominciamo.

2.1 API del Motore MATLAB e Funzioni MCR

MATLAB Engine - è un'interfaccia esterna che consente ad altri programmi di utilizzare il desktop MATLAB. Fornisce un lavoro completamente funzionale di tutti i pacchetti MATLAB senza alcuna restrizione.

Sebbene non sia specificato nella documentazione, ma in termini di programmatore di sistema - è solo una macchina virtuale, come PHP, MySQL, ecc. che supporta un modo semplice e relativamente veloce per scambiare dati tra MetaTrader 4/5 e MATLAB.  

Questo metodo di connessione di programmi esterni con il pacchetto MATLAB è consigliato dagli sviluppatori. L'interfaccia è composta da sei funzioni:

Engine *pEng = engOpen(NULL) — questa funzione chiama il desktop MATLAB, il parametro è sempre NULL, restituisce un puntatore al descrittore del desktop.

int exitCode = engClose(Engine *pEng) — questa funzione chiude il desktop, restituisce il numero di utenti rimanenti del desktop MATLAB, dove:

  • Motore *pEng — puntatore al descriptor del desktop.  

mxArray *mxVector = mxCreateDoubleMatrix(int m, int n, int ComplexFlag) — questa funzione crea una variabile (matrice) di MATLAB desktop, restituisce un puntatore alla variabile (matrice), dove:

  • mxArray *mxVector — puntatore alla variabile matrice.  
  • //--- numero di righe  
  • int n — numero di colonne.  
  • ComplexFlag — tipo di numero complesso per MetaTrader 4/5 mxREAL.
void = mxDestroyArray(mxArray *mxVector)— questa funzione distrugge la matrice MATLAB, è necessaria per cancellare la memoria, dove:
  • mxArray *mxVector — puntatore alla variabile matrice.  
int = engPutVariable(Engine *pEng, char *Name, mxArray *mxVector)— questa funzione invia la variabile al desktop. Non devi solo creare variabili di tipo mxArray, ma anche inviarle a MATLAB, dove:
  • Motore *pEng — puntatore al descriptor del desktop.  
  • char *Name — nome della variabile del tipo char nel desktop MATLAB.  
  • mxArray *mxVector — puntatore alla variabile matrice.  
mxArray *mxVector = engGetVariable(Engine *pEng, char *Name) — questa funzione ottiene la variabile dal desktop - l'inverso della funzione precedente. Sono accettate solo variabili di tipo mxArray, dove:
  • mxArray *mxVector — puntatore alla variabile matrice.  
  • Motore *pEng — puntatore al descriptor del desktop.  
  • char *Name — nome della variabile del tipo char nel desktop MATLAB.  
double *p = mxGetPr(mxArray *mxVector) — questa funzione ottiene il puntatore all'array di valori, viene utilizzata per copiare i dati insieme a memcpy() (vedi 2.3 Libreria di input/output standard C++), dove:
  • double *p — puntatore all'array di tipo double.  
  • mxArray *mxVector — puntatore alla variabile matrice.  
int = engEvalString(Engine *pEng, char *Command) — questa funzione invia comandi al desktop MATLAB, dove:
  • Motore *pEng — puntatore al descriptor del desktop.  
  • char *Command — comando per MATLAB, stringa del tipo char.  

Probabilmente hai notato che l'API MATLAB Engine ti consente di creare una struttura mxArray solo per il tipo double. Ma questa restrizione non influisce sulle tue possibilità, ma influenzerà l'algoritmo della tua libreria.

MCR (MCR instance) — è la libreria speciale del pacchetto MATLAB che consente di eseguire applicazioni/biblioteche pubbliche autonome, generate dall'ambiente MATLAB su qualsiasi computer. Nota che anche se hai un pacchetto MATLAB completo, devi comunque installare la libreria MCR eseguendo il file MCRInstaller.exe che si trova nella cartella <MATLAB>\Toolbox\compiler\deploy\win32. Quindi, prima di chiamare qualsiasi funzione di libreria pubblica creata dall'ambiente MATLAB, è necessario chiamare la funzione di inizializzazione MCR:
 
bool = mclInitializeApplication(const char **option, int count) – ritorna TRUE se l'avvio di MCR ha avuto successo, altrimenti FALSE, dove:

  • const char **option — stringa di opzioni, come in mcc - R; di solito è NULL  
  • int count — stringa di opzioni di dimensione, in genere 0.

Al termine del lavoro di biblioteca pubblica è necessario chiamare:
bool = mclTerminateApplication(void) — ritorna TRUE se MCR è stato chiuso correttamente.

2.2 Compiler MATLAB 4

MATLAB Compiler ti consente di creare quanto segue dalle funzioni M:  

  • Applicazioni autonome che vengono eseguite anche se MATLAB non è installato.
  • Librerie di condivisione C/C++, che possono essere utilizzate senza MATLAB sui sistemi degli utenti finali.

Il Compiler supporta la maggior parte dei comandi e dei pacchetti di MATLAB, ma non tutti. L'elenco completo delle restrizioni è disponibile sul sito web di MATLAB. Questo metodo consente di creare "bundle indipendenti dal software" di MetaTrader 5 e MATLAB, ma a differenza di MATLAB Engine, richiede un programmatore ben addestrato e una profonda conoscenza della compilazione.

Il Compiler MATLAB richiede almeno uno dei seguenti compiler C/C++:

  • Lcc C (di solito viene fornito con MATLAB). È solo un compiler C.  
  • Borland C++ versioni 5.3, 5.4, 5.5, 5.6.
  • Microsoft Visual C/C++ versioni 6.0, 7.0, 7.1.

MATLAB Compiler 4, a differenza dei suoi predecessori, genera solo il codice dell'interfaccia (wrapper), cioè non traduce le funzioni m in codice binario o C/C++, ma crea un file speciale basato sulla tecnologia Component Technology File (CTF), che include integrazioni di vari pacchetti, necessari per supportare m-functions. MATLAB Compiler crittografa anche questo file con una chiave univoca (non ripetuta) a 1024 bit.

Consideriamo ora l'algoritmo di MATLAB Compiler 4, poiché l'ignoranza di questo argomento porterà a molti errori stupidi in fase di compilazione:

  1. Analisi delle dipendenze: in questa fase determina tutte le funzioni, i file MEX e i file P, da cui dipendono le m-funzioni compilate.  
  2. Creazione di un archivio: il file CTF viene creato, crittografato e compresso.  
  3. Generazione del codice oggetto del wrapper – in questa fase vengono creati tutti i codici sorgente, necessari per il componente:
    • Codice interfaccia C/C++ per m-funzioni specificate nella riga di comando (NomeFile_main.c).
    • File del componente (NameFile_component.dat), che contiene tutte le informazioni necessarie per eseguire m-code (incluse chiavi e percorsi di crittografia, archiviati nel file CTF).  
  4. Traduzione C/C++. In questa fase i file del codice sorgente C/C++ vengono compilati nei file oggetto.
  5. Collegamento. La fase finale della costruzione del progetto.

Ora, quando hai familiarità con il comportamento dell'algoritmo del compilatore MATLAB, devi imparare di più sulle chiavi per avere un piano dettagliato delle azioni quando usi il compiler (mcc):   

Chiave
Scopo
    un nome del file
 Aggiungi il file <nomefile> all'archivio, determina quali file verranno aggiunti all'archivio CTF
     l
 Macro, che genera una libreria di funzioni
    N
 Cancella tutti i percorsi, tranne il set minimo di directory necessario
    p <directory>
 Aggiungi il percorso di traduzione secondo la procedura. Richiede la chiave -N.
    R -nojvm
 Annulla l'opzione MCR (MATLAB Component Runtime, vedere la Guida di MATLAB)
    W
 Gestire la creazione di funzioni wrapper
    lib
 Creare funzioni di inizializzazione e completamento
    main
 Crea una shell POSIX della funzione main()
    T
 Specificare la fase di uscita
    codegen
 Crea il codice wrapper per l'applicazione autonoma
    compile:exe
 Uguale al codegen
    compile:lib
 Crea codice wrapper per le DLL pubbliche
    link:exe
 Uguale a compile:exe più il collegamento
    link:lib
 Uguale a compile:exe più il collegamento

Tabella 3 Chiavi del Compiler Matlab mcc (versione 4)

La tabella 3 contiene chiavi di base che possono essere utili per risolvere problemi tipici. Per ulteriore assistenza, utilizzare i comandi MATLAB help mcc o doc mcc.

Dobbiamo familiarizzare con il linker MATLAB, di seguito sono riportate le chiavi principali (mbuild):

 Chiave
Scopo
 -setup
 In modalità interattiva, definizione del file delle opzioni del compiler da utilizzare per impostazione predefinita nelle chiamate future di mbuild
 -g
 Creare un programma con informazioni di debug. Aggiungi DEBUGFLAGS alla fine del file.
 -O
 Ottimizzazione del codice oggetto

Tabella 4 Chiavi Matlab mbuild Linker (versione 4)

La tabella 4 elenca le chiavi principali. Per ulteriori informazioni, utilizzare i comandi help mbuild o doc mbuild.

2.3 Libreria di input/output standard C++

L'utilizzo della libreria Standard Input/Output fornisce la copia corretta dei dati. Il suo utilizzo ti salverà da errori "stupidi" che si verificano durante la fase di progettazione del programma (ad esempio: molti programmatori alle prime armi copiano solo il puntatore al blocco di memoria invece di copiare l'intero blocco di memoria ). Dell'intera libreria Input/Output ci interessa solo una funzione:

void *pIn = memcpy(void *pIn, void *pOut, int nSizeByte) – questa funzione copia (cloni) variabile/array da pOut a pIn con dimensione di nSizeByte byte, dove:

  • void *pIn — puntatore all'array, dove copiare.  
  • void *pOut — puntatore all'array, da cui viene eseguita la copia.  
  • int nSizeByte — la dimensione dei dati copiati, non deve superare la dimensione dell'array pIn, altrimenti si verificherà un errore di accesso alla memoria.  

3. Pratica

Ora abbiamo finito con la teoria e possiamo procedere con la realizzazione dell'interazione MetaTrader 5 e MATLAB.

Come probabilmente avrai intuito, ciò avverrà in due modi: utilizzando la macchina virtuale MATLAB Engine e utilizzando le librerie generate da MATLAB Compiler. Innanzitutto, considera un modo di interazione semplice, veloce e versatile tramite MATLAB Engine.

Questa parte dell'articolo deve essere letta dall'inizio alla fine, poiché, nonostante l'apparente differenza tra i metodi di interazione, hanno una filosofia e una sintassi familiare dei costrutti linguistici e imparare qualcosa di nuovo è più facile con semplici esempi.

3.1 Sviluppo della Libreria Universale di MetaTrader 5 e Interazione con MATLAB Engine

Questo metodo di interazione non può essere definito elegante e veloce, ma è il più affidabile e copre l'intero pacchetto MATLAB. Naturalmente, dovremmo menzionare la velocità di sviluppo del modello finale. L'essenza dello sviluppo è scrivere un wrapper di libreria universale per l'interazione con MetaTrader 4/5 e MATLAB Engine. Dopo questo script/indicatore/esperto MetaTrader 4/5 può gestire il desktop virtuale MATLAB. E l'intero algoritmo matematico può essere memorizzato nel programma MQL come stringhe, quindi puoi usarlo per proteggere la tua proprietà intellettuale (per maggiori dettagli vedi l'articolo "Proteggetevi, sviluppatori!"). Può anche essere memorizzato in file separati di funzioni m o funzioni P nella cartella <MetaTrader 5>\MQL5\Libraries.  

Possibili ambiti di applicazione di tale interazione:

  • Per testare o dimostrare "modelli/idee matematici" senza dover scrivere programmi complessi (la protezione della proprietà intellettuale può essere organizzata come nel programma MQL e tramite il pacchetto MATLAB - utilizzando le funzioni P).  
  • Per scrivere modelli matematici complessi utilizzando tutte le funzionalità di MATLAB.
  • A tutti coloro che non distribuiranno i propri script/indicatori/esperti.

Procediamo. Spero che tu abbia letto i 1.1 tipi di dati in MATLAB e MQL5, 1.2 Confronto tra Tipi di Dati MQL5 e MATLAB, 2.1 MATLAB Engine API e Funzioni MCR2.3 C++ Libreria Standard Input/Output , poiché non li metteremo in pausa e li analizzeremo più . Leggere attentamente il seguente schema a blocchi, che illustra l'algoritmo della futura libreria:  

 Figura 1. Schema a Blocchi dell'Algoritmo della Libreria

Figura 1. Schema a Blocchi dell'Algoritmo della Libreria

Come mostrato nella Figura 1, la libreria è composta da tre blocchi principali. Considera i loro scopi:

  • Blocco MQL5, preparazione preliminare dei dati inviati/ricevuti:  
    • Array inverse.
    • Conversione di tipi.
    • Conversione di codifiche di stringhe.
  • Blocco C/C++:
    • Converte l'array nella struttura mxArray.
    • Passa i comandi del motore MATLAB.
  • MATLAB Engine block — sistema di calcolo.  

Passiamo ora agli algoritmi. Inizieremo con il blocco MQL5. Il lettore attento ha già notato che si concentrerà sull'implementazione di quanto scritto nella sezione Tipi di Dati in MATLAB e MQL5. Se te lo sei perso, difficilmente capirai perché tutto questo è necessario.

L'algoritmo delle funzioni mlInput <variable_type> è quasi identico. Discutiamo il suo lavoro utilizzando la funzione mlInputDouble() che fornisce input di variabili di tipo double alla macchina virtuale MATLAB.

Ecco il prototipo:

bool mlInputDouble(double &array[],int sizeArray, string NameArray), dove:

  • array — riferimento a variabile o array di tipo double.
  • sizeArray— dimensione dell'array (numero di elementi, non byte!). 
  • NameArray — stringa, contenente il nome della variabile univoco per la macchina virtuale MATLAB (il nome deve corrispondere ai requisiti MATLAB).

Algoritmo:

  1. Converti la stringa NameArray in un array di char utilizzando la funzione StringToCharArray().
  2. Controllareil tipo di indicizzazione utilizzando la funzione ArrayIsSeries(). Se il tipo di indicizzazione è normale, passa il valore alla funzione mlxInputDouble().
    ELSE indicizzazione dell'array di serie temporali:
    array "reverse" e passa valore alla funzione mlxInputDouble().
  3. End function, passa il valore restituito alla funzione mlxInputDouble().

Anche l'algoritmo delle funzioni mlGet <variable_type> è quasi identico. Discutiamone il lavoro utilizzando la funzione mlGetDouble() che restituisce una variabile di tipo double dalla macchina virtuale MATLAB.

Il prototipo:

int mlGetDouble(double &array[],int sizeArray, string NameArray), dove:

  • array — riferimento a variabile o array di tipo double.
  • sizeArray— dimensione dell'array (numero di elementi, non byte!). 
  • NameArray — stringa, contenente un nome di variabile univoco per la macchina virtuale MATLAB.

Algoritmo:

  1. Converti la stringa NameArray in un array di char utilizzando la funzione StringToCharArray().   
  2. Trova la dimensione dell'array usando la funzione mlxGetSizeOfName().
    • SEla dimensione è MAGGIORE DI ZERO, allocare l'array del destinatario della dimensione necessaria utilizzando la funzione ArrayResize(), ottenere i dati di mlxGetDouble(), restituire la dimensione dell'array.
    • SEla dimensione è ZERO, ritorna un errore, ovvero un valore nullo.  

Questo è tutto! Le funzioni mlGetInt() e mlGetLogical() producono la conversione "ombra" dei tipi double ->; int/bool. A tale scopo queste funzioni creano un buffer di memoria temporaneo nei loro corpi. Questa è una misura forzata, perché purtroppo l'API MATLAB non consente di creare strutture mxArray per tipi di dati diversi da double. Tuttavia, ciò non significa che MATLAB operi esclusivamente i tipi double.

Il blocco C/C++ è molto più semplice: dovrebbe fornire la traduzione dei dati dal tipo double alla struttura mxArray. Viene eseguito utilizzando le funzioni mxCreateDoubleMatrix(), mxGetPr() e memcpy(). Quindi, utilizzando la funzione engPutVariable() passa i dati alla macchina virtuale MATLAB e per estrarre i dati utilizza la funzione engGetVariable(). Ancora una volta, presta attenzione alle funzioni con prefissi Int e Logical: come visto nello schema a blocchi, non interagiscono direttamente con MATLAB, ma usano le funzioni mlxInputDouble/mlxGetDouble e mlxInputChar(). L'algoritmo del loro comportamento è semplice: chiamata della funzione mlxInputDouble/mlxGetDouble — valori di input/output come double(!) e inviare il comando MATLAB "shadow" per convertire il tipo di dati tramite la funzione mlxInputChar().

MATLAB Engine block è ancora più semplice. Fornisce solo funzioni matematiche. Il suo comportamento dipende dai tuoi comandi e dalle tue funzioni m/p.  

Ora, quando tutti i "dettagli" del progetto sono chiari, è il momento di occuparsi della costruzione del progetto.

Qualsiasi build di questo tipo inizia con la creazione della libreria principale, nel nostro caso è un blocco C/C++. A tal fine, in qualsiasi editor di testo ANSI (Notepad, Bred, ecc.) creare un file con estensione DEF. Sarebbe meglio che il nome di questo file sia composto da caratteri latini senza spazi e punteggiatura, altrimenti "sentirai" molte "parole" lusinghiere dal tuo compiler... Questo file fornisce la permanenza delle tue funzioni. Se questo file è assente, il compiler C/C++ inventerà i suoi "nomi esotici" per esportare le funzioni.

Questo file contiene: LIBRARY — parola di controllo, LibMlEngine — nome della libreria ed EXPORTS — seconda parola di controllo, quindi vengono i nomi delle funzioni. Come probabilmente saprai, i nomi delle funzioni di esportazione non possono avere spazi e punteggiatura. Ecco il testo del file DllUnit.def dall'archivio MATLABEngine.zip:  

LIBRARY LibMlEngine
EXPORTS
mlxClose
mlxInputChar
mlxInputDouble
mlxInputInt
mlxInputLogical
mlxGetDouble
mlxGetInt
mlxGetLogical
mlxGetSizeOfName
mlxOpen

Quindi, abbiamo il primo file di progetto. Ora apri Windows Explorer e vai alla cartella "<MATLAB>\Extern\include". Copia il file engine.h (file di intestazione della macchina virtuale MATLAB) nella cartella in cui viene compilato il progetto (se non lo farai, dovrai specificare manualmente il percorso del file in fase di compilazione).

Ora è il momento di creare un blocco C/C++. Non includeremo l'intero codice sorgente del programma nell'articolo, perché questo file si trova in MATLABEngine.zip come DllUnit.cpp ed è ben commentato. Si noti che è meglio creare funzioni utilizzando la convenzione __stdcall, ovvero i parametri vengono passati attraverso lo stack e la funzione pulisce lo stack. Questo standard è "nativo" per l'API Win32/64.

Considera come dichiarare una funzione:

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

  1. extern "C" __declspec(dllexport) — dice al compiler C++ che la funzione è esterna.  
  2. <variable_type> — tipo di variabile restituita, può essere: void, bool, int, double, compositi (noti non solo a Dll, ma anche al programma chiamante) e puntatori.
  3.  __stdcall — dichiarazione sul passaggio di parametri alla funzione e viceversa, è uno standard per l'API Win32/64.  
  4. Funzione: il nome della funzione.  
  5. <tipo> <nome> — tipo e nome della variabile di input, il numero massimo di variabili è 64.

Questo argomento è trattato in dettaglio nell’articolo Come Scambiare Dati: Una DLL per MQL5 in 10 minuti.

Costruzione di blocchi C/C++: per questo è necessario includere la libreria standard di input/output e aggiungere al progetto i seguenti file (nel compiler: Progetto->Aggiungi progetto):

  1. DllUnit.def
  2. Nella cartella <MATLAB>\Extern\lib\<win32/64>\<compilatore>\, dove:
    <MATLAB> — Cartella principale di MATLAB.
    <win32/64>: cartella win32 per sistema operativo a 32 bit o win64 per sistema operativo a 64 bit.
    <compiler> — la cartella "borland" per Borland C/C++ ver. 5-6, la cartella "microsoft" per Microsoft Visual C++:  
    • libeng.lib
    • libmx.lib

Potrebbe sorgere una domanda comune come questa: "Ho una versione diversa del compiler o nessun compiler di questo tipo nell'elenco! (Molto raramente non ci sono tali file)". Vediamo come creare manualmente una biblioteca pubblica. Considereremo come è fatto in Visual C++ e in Borland C++:

  1. In FAR aprire la cartella <MATLAB>\Bin\<win32/64>, dove:
    <MATLAB> — Cartella principale di MATLAB.
    <win32/64>: cartella win32 per sistema operativo a 32 bit o win64 per sistema operativo a 64 bit.  
  2. Per Borland C++immettere: implib libeng.lib libeng.dll. Lo stesso per libmx.dll.
  3. Per Visual C++immettere: lib libeng.dll. Lo stesso per libmx.dll.
  4. Se un altro compiler: qualsiasi compiler di qualsiasi linguaggio di programmazione deve avere questa utilità - Gestore Libreria, di solito questo è un programma console <cartella_compiler>\bin\*lib*.exe.

A proposito, ho dimenticato di avvertirti: non provare a creare LIB a 64 bit per il compiler a 32 bit. Innanzitutto, scopri se è disponibile il supporto per l'indirizzamento a 64 bit nella guida del compiler. In caso contrario, cercare la DLL MATLAB a 32 bit o scegliere un altro compiler C/C++. Ci avviciniamo alla compilazione, dopo di che otteniamo una libreria che dovrebbe essere collocata nella cartella terminal_folder\MQL5\Libraries.

Ora iniziamo con il blocco MQL. Esegui MetaEditor, fai clic su "Nuovo" e fai come nelle seguenti figure:  

Figura 2. MQL5 Wizard: Crea Libreria

Figura 2. MQL5 Wizard: Crea libreria

 Figura 3. MQL5 Wizard: Proprietà Generali della Libreria

Figura 3. MQL5 Wizard: Proprietà Generali della Libreria

Ora, quando MQL5 Wizard ha creato un template, procedi alla sua modifica:

1. Descrivi le funzioni di importazione:

//+------------------------------------------------------------------+
//| 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    

Nota che in MQL 5 puoi passare i "puntatori" in due modi:

  • void NameArray[]; // Questo metodo di passaggio dall'array consente solo di leggere i dati. Tuttavia, se provi a utilizzare questo riferimento per "modificare i suoi contenuti", otterrai un errore di accesso alla memoria (nel migliore dei casi per te, MetaTrader 5 gestirà silenziosamente l'errore nel frame SEH, ma NON ABBIAMO SCRITTO un SEH-frame, quindi possiamo anche perdere il motivo dell'errore).
  • void Array& Nome[]; // Questo metodo di passaggio consente di leggere e modificare il contenuto dell'array, ma è necessario mantenere la dimensione dell'array.

Se la funzione non accetta o non passa parametri, specificare sempre il tipo void.

2. Non descriveremo tutte le funzioni del blocco MQL, perché puoi trovare il codice sorgente MatlabEngine.mq5 in MATLABEngine.zip.

Pertanto, considereremo i dettagli della dichiarazione e della definizione delle funzioni esterne in MQL5:

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

Come si vede nell'esempio, la dichiarazione e la definizione di funzione sono combinate. In questo caso, dichiariamo una funzione denominata mlInputChar() come esterna (export), che restituisce un valore di tipo bool e accetta la stringa dell'arraycome parametro. Ora compila...

Ora che abbiamo completato l'ultimo blocco della libreria e compilato, è il momento di testarlo in condizioni reali.

Per fare ciò, scrivi un semplice script di test (o prendilo da MATLABEngine.zip, file: TestMLEngine.mq5).

Il codice dello script è semplice e ben commentato:

#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();
  }

Come si vede dallo script, stiamo inserendo valori e quindi otteniamo valori. Tuttavia, a differenza di MetaTrader 4, dove avevamo bisogno di conoscere la dimensione del buffer in fase di progettazione, in MetaTrader 5 non è necessario, poiché utilizziamo buffer dinamici.

Ora che hai finalmente compreso la macchina virtuale MATLAB, puoi iniziare a utilizzare la DLL integrata nell'ambiente MATLAB.

3.2 Linee guida tecniche per la creazione/utilizzo di DLL generate da MATLAB Compiler 4

Nella sezione precedente hai imparato come creare una libreria per l'interazione universale con il pacchetto MATLAB. Tuttavia, questo metodo ha uno svantaggio: richiede il pacchetto MATLAB dall'utente finale. Questa restrizione crea una serie di difficoltà nella distribuzione del prodotto software finito. Ecco perché il pacchetto matematico MATLAB ha un compiler integrato che consente di creare "applicazioni standalone" indipendenti dal pacchetto MATLAB. Diamo un'occhiata.

Ad esempio, considera un semplice indicatore: la media mobile (SMA). Aggiornalo leggermente aggiungendo un filtro di rete neurale (GRNN) che consente di attenuare il "rumore bianco" (burst casuali). Denomina il nuovo indicatore NeoSMA e filtra come GRNNFilter.  

Quindi abbiamo due funzioni m, di cui vogliamo creare una DLL, che può essere chiamata da MetaTrader 5.

Ora ricorda che MetaTrader 5 cerca le DLL nelle seguenti cartelle:

  • <terminal_dir>\MQL5\Libraries  
  • <terminal_dir>  
  • Cartella corrente
  • Cartella di sistema <dir_windows>\SYSTEM32;  
  • <windows_dir>  
  • Directory elencate nella variabile di ambiente di sistema PATH.

Pertanto, inserisci in una di queste directory due funzioni m (NeoSMA.m e GRNNFilter.m), dove creeremo la DLL. Attiro la vostra attenzione su questo fatto di collocazione, poiché ciò non avviene per caso. Il lettore attento conosce già la funzionalità del compiler MATLAB - conserva i percorsi durante la compilazione (vedi "2.2 MATLAB Compiler 4").

  Prima di iniziare a compilare il progetto, è necessario configurare il compiler. Per fare ciò, segui questi passaggi:   

  1. Nella riga di comando di MATLAB inserisci: mbuild -setup
  2. Premi 'y' per confermare la ricerca dei compiler compatibili con C/C++ installati nel tuo sistema.
  3. Scegli il compiler C Lcc-win32 standard.
  4. Premere 'y' per confermare il compiler selezionato.

Figura 4. Compilazione del progetto

Figura 4. Compilare il progetto


Ora siamo pronti per passare al processo di compilazione delle funzioni m.

Per questo inserisci:

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

Spiega le chiavi:

-N — per saltare tutti i percorsi non necessari
-W lib:NeoSMA — dice al compilatore che NeoSMA è il nome della libreria
-T link:lib — dice al compiler di creare una libreria pubblica con il collegamento
NeoSMA.m e GRNNFilter.m — nomi delle funzioni m

Ora, vediamo cosa ha creato il compilatore:

  • mccExcludedFiles.log — file di registro contenente le azioni dei compiler
  • NeoSMA.c — Versione C della libreria (contiene С-code del wrapper)  
  • NeoSMA.ctf — File CTF (vedi 2.2 MATLAB Compiler 4) sezione  
  • NeoSMA.h — file di intestazione (contiene dichiarazioni di librerie, funzioni, costanti)  
  • NeoSMA.obj — file oggetto (file sorgente contenente macchina e pseudo codice)  
  • NeoSMA.exports — nomi delle funzioni esportate  
  • NeoSMA.dll — DLL per ulteriori collegamenti  
  • NeoSMA.lib — DLL da utilizzare nei progetti C/C++  
  • NeoSMA_mcc_component_data.c — Versione C sul componente (utilizzato per la conformità con il file CTF, contiene percorsi, ecc.)  
  • NeoSMA_mcc_component_data.obj — versione oggetto del componente (file sorgente contenente macchina e pseudo codice);

Quindi gestiamo con DLL, precisamente con la sua struttura interna. Consiste di (solo funzioni di base) da:

  1. Funzione principale di qualsiasi DLL - BOOL WINAPI DllMain(), che (secondo le specifiche Microsoft) gestisce gli eventi che si verificano nella DLL: Caricamento della DLL nello spazio degli indirizzi del processo, creazione di un nuovo flusso, eliminazione del flusso e scaricamento della DLL dalla memoria.  
  2. Funzioni di servizio di inizializzazione/reinilizzazione DLL: BOOL <NameLib>Initialize(void)/void <NameLib>Terminate(void) — sono necessari per avviare/scaricare l'ambiente Math Work prima di utilizzare le funzioni di libreria e al termine del loro utilizzo.
  3. Funzioni m esportate – void mlf<NameMfile>(int <number_of_return_values>, mxArray **<return_values>, mxArray *<input_values>, ...), dove:
    • <number_of_return_values> — numero di variabili restituite (da non confondere con la dimensione dell'array, ecc.).
    • mxArray **<return_values> — indirizzo della struttura mxArray in cui verranno restituiti i risultati del lavoro della funzione m.
    • mxArray *<input_values> — puntatore alla struttura mxArray della variabile di input della funzione m.
     

Come puoi vedere, le funzioni m esportate contengono indirizzi e puntatori alla struttura mxArray e non puoi chiamare direttamente queste funzioni da MetaTrader 5, poiché non capirà questo tipo di dati. Non descriveremo la struttura mxArray in MetaTrader 5, perché gli sviluppatori MATLAB non garantiscono che non cambierà nel tempo, anche all'interno della stessa versione del prodotto, quindi è necessario scrivere un semplice adattatore DLL.

Il suo schema a blocchi è mostrato di seguito:

Figura 5. Schema a Blocchi dell'Adattatore DLL

Figura 5. Schema a Blocchi dell'Adattatore DLL

È molto simile al lato destro della DLL per MATLAB Engine, quindi non analizzeremo il suo algoritmo e procederemo direttamente al codice. Per fare ciò, crea due piccoli file nel tuo compiler C/C++:  

nSMA.cpp (from DllMatlab.zip):  

#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 (from DllMatlab.zip):

LIBRARY nnSMA
EXPORTS
IsStartSMA
nSMA


Compila il progetto nel tuo compiler C/C++: per questo devi includere la libreria standard di input/output e aggiungere al progetto i seguenti file (nel tuo compiler: Progetto->Aggiungi progetto):

  1. nSMA.def
  2. Nella cartella <MATLAB>\Extern\lib\<win32/64>\<compilatore>\, dove:
    <MATLAB> — Cartella principale di MATLAB.
    <win32/64>: cartella win32 per sistema operativo a 32 bit o win64 per sistema operativo a 64 bit.
    <compiler> — la cartella "borland" per Borland C/C++ ver. 5-6, la cartella "microsoft" per Microsoft Visual C++ (ho i file per la versione 6):  
    • libmx.lib
    • mclmcr.lib
  3. NeoSMA.lib — crea manualmente (vedi 3.1 Sviluppo della Libreria Universale di MetaTrader 5 e Interazione con MATLAB Engine).  

L'ultimo, quello che voglio dirti in questa sezione, riguarda i file necessari quando si sposta il progetto su un altro computer, dove non è installato MATLAB.

Ecco un elenco di file e percorsi sulla macchina di destinazione:

  • MCRInstaller.exe qualsiasi cartella (programma di installazione MCR)
  • extractCTF.exe qualsiasi cartella (per il programma di installazione MCR)
  • MCRRegCOMComponent.exe qualsiasi cartella (per il programma di installazione MCR)
  • unzip.exe qualsiasi cartella (per il programma di installazione MCR)
  • NeoSMA.dll                           <terminal_dir>\MQL5\Libraries
  • NeoSMA.ctf                           <terminal_dir>\MQL5\Libraries
  • nnSMA.dll                             <terminal_dir>\MQL5\Libraries

Molti programmatori esperti hanno già intuito che è consigliabile utilizzare un programma di installazione (SETUP). Ce ne sono molti su Internet, compresi i prodotti gratuiti.

Ora dobbiamo testare questa DLL in MetaTrader 5. Per farlo scriveremo un semplice script (TestDllMatlab.mq5 dal DllMatlab.zip):

#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
  }
//+------------------------------------------------------------------+

Conclusione

Quindi, sai come creare una libreria universale per l'interazione MetaTrader 5 e MATLAB e come connettere le DLL integrate nell'ambiente MATLAB. Ma ci sono ancora interfacce di interazione MetaTrader 5 e MATLAB da descrivere, ma questo va oltre lo scopo di questo articolo. L'argomento di questo articolo è trattato in dettaglio. Ho scelto le modalità di interazione più efficaci, non richiedendo particolari tipi di "adattatori". Anche se puoi andare in "un'altra strada", come la tecnologia .NET - Come esportare le quotazioni da MetaTrader 5 alle applicazioni .NET utilizzando i servizi WCF.

Molti lettori potrebbero avere una domanda: quale metodo scegliere? La risposta è semplice: entrambi, perché durante la progettazione/debug del modello matematico la velocità non è necessaria. Ma avrai bisogno della piena potenza di MATLAB senza "costi di produzione speciali" per la programmazione. MATLAB Engine ti aiuterà, ovviamente. Tuttavia, quando il modello matematico è sottoposto a debug e pronto per l'uso, avrai bisogno di velocità, multitasking (lavoro di indicatore e/o sistema di trading a diversi grafici dei prezzi) - qui senza dubbio avrai bisogno di una DLL, costruita in ambiente MATLAB .

Ma tutto questo non ti obbliga a seguirlo. Ognuno darà la risposta a questa domanda da solo, basandosi principalmente sulla proporzione del "costo di programmazione" alla scala del progetto (numero di indicatori e/o utenti del sistema di trading). Non ha senso creare DLL nell'ambiente MATLAB per uno o due utenti (è più facile installare MATLAB su due computer).  

Molti lettori che non hanno familiarità con MATLAB, probabilmente hanno una domanda: perché tutto questo? MQL5 ha già funzioni matematiche! La risposta è che l'uso di MATLAB ti consente di implementare senza sforzo le tue idee matematiche, ecco solo un elenco parziale di possibilità:  

  • algoritmo dinamico di logica fuzzy nell'indicatore e/o nel sistema di trading meccanico  
  • algoritmo genetico dinamico nel sistema di trading meccanico (tester di strategia dinamica)
  • algoritmo di rete neurale dinamica nell'indicatore e/o nel sistema di trading meccanico  
  • indicatori tridimensionali
  • simulazione di sistemi di gestione non lineari

Quindi, tutto nelle tue mani, e non dimenticare: "La matematica è sempre stata la regina delle scienze" e il pacchetto MATLAB è la tua calcolatrice scientifica.

Letteratura

  1. Guida integrata di MATLAB.
  2. Guida integrata di MQL5.
  3. Jeffrey Richter. Applicazioni di programmazione per Microsoft Windows.

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/44

File allegati |
dllmatlab_en.zip (955.7 KB)
matlabengine_en.zip (670.57 KB)
Creazione di un Indicatore con più Indicatori Buffer per Principianti Creazione di un Indicatore con più Indicatori Buffer per Principianti
I codici complessi sono costituiti da un insieme di codici semplici. Se li conosci, non sembra così complicato. In questo articolo, parleremo di come creare un indicatore con più buffer di indicatori. Ad esempio, l'indicatore Aroon viene analizzato in dettaglio e vengono presentate due diverse versioni del codice.
Creazione di un Indicatore con Opzioni di Controllo del Grafico Creazione di un Indicatore con Opzioni di Controllo del Grafico
Coloro che hanno familiarità con i sentiment del mercato conoscono l'indicatore MACD (il suo nome completo è Moving Average Convergence/Divergence) - il potente strumento per analizzare il movimento dei prezzi, utilizzato dai trader fin dai primi momenti della comparsa dei metodi di analisi del computer. In questo articolo considereremo possibili modifiche del MACD e le implementeremo in un indicatore con la possibilità di passare graficamente tra le modifiche.
MQL per "Duri di Comprendonio": Come Progettare e Costruire Classi di Oggetti MQL per "Duri di Comprendonio": Come Progettare e Costruire Classi di Oggetti
Creando un programma di esempio di visual design, dimostriamo come progettare e costruire classi in MQL5. L'articolo è scritto per i programmatori principianti che stanno lavorando su applicazioni MT5. Proponiamo una tecnologia semplice e di facile comprensione per la creazione di classi, senza la necessità di immergersi profondamente nella teoria della programmazione orientata agli oggetti.
Gestione degli Eventi in MQL5: Modifica del periodo MA al volo Gestione degli Eventi in MQL5: Modifica del periodo MA al volo
Supponiamo che un semplice indicatore MA (Media Mobile) con periodo 13 sia applicato a un grafico. E vogliamo cambiare il punto in 20, ma non vogliamo andare alla finestra di dialogo delle proprietà dell'indicatore e modificare il numero da 13 a 20: semplicemente stanchi di queste noiose azioni con mouse e tastiera. E soprattutto non vogliamo aprire il codice dell'indicatore e modificarlo. Vogliamo fare tutto questo premendo un pulsante - "frecce su" accanto al tastierino numerico. In questo articolo descriverò come farlo.