La potenza di MetaTrader 5: Dal debug passo-passo alla protezione dei file EX5 in un ambiente integrato
Introduzione
Nel mondo del trading algoritmico, un'idea di trading è solo il punto di partenza. Il vero valore di un prodotto inizia a emergere non quando viene scritta la prima riga di codice, ma durante i cicli ripetuti di perfezionamento, validazione e preparazione per l’operatività live.
Molti sviluppatori considerano ancora MetaEditor un editor di testo avanzato. Per anni, hanno utilizzato metodi di debug manuali: riempiendo i registri con migliaia di istruzioni print, trascorrendo ore a ispezionare visivamente i file di testo e cercando di indovinare le cause di slittamenti, falsi segnali o cicli bloccati. Questo approccio trasforma lo sviluppo in un processo di ricerca caotico e non sistematico in cui la risorsa più preziosa, ovvero il tempo, viene costantemente sprecata. L'affidabilità del codice in questo processo rimane incerta.
Per realizzare un sistema di trading automatizzato non bastano un ambiente di sviluppo comodo e un linguaggio di programmazione potente. Richiede inoltre strumenti per il debug e la calibrazione.
Il sistema di sviluppo e trading MetaTrader 5 offre uno standard fondamentalmente diverso. La potenza della piattaforma risiede non solo nell'espressività del linguaggio MQL5, ereditata dal C++ orientato agli oggetti, ma anche nella velocità con cui uno sviluppatore può procedere attraverso l'intero flusso di lavoro: "Individuazione dei bug → Risoluzione dei problemi → Ottimizzazione della velocità di esecuzione → Protezione dell'applicazione finale .ex5".
Al centro di questo processo si trova MetaEditor — un ambiente di sviluppo integrato (IDE) completo che copre ogni fase del ciclo di vita dello sviluppo di applicazioni MQL5. MetaEditor include strumenti specializzati per ogni fase della catena:
- Debug passo-passo tramite tick reali
- Profilazione delle prestazioni a livello hardware del tempo di esecuzione del codice
- Integrazione diretta con DLL C++ per accelerare i calcoli critici per le prestazioni.
- Protezione crittografica del codice binario basata su cloud.
Non si tratta semplicemente di una raccolta di comode funzionalità, ma di un ecosistema di sviluppo attentamente progettato che riduce i tempi di sviluppo e minimizza il rischio di fallimento nell'implementazione di idee di trading.
In questo articolo, analizzeremo l'intero ciclo di vita della creazione di un robot di trading: dalla configurazione del progetto al debug della logica del programma, dall'identificazione dei colli di bottiglia prestazionali all'isolamento dei calcoli matematici complessi in una DLL C++, fino alla protezione della proprietà intellettuale con MQL5 Cloud Protector.
A titolo di esempio pratico, svilupperemo un nostro indicatore basato sulle Bande di Bollinger, incluso nel pacchetto del terminale MetaTrader 5. Aggiungeremo la visualizzazione dei segnali, impostazioni interattive e calcoli delle prestazioni del trading virtuale. Potrete poi utilizzare questo indicatore come base per testare le vostre idee.
Figura 1: Dall'idea al profitto
Indicatore di test: Requisiti del progetto
Svilupperemo un indicatore di test per il debug e la profilazione. L'indicatore presenterà le seguenti funzionalità:
- Visualizza le frecce per il segnale di acquisto/vendita e i livelli di Stop Loss e Take Profit in punti.
- Utilizza l'indicatore standard Bollinger Bands (BB) per generare segnali
- Supporta due modalità di segnalazione: inversione dai limiti BB superiore/inferiore e breakout dei limiti BB.
Modalità Inversione:
- Se la barra chiude al di sopra del limite superiore delle BB, genera un segnale di vendita, imposta il Take Profit sulla linea mediana delle BB e lo Stop Loss alla stessa distanza del Take Profit.
- Se la barra chiude al di sotto del limite inferiore delle BB, genera un segnale di acquisto, imposta il Take Profit sulla linea mediana delle BB e lo Stop Loss alla stessa distanza del Take Profit.
Modalità Breakout:
- Inverte i segnali Buy e Sell e scambia i livelli di Take Profit e Stop Loss.
Può rimanere attivo un solo segnale di entrata finchè non viene raggiunto il Take o lo Stop. Dopodiché, il ciclo di tracciamento del segnale e di visualizzazione delle frecce ricomincia.
Se alla chiusura della barra compare un segnale opposto, la posizione dovrebbe invertirsi.
Condizioni pratiche aggiuntive:
- Saltate le prime ore di una nuova giornata di trading (numero di ore configurabile)
- Non effettuate operazioni di trading durante l'ultima ora prima della chiusura del mercato.
- Chiudete tutte le posizioni al termine della giornata di trading (l'orario di chiusura è configurabile).
Visualizzazione dei segnali sul grafico:
- Buy — freccia verde verso l'alto
- Sell — freccia rossa verso il basso
- Stop — croce gialla
- Take — croce blu
Il risultato dell'operazione dell'indicatore è mostrato di seguito:
Figura 2: Segnali indicatore di test
Il codice sorgente completo dell'indicatore è disponibile nel file BB_Signal_Indicator.mq5 allegato a questo articolo.
Impostazione del progetto: Le basi dello sviluppo e del debug
Cominciamo dalle basi - una corretta organizzazione del progetto. Preparare l'ambiente di sviluppo in anticipo consente di risparmiare molto tempo, ancor prima di eseguire il primo test.
Qualsiasi progetto serio non inizia con la scrittura del codice, ma con la creazione del giusto ambiente per quel codice. MetaEditor, in quanto IDE completo, offre strumenti per automatizzare le attività di routine, consentendo agli sviluppatori di concentrarsi sulla logica anziché sulle impostazioni e configurazioni dei grafici. Analizziamo le componenti chiave che costituiscono la base di uno sviluppo efficiente.
Creazione di un progetto: Da un singolo file a un sistema
Lavorare con singoli file .mq5 è accettabile durante la fase di prototipazione, ma per uno sviluppo serio è necessario un progetto.
Un progetto è un file separato con estensione .mqproj che memorizza le impostazioni del programma, i parametri di compilazione e le informazioni su tutti i file correlati. Per una gestione più agevole del progetto, nel Navigatore è disponibile una scheda dedicata. Tutti i file, come include, resource, header e altri file sono organizzati in categorie in questa scheda.
Come creare un progetto da un file sorgente:
- Nella finestra Navigatore, selezionare il file MQ5 esistente (BB_Signal_Indicator.mq5 nel nostro caso).
- Fare clic con il pulsante destro del mouse e scegliere "Nuovo progetto da sorgente" dal menu contestuale.
Nella stessa directory verrà creato automaticamente un file .mqproj:
Figura 3: Creazione di un progetto da un file sorgente
Cosa offre un progetto:
- Gestione centralizzata di tutti i file di programma
- Tracciamento automatico delle dipendenze (#include, #resource)
- Impostazioni di compilazione separate, indipendenti dal codice sorgente
- Controllo delle versioni e tracciamento delle modifiche.
La procedura guidata consente anche di creare progetti vuoti. Questa è una funzionalità utile per progetti di sviluppo non standard con strutture di file specifiche per le quali i modelli predefiniti non sono adatti. In questo caso, viene creato solo un file di configurazione .mqproj vuoto. I file sorgente dovranno essere aggiunti manualmente in seguito.
Note
- Se il progetto viene creato a partire da un file sorgente esistente, il nome del progetto viene ereditato da tale file. Se create un nuovo progetto, vi verrà richiesto di specificarne manualmente il nome.
- Si raccomanda inoltre di creare una directory dedicata per archiviare tutti i file e le cartelle del progetto.
Caratteristiche del progetto: Configurazione centralizzata
Le impostazioni del progetto sono accessibili tramite il menu contestuale del progetto, nella sezione Proprietà. Questa finestra di dialogo sostituisce la modifica manuale delle direttive #property nel codice sorgente.
Figura 4: Proprietà del progetto
Caratteristiche principali:
- Tipo di programma - definisce il tipo di modulo eseguibile generato durante la compilazione.
- Progetto CPU - consente di selezionare il set di istruzioni standard (X64 Regular) o i set di istruzioni estesi della CPU utilizzati durante la compilazione.
- Copyright — informazioni sul copyright, equivalenti a #property copyright nel codice sorgente.
- Link — un collegamento al sito web dello sviluppatore, equivalente a #property link nel codice sorgente.
- Versione — versione del programma, equivalente a #property version nel codice sorgente.
- Icona — icona del programma, equivalente a #property icon nel codice sorgente.
- Descrizione — descrizione del programma, equivalente a #property description.
Impostazioni di ottimizzazione e prestazioni:
- Massima ottimizzazione - le applicazioni compilate senza ottimizzazione vengono create più velocemente, ma l'esecuzione risulta più lenta. Se necessario, disattivare l'ottimizzazione durante il debug, ma abilitarla per le build di rilascio.
- Verifica dei divisori in virgola mobile - la disabilitazione dei controlli dei divisori migliora leggermente le prestazioni perché gli errori di divisione per zero non vengono più verificati durante l'esecuzione di runtime.
- Utilizzare la cache di ottimizzazione (per Expert Advisor) - durante l'ottimizzazione, lo Strategy Tester memorizza i risultati in una cache. I risultati vengono salvati per ogni set di input. Rieseguire l'ottimizzazione con parametri identici consente a MetaTrader 5 di riutilizzare i risultati memorizzati nella cache anziché ricalcolarli. L'eccezione è rappresentata dai calcoli matematici, per i quali potrebbe essere necessario eseguire un nuovo calcolo indipendentemente dalle voci già presenti nella cache. In questi casi, disabilitare l'opzione "Usa cache di ottimizzazione" nelle impostazioni del progetto. Anche quando la cache è disabilitata, i risultati dei test vengono comunque memorizzati in modo che tutte le prove completate rimangano disponibili nei report dello Strategy Tester.
Proprietà dell'indicatore:
- Calcola l'indicatore ad ogni tick nel tester - forza gli indicatori ad essere calcolati ad ogni tick in arrivo. Questa opzione influisce solo sulle operazioni nello Strategy Tester. Nell'ambiente della piattaforma live, gli indicatori vengono sempre ricalcolati ad ogni tick.
Tuttavia, durante il test di un Expert Advisor che utilizza indicatori, lo Strategy Tester calcola i valori degli indicatori solo quando l'EA richiede esplicitamente i dati del buffer degli indicatori. Ciò velocizza notevolmente i test e l'ottimizzazione quando l'Expert Advisor non necessita dei valori degli indicatori a ogni tick. Se il tuo indicatore richiede calcoli a ogni tick, abilita questa opzione.
Gli indicatori vengono inoltre ricalcolati forzatamente ad ogni tick nei seguenti casi:
- La modalità di test visivo è abilitata
- L'indicatore utilizza EventChartCustom(), OnChartEvent() o OnTimer()
- L'indicatore è stato compilato con una versione precedente alla 1916
Nota
Le proprietà del progetto hanno sempre la precedenza sulle proprietà specificate nel codice sorgente. Se le impostazioni sono definite sia nel progetto che nel codice sorgente (anche con valori diversi), verranno utilizzate le impostazioni del progetto.
Gestione dei file di progetto nel Navigatore
Aggiunta automatica dei file:
- I file inclusi tramite #include vengono visualizzati automaticamente in Dipendenze nel Navigatore
- I file di intestazione appaiono nella scheda Headers
- Le risorse (immagini, suoni, ecc.) incluse tramite #resource vengono visualizzate nella sezione Resources.
- I file sorgente MQ5 compaiono nella sezione Sources.
Aggiunta manuale del file:
-
È inoltre possibile aggiungere i file manualmente utilizzando il menu contestuale del progetto, tramite le opzioni "Aggiungere un file esistente" o "Aggiungere una cartella esistente". Il comando "Aggiungi una cartella esistente" consente di aggiungere in blocco tutti i file supportati da una directory selezionata al progetto.
Figura 5: Aggiunta manuale dei file
Nota
Quando un file viene aggiunto manualmente, non viene incluso automaticamente nel codice del programma e non viene copiato nella directory del progetto. Il file è semplicemente collegato al progetto in modo che appaia nel navigatore del progetto.
È possibile rimuovere i file tramite il menu contestuale del progetto selezionando Elimina sul file desiderato. Quando si elimina un file dal progetto, il sistema offre due opzioni:
- Rimuovi — esclude il file dal progetto mantenendolo sul disco.
- Elimina — rimuove completamente il file sia dal progetto che dal disco rigido.
Fai attenzione quando elimini i file. La rimozione accidentale di un file sorgente può comportare la perdita permanente del codice.
Sezioni aggiuntive:
- Settings and files - questa sezione può essere utilizzata per aggiungere file ausiliari come configurazioni di test o modelli di grafici.
Utilizzo del modello debug.tpl
Molti sviluppatori trascurano il file denominato debug.tpl che si trova nella directory del terminale \profiles\templates. Si tratta di un'importante occasione persa che riduce l'efficienza dello sviluppo e dei test. Ecco come funziona: quando si avvia il debug (tasto F5), MetaEditor crea un grafico temporaneo nel terminale di MetaTrader 5. Se nella cartella dei modelli è presente un file debug.tpl, il terminale applica automaticamente le sue impostazioni a quel grafico.
Il vantaggio pratico è che è possibile preconfigurare questo modello con tutti gli indicatori, i livelli, le impostazioni della griglia e le proprietà del grafico necessari. Ad esempio, se il tuo robot effettua operazioni di trading utilizzando le Bollinger Bands, è sufficiente aggiungere l'indicatore al modello. Ogni volta che si avvia il debug, il grafico sarà già completamente configurato e includerà l'indicatore, eliminando la necessità di impostazioni manuali.
Poiché la pressione del tasto F5 durante il debug è un'operazione frequente durante tutto lo sviluppo, questo semplifica notevolmente il flusso di lavoro.
Preconfigurazione dell'ambiente di debug
Le impostazioni dell'ambiente di debug si trovano in MetaEditor al seguente percorso: "Strumenti → Opzioni → Debug/Profilo". Configura i parametri predefiniti che verranno utilizzati ogni volta che viene avviato il debugger.
Figura 6: Impostazioni dell'ambiente di debug
Principali impostazioni di debug e profilazione:
- Simbolo - specifica lo strumento di trading per cui è progettata la vostra applicazione (ad esempio, EURUSD) e il timeframe utilizzato dalla strategia (ad esempio, H1 per i sistemi a medio termine).
- Data - durante il debug dei dati storici, è possibile definire immediatamente l'intervallo di tempo desiderato. I test visivi nello Strategy Tester verranno eseguiti a questo intervallo.
- Abilita l'ottimizzazione durante la profilazione - quando si cercano i colli di bottiglia, disabilitare l'ottimizzazione per vedere chiaramente quali righe di codice consumano la maggior parte del tempo di esecuzione. Tenete presente che le metriche prestazionali risultanti saranno diverse da quelli delle build di rilascio; per i benchmark finali, riattivate l'ottimizzazione.
- Abilita l'inlining durante la profilazione - con l'inlining abilitato, il codice della funzione viene inserito direttamente nel punto di chiamata, migliorando significativamente la velocità di esecuzione. Tuttavia, ciò complica la profilazione funzionale. Per ottenere report di profilazione più precisi, disabilitare l'inlining.
- Utilizza la modalità visiva per il debug dei dati storici - per impostazione predefinita, il debug dei dati storici viene eseguito in modalità non visuale all'interno dello Strategy Tester, ma questa opzione consente di abilitare manualmente la modalità visiva. La profilazione basata su dati storici viene sempre effettuata in modalità non visiva.
La profilazione dei dati storici in modalità visiva è generalmente inutile perché la maggior parte delle risorse di sistema viene impiegata per il rendering dei grafici anziché per l'esecuzione della logica MQL. Per testare le funzionalità grafiche (pannelli, oggetti, interfacce, ecc.), la modalità in tempo reale è solitamente sufficiente, poiché il programma viene eseguito direttamente su un normale grafico.
- Utilizzare impostazioni specificate - abilita o disabilita determinate impostazioni per il debug e la profilazione. Quando abilitata, il programma viene avviato utilizzando il simbolo e il timeframe selezionati. Anche il debug su dati storici utilizza questi parametri per i test visivi. Se disabilitati, i campi sottostanti non saranno modificabili.
Se nella scheda Debug/Profilo non viene specificato alcun simbolo o timeframe, MetaEditor utilizza per impostazione predefinita il primo simbolo nella finestra Market Watch e il timeframe H1.
Compilazione: Errori e avvisi
Premendo F7 il codice sorgente viene compilato in un file eseguibile .ex5. Durante la compilazione, la scheda Strumenti/Errori di MetaEditor può visualizzare due tipi di messaggi:
- Errori - problemi critici che impediscono la creazione del file .ex5.
- Avvisi - sezioni di codice che potrebbero potenzialmente causare problemi in fase di esecuzione (ad esempio, l'utilizzo di una variabile non inizializzata). Il file .ex5 viene comunque generato, ma vengono emessi degli avvisi.
Gli avvisi non vanno ignorati. La prassi migliore quando si lavora con MetaEditor è considerare il codice pronto per il test solo quando il numero di avvisi è pari a zero (e naturalmente, anche il numero di errori è pari a zero). I flag di compilazione nelle impostazioni di progetto possono imporre questa disciplina trattando gli avvisi come errori, obbligando gli sviluppatori a eliminare le ambiguità del codice prima dell'esecuzione.
Una volta che tutti i file di progetto sono organizzati correttamente, le impostazioni di debug e profilazione sono configurate, i modelli sono preparati e il compilatore produce una build pulita senza errori o avvisi, è il momento di passare alla fase più importante: identificare e correggere gli errori logici utilizzando il debugger integrato.
Procedura di debug passo passo: Esaminate il vostro codice al microscopio
Nella fase precedente, abbiamo creato la struttura del progetto e aggiunto tutti i file necessari, ma la logica dell'algoritmo esiste ancora solo in teoria. La funzionalità di debug passo-passo di MetaEditor consente di esaminare un programma in esecuzione, metterlo in pausa in qualsiasi momento e ispezionare lo stato corrente e i valori delle variabili. Vediamo come utilizzare il debugger integrato per testare la logica di un programma MQL5.
MetaEditor supporta due modalità di debug: debug in tempo reale e debug su dati storici. La sua flessibilità deriva dalla profonda integrazione sia con il terminale di trading che con lo Strategy Tester. Ogni modalità risolve compiti diversi:
1. Debug sui dati in tempo reale
Questa modalità si attiva premendo F5 su un grafico dedicato nel terminale MetaTrader 5, che riceve i tick in tempo reale dal server del broker. Il grafico si apre automaticamente utilizzando le impostazioni del modello debug.tpl. Questa modalità è ideale per testare le reazioni di robot o indicatori agli eventi di mercato in tempo reale, verificare la gestione degli eventi dell'interfaccia (OnChartEvent) o testare gli eventi del timer (OnTimer).
In sostanza, si tratta del programma in esecuzione live. Si osserva in tempo reale come il codice reagisce ai tick in arrivo. Tuttavia, c'è uno svantaggio: la velocità di debug è limitata dalla velocità effettiva dei tick di mercato in arrivo.
Quando un Expert Advisor viene avviato in questa modalità, la parola "Debug" appare accanto al suo nome nell'angolo in alto a destra del grafico, ad indicare che il grafico è in modalità di debug.
2. Debug sui dati storici
Questa modalità si avvia utilizzando Ctrl+F5 all'interno dello Strategy Tester. I dati storici salvati vengono inseriti sequenzialmente nell'Expert Advisor o nell'indicatore, riproducendo la cronologia del mercato nell'intervallo selezionato. Questa è la modalità principale per la convalida della logica di trading. Consente di eseguire algoritmi su anni di dati storici in pochi minuti e di rilevare situazioni rare (come il comportamento dei gap o eventi di alta volatilità).
Le impostazioni di MetaEditor consentono anche di abilitare la modalità visiva per visualizzare il grafico durante il debug, utilizzando l'opzione "Usa la modalità visiva per il debug sui dati storici" che si trova nella scheda Debug/Profilo.
Breakpoints - fermati e pensa
L'elemento centrale del debug è il punto di interruzione (Breakpoint). Un breakpoint è un indicatore posizionato su una riga di codice sorgente che istruisce MetaEditor/MetaTrader 5 a sospendere l'esecuzione quando tale riga viene raggiunta. È possibile attivare o disattivare i breakpoint facendo doppio clic sul margine grigio accanto al numero di riga oppure premendo F9 con il cursore sulla riga desiderata.
Perché utilizzare i breakpoint? Anziché cercare di indovinare in seguito dove e perché si è verificato un errore, è possibile esaminare in modo proattivo le sezioni critiche del codice (come i calcoli delle dimensioni dei lotti o la generazione dei segnali di trading). L'esecuzione si interrompe prima che venga eseguita la riga contrassegnata, consentendo di esaminare le variabili di input e i valori intermedi, leggere il contenuto delle stringhe, ecc. In altre parole, è possibile verificare se le variabili contengono effettivamente i valori previsti.
Navigazione del codice — Esecuzione passo-passo
Una volta messa in pausa l'esecuzione, lo sviluppatore ottiene un controllo pressoché completo sul programma. L'unica cosa che non si può fare è modificare il codice al volo. MetaEditor fornisce tre comandi principali per l'esecuzione passo-passo:
- Passo dentro — premendo F11. Esegue una riga di codice. Se la riga contiene una chiamata di funzione, il debugger entra in quella funzione e si ferma alla sua prima riga. È quindi possibile continuare a eseguire il corpo della funzione riga per riga premendo F10 o F11.
- Passo oltre — premendo F10. Esegue una riga di codice. Se la riga contiene una chiamata di funzione, il debugger esegue l'intera funzione senza entrarvi e si ferma alla riga successiva.
- Passo fuori — premendo Maiusc+F11. Esegue la parte rimanente della funzione corrente e si mette in pausa immediatamente dopo essere tornata al codice chiamante.
Strumenti di analisi del codice — i call stack e finestra di monitoraggio.
La semplice sospensione dell'esecuzione non è sufficiente. È inoltre necessario comprendere lo stato attuale del programma. Questa operazione viene gestita tramite la scheda Strumenti\Debug.
Figura 7: Strumenti di analisi del codice
I call stack (finestra call stack nella Figura 7) visualizzano la cronologia di esecuzione del programma. Mostra la sequenza di file e funzioni che ha portato al breakpoint corrente. La prima voce del call stack rappresenta la funzione attualmente in esecuzione. Nella Figura 7, si tratta della funzione OnCalculate(). La voce in basso rappresenta il punto di ingresso. Nella Figura 7, si tratta ancora una volta della funzione OnCalculate() - in questo caso coincidono. La prima colonna nell'elenco dei call stack visualizza il nome del file, mentre l'ultima colonna visualizza il numero di riga.
Facendo doppio clic su una qualsiasi funzione nel call stack, il cursore dell'editor si sposta istantaneamente sulla riga in cui è stata chiamata quella funzione. Questo è indispensabile quando si analizzano programmi complessi con chiamate di funzione profondamente annidate.
La finestra di monitoraggio (la finestra di monitoraggio nella Figura 5) consente il monitoraggio in tempo reale dei valori delle variabili. Per aggiungere una variabile alla Watch List, selezionare la variabile nel codice e premere Maiusc+F9 (oppure scegliere Aggiungi al monitoraggio dal menu contestuale); la variabile verrà quindi aggiunta all'elenco. Dopo ogni passaggio di esecuzione (F10 o F11), le variabili monitorate vengono aggiornate. I valori modificati sono evidenziati per comodità.
Oltre ai valori e ai nomi, la finestra di monitoraggio visualizza anche i tipi di variabile. Per gli array, l'elenco fornisce la dimensione e l'attributo della serie temporale (Series), se specificato.
È possibile inserire espressioni semplici come a+b direttamente nella watchlist e visualizzare immediatamente il risultato senza modificare il codice sorgente. Gli elenchi espandibili consentono di visualizzare il contenuto di strutture e array.
Il debugger integrato in MetaEditor trasforma il debug in un processo analitico strutturato. È possibile controllare il tempo (esecuzione su dati storici o in tempo reale), gestire lo spazio (tramite i call stack) e visualizzare lo stato (tramite l'ispezione delle variabili). Questo rende molto più rapida l'individuazione e la correzione degli errori logici nei programmi.
Ma una volta che il programma funziona correttamente, sorge un'altra domanda: È abbastanza veloce? Se il codice funziona ma le prestazioni sono scarse, il prossimo strumento nell'arsenale di MetaEditor diventa essenziale: il Profiler.
Individuare i colli di bottiglia con il Profiler, ovvero come migliorare le prestazioni del programma.
Nella maggior parte dei casi, i problemi di prestazioni sono causati da un codice inefficiente. È qui che il Profiler diventa prezioso - uno strumento che misura il tempo di esecuzione di ogni funzione e persino delle singole righe di codice.
Prima di analizzare la velocità di esecuzione, assicurarsi che le ottimizzazioni del compilatore siano disabilitate. In MetaEditor, aprire Strumenti/Opzioni e andare alla scheda Debug/Profilo. Perché è importante? Per impostazione predefinita, il compilatore ottimizza il codice: rimuove le variabili non necessarie, unisce gruppi di operazioni e applica l'inlining delle funzioni.
Se la profilazione è abilitata per il codice ottimizzato, i risultati diventano difficili da interpretare perché la struttura e la sequenza di esecuzione effettive non corrispondono più a ciò che si vede nell'editor. Il profiler dovrebbe funzionare con codice "onesto".
Profilazione su dati in tempo reale
Per i programmi che operano in tempo reale, la velocità di esecuzione è di fondamentale importanza. MetaEditor offre un modo pratico per valutare il costo di esecuzione di diverse sezioni di codice. Per fare ciò, avviare la profilazione del codice e lasciare che il programma venga eseguito per un certo periodo di tempo. Per la profilazione degli indicatori, di solito bastano pochi minuti.
La profilazione viene avviata su un grafico speciale tramite il menu di MetaEditor: Debug/Avvia la profilazione su dati reali. Questo strumento può essere utilizzato per valutare la reattività dell'interfaccia o l'elaborazione dei tick in entrata.
Note
- Dopo l'avvio, lasciare che il robot funzioni per un tempo sufficiente affinché vengano eseguite tutte le funzioni critiche: inizializzazione, calcoli degli indicatori, operazioni di trading. Se una funzione non viene mai chiamata, non comparirà nel report.
-
Per la massima precisione, si consiglia di non interrompere il debug premendo Stop (Maiusc+F5). In alternativa, rimuovi l'Expert Advisor o l'indicatore direttamente dal grafico. Ciò garantisce la corretta chiusura di tutti i processi e assicura che le statistiche di profilazione vengano salvate correttamente.
Profilazione basata sui dati storici
La profilazione su dati storici viene avviata tramite il comando del menu in MetaEditor: Debug/Avvia la profilazione sui dati storici. In questa modalità, la profilazione viene eseguita all'interno dello Strategy Tester. Questa è la modalità principale per individuare i colli di bottiglia perché consente di testare il programma su ampi intervalli storici in tempi molto rapidi.
Analisi dei risultati
Al termine della profilazione, i risultati vengono visualizzati nella scheda Strumenti/Profiler. Per ogni funzione vengono visualizzati due parametri chiave:
- Attività totale della CPU - mostra la percentuale di tempo che una funzione trascorre all'interno dello stack delle chiamate. Ciò include l'esecuzione della funzione stessa e il tempo trascorso all'interno di tutte le funzioni che essa richiama.
- Attività CPU Individuale - mostra la percentuale di tempo trascorso nell'esecuzione dei soli comandi all'interno della funzione stessa, escludendo le chiamate annidate.
Figura 8: Risultati della profilazione in tempo reale - funzioni per chiamate
Interpretazione dei risultati della profilazione
Esaminiamo la Figura 8. Le tre funzioni contrassegnate dalle frecce verdi mostrano i livelli di attività più elevati. Si tratta di gestori di eventi (identificati dall'icona f→) utilizzati dall'indicatore. Questi sono OnInit(), OnDeinit(), OnCalculate(). Le prime due funzioni presentano valori prossimi allo zero sia per l'Attività Totale che per l'Attività Individuale. Questo è prevedibile, poiché vengono eseguite solo durante l'inizializzazione e durante lo spegnimento. Svolgono compiti relativamente semplici:
- OnInit() configura i buffer degli indicatori e crea un handle per l'indicatore standard delle Bollinger Bands;
- OnDeinit() — rilascia l'handle delle Bollinger Bands e cancella la stringa dei commenti.
La terza funzione OnCalculate() mostra Attività Totale = 99,9%. Anche questo è previsto. Una volta completata con successo la funzione OnInit(), l'indicatore impiega quasi tutta la sua durata a elaborare i tick in arrivo, quindi il tempo di elaborazione è dedicato a questa funzione.
Tuttavia, nonostante la sua Attività Totale estremamente elevata, OnCalculate() ha un'Attività Individuale molto bassa, pari allo 0,23%. Questo ci indica che la funzione in sé è veloce, ma internamente ne richiama un'altra, molto più lenta. Quindi, se è necessaria l'ottimizzazione, non dovremmo ottimizzare OnCalculate() in sé, ma qualsiasi cosa essa chiami.
Per approfondire l'analisi, passare alla visualizzazione "Funzioni per Righe" del profiler:
Figura 9: Risultati della profilazione in tempo reale - Funzioni per Righe
Come si può osservare nella Figura 9, la riga con l'Attività Totale più elevata contiene tre chiamate alla funzione standard di copia del buffer degli indicatori: CopyBuffer(...). Si tratta di una funzione a livello di sistema. Di per sé è veloce, ma internamente richiama funzioni kernel terminali. Non possiamo ottimizzare l'implementazione interna del terminale, ma possiamo ridurre la quantità di dati trasferiti (barre). Nel nostro caso, tuttavia, il processo è già ottimizzato perché vengono copiate solo le barre non elaborate più recenti.
Di conseguenza, possiamo concludere che il nostro semplice indicatore è già implementato in modo piuttosto efficiente.
Esportazione dei dati
Per ulteriori analisi, i risultati della profilazione possono essere esportati nei formati Open XML (Excel), HTML o CSV. Questo è utile per confrontare le prestazioni di diverse versioni di algoritmi o per mantenere uno storico delle ottimizzazioni di progetto.
Ma cosa succede se si individua un collo di bottiglia nel programma che non può più essere ottimizzato utilizzando solo MQL5? Ad esempio, cosa succederebbe se calcoli statistici complessi o operazioni crittografiche richiedessero ancora troppo tempo anche dopo un'ottimizzazione approfondita? In tal caso, è necessario uscire dalla "sandbox" di MetaEditor. Vediamo come la potenza del C++ può essere integrata direttamente in un progetto MQL5.
Integrazione C++: Quando MQL5 lascia spazio al codice nativo
MQL5 consente di spostare i componenti critici per le prestazioni in librerie dinamiche (DLL) scritte in C++. Ove necessario, è possibile spostare le parti critiche per le prestazioni in codice C++ nativo per ottenere una maggiore velocità di esecuzione. È proprio qui che MetaEditor dimostra la sua unicità come ambiente di sviluppo, eliminando di fatto la barriera tra i linguaggi di programmazione.
La migrazione al C++ non dovrebbe diventare un fine a sé stessa. Si tratta di un compromesso tra complessità della manutenzione e velocità di esecuzione. Utilizza questo approccio se:
- Il profiler mostra che una funzione consuma una quantità sproporzionata di risorse della CPU e non può essere semplificata algoritmicamente.
- È necessario utilizzare soluzioni già pronte (ad esempio, librerie di apprendimento automatico o pacchetti matematici specializzati) che non hanno equivalenti in MQL5.
Miglioriamo il nostro indicatore sperimentale aggiungendo il calcolo e la visualizzazione delle statistiche di trading virtuali. La data di inizio dei calcoli verrà specificata tramite i parametri di input dell'indicatore. Di seguito è riportata la versione aggiornata dell'indicatore:
Figura 10: Indicatore di test con calcoli statistici
Il codice sorgente completo è disponibile nel file BB_Signal_Stat_Indicator_V2.mq5 allegato a questo articolo.
Ora analizziamo l'indicatore con il profiler:
Figura 11: Profilazione dell'indicatore mediante calcoli statistici storici
È apparsa una nuova funzione statistica: CalculateVirtualStats(). Supponiamo di decidere di spostarla in una DLL per future espansioni e calcoli più avanzati nelle versioni commerciali dell'applicazione. In questo caso, l'aggiornamento del motore statistico richiede solo la sostituzione della libreria DLL, senza la necessità di ricompilare l'intero progetto.
MetaEditor come editor C++
Molti sviluppatori non si rendono conto che MetaEditor non è limitato a MQL. Può funzionare con file sorgente C++ (.cpp e .h) con la stessa facilità con cui funziona con i file .mq5. Come creare una libreria all'interno di MetaEditor:
- Crea un file .cpp all'interno della cartella del vostro progetto (ad esempio, nella sezione Libraries).
- Scrivete il codice della funzione. È importante utilizzare la convenzione di chiamata __stdcall o __cdecl affinché MQL5 possa interagire correttamente con la libreria.
- Premete F7 (Compila). MetaEditor richiama automaticamente un compilatore esterno e crea il file DLL. Per la compilazione C++, MetaEditor utilizza Microsoft Visual Studio installato sul computer (Visual Studio 2008 o versioni successive, incluse le edizioni Express e Community).
L'architettura di Visual Studio deve corrispondere all'architettura dell'installazione di MetaEditor, il che significa che è necessaria la versione a 64 bit di Microsoft Visual Studio. MetaTrader 5 e MetaEditor supportano solo sistemi operativi Windows a 64 bit.
Per importare funzioni da una DLL nel codice MQL5, utilizzare la seguente dichiarazione:
//+------------------------------------------------------------------+ //| Import function from DLL | //+------------------------------------------------------------------+ #import "StatsCalculator.dll" void CalculateStatsDLL(const TradeRecord &p_history[],int p_trade_count,double initial_balance,VStatResult &res); #import
Qui viene importata una singola funzione: CalculateStatsDLL(). Questa funzione calcola le statistiche di trading utilizzando le transazioni virtuali fornite. I risultati vengono restituiti tramite la struttura VStatResult &res, che viene popolata internamente all'interno della DLL.
All'interno del codice dell'indicatore, la funzione statistica originale deve essere sostituita con:
//+------------------------------------------------------------------+ //| Wrapper for DLL function call | //+------------------------------------------------------------------+ void CalculateVirtualStats(const TradeRecord &p_history[],int p_trade_count,double initial_balance,VStatResult &res) { //--- validate trade count (comparing arrays with NULL is prohibited in MQL5) if(p_trade_count<=0) return; CalculateStatsDLL(p_history,p_trade_count,initial_balance,res); }
Un controllo aggiuntivo garantisce che l'array delle transazioni non sia vuoto, fornendo una protezione extra contro gli errori di runtime. Il codice sorgente completo dell'indicatore, che utilizza l'implementazione DLL, è disponibile nel file BB_Signal_Stat_Indicator_DLL.mq5 allegato a questo articolo.
Una volta che l'algoritmo è stato sottoposto a debug, le prestazioni sono state ottimizzate e i componenti critici sono stati spostati in C++, inizia la fase finale - la protezione del prodotto finito. Nel trading algoritmico commerciale, il codice sorgente della strategia rappresenta l'asset principale.
Protezione del file EX5 finale: Uno scudo dal cloud per la proprietà intellettuale
Sebbene il formato eseguibile EX5 sia già altamente resistente alla decompilazione, la distribuzione commerciale richiede ulteriori garanzie. È qui che entra in gioco il servizio MQL5 Cloud Protector. Offre un livello di protezione ancora più elevato.
Come funziona la protezione: Crittografia senza compromessi
Molti sviluppatori sono cauti nei confronti dei servizi di protezione basati sul cloud perché temono la fuga di codice sorgente. MQL5 Cloud Protector è stato progettato specificamente per eliminare completamente questi rischi.
- Compilazione locale: Il programma viene innanzitutto compilato in un file EX4/EX5 sul computer locale dell'utente. La protezione aggiuntiva viene applicata solo al file eseguibile compilato - il codice sorgente non viene mai trasmesso a terzi.
- Trasmissione di soli dati binari: Solo la parte eseguibile del file viene inviata tramite una connessione sicura al servizio online, dove viene crittografata utilizzando moderni algoritmi asimmetrici e firmata con una chiave privata univoca.
- Compilazione e crittografia native: Lato server, viene applicata la crittografia asimmetrica moderna. Il codice viene trasformato in codice macchina nativo, lo stesso tipo di protezione utilizzato nel Market di MetaTrader. L'unica differenza è che il file risultante non è legato a un computer specifico. Può essere eseguito su qualsiasi macchina, proprio come una normale applicazione EX4/EX5.
Questo livello di protezione rende praticamente impossibile il reverse engineering e la modifica del programma EX5.
Integrazione della protezione nell'eseguibile: Lo standard commerciale
Per creare un eseguibile con protezione aggiuntiva, aprite il progetto o il file sorgente MQL principale ed eseguite Strumenti → MQL5 Cloud Protector. Questo avvia una sequenza automatica di compilazione ed elaborazione nel cloud. Il file eseguibile finale viene creato nella stessa directory del progetto o del file sorgente principale MQ5.
Figura 12: Integrazione della protezione nell'eseguibile
MQL5 Cloud Protector risolve tre problemi principali relativi alla distribuzione commerciale:
- Prevenire la decompilazione
- Distribuzione flessibile
- Preservare e persino migliorare le prestazioni - a differenza delle tecniche di offuscamento, la compilazione cloud-native mantiene o migliora la velocità di esecuzione attraverso l'ottimizzazione a livello di istruzioni macchina.
La protezione del file eseguibile finale rappresenta la conclusione logica del ciclo di sviluppo descritto all'inizio di questo articolo. Con MQL5 Cloud Protector, il vostro prodotto si evolve da prototipo a soluzione commerciale sicura, pronta per la scalabilità.
Conclusioni
Nel trading algoritmico moderno, dove la competizione si misura in millisecondi e il costo di un errore può equivalere all'intero deposito, la qualità dello sviluppo dipende dalla sofisticatezza degli strumenti padroneggiati dal programmatore e dal trader algoritmico. Abbiamo analizzato l'intero ciclo di vita di un'applicazione MQL5: dall'idea iniziale alla protezione crittografica finale del prodotto finito.
La conclusione fondamentale è chiara: MetaEditor è un argomento altrettanto valido per scegliere MetaTrader 5 quanto il linguaggio MQL5 stesso. Un linguaggio di programmazione definisce cosa si può costruire. Un ambiente di sviluppo definisce la velocità, l'affidabilità e l'efficienza con cui può essere costruito. MetaEditor apporta struttura e disciplina al processo di programmazione:
- Il debugger integrato sostituisce infinite ipotesi e analisi dei log con un'ispezione precisa degli stack di chiamata e degli stati/valori delle variabili.
- Il profiler fornisce metriche di prestazione oggettive, sostituendo le impressioni soggettive con dati numerici.
- L'integrazione con C++ tramite DLL elimina le limitazioni di un linguaggio di alto livello per le attività che richiedono un'elevata potenza di calcolo.
- MQL5 Cloud Protector risolve il problema della protezione della proprietà intellettuale, rendendo la distribuzione commerciale degli algoritmi sicura e legittima.
Uno sviluppatore che padroneggia tutti questi strumenti accorcia i tempi che intercorrono tra l'idea e la sua implementazione, ottenendo un significativo vantaggio competitivo. L'intero flusso di lavoro viene gestito tramite un'unica interfaccia MetaEditor.
Materiali consigliati per imparare MetaEditor e MetaTrader 5:
- Argomenti della Guida di MetaEditor: Debug, Profiling, C++ DLL e Cloud Protector.
- Articolo: Come sviluppare e debuggare rapidamente una strategia di trading (in Inglese)
Elenco degli allegati:
| Nome del File | Descrizione |
|---|---|
| BB_Signal_Ind.mq5 | Codice di un indicatore di test che visualizza i segnali come frecce su un grafico |
| BB_Signal_Stat_Indicator_V1.mq5 | Codice di un indicatore di test che visualizza i segnali come frecce e statistiche di trading virtuali. |
| BB_Signal_Stat_Indicator_V2.mq5 | Codice di un indicatore di test che visualizza i segnali come frecce, statistiche di trading virtuali e una curva del saldo. |
| BB_Signal_Stat_Indicator_DLL.mq5 | Codice di un indicatore di test che visualizza i segnali come frecce, statistiche di trading virtuali, una curva del saldo e utilizza anche una libreria DLL. |
| StatsCalculator.zip | Codice per la creazione di una DLL per il calcolo delle statistiche di trading virtuali in Visual Studio 2019 |
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/22395
Avvertimento: Tutti i diritti su questi materiali sono riservati a MetaQuotes Ltd. La copia o la ristampa di questi materiali in tutto o in parte sono proibite.
Arriva il Nuovo MetaTrader 5 e MQL5
Come abbiamo creato la piattaforma di trading più potente basata sull'apprendimento automatico: L'evoluzione di MQL e MetaTrader attraverso archivi, forum e nuove versioni.
Utilizza i canali MQL5.community e le chat di gruppo
Visualizzazione 3D senza librerie esterne: come MetaTrader 5 mostra i risultati dell'ottimizzazione tramite MQL5 + DX11
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso