English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
preview
Sviluppare un Expert Advisor per il trading da zero (Parte 17): Accesso ai dati sul web (III)

Sviluppare un Expert Advisor per il trading da zero (Parte 17): Accesso ai dati sul web (III)

MetaTrader 5Esempi | 13 aprile 2023, 10:35
608 0
Daniel Jose
Daniel Jose

Introduzione

Nel precedente articolo Sviluppare un Expert Advisor di trading da zero (Parte 16): Accesso ai dati sul web (II), abbiamo parlato dei problemi e delle conseguenze dell'acquisizione dei dati dal web. Abbiamo anche considerato come usarli in un Expert Advisor e abbiamo discusso tre possibili soluzioni, ognuna con i suoi pro e i suoi contro.

Nella prima soluzione, che prevedeva l'acquisizione dei dati direttamente tramite l'Expert Advisor, abbiamo considerato un possibile problema, legato alla lentezza di risposta del server. Abbiamo anche accennato alle conseguenze che questo può avere su un sistema di trading.

Nella seconda soluzione, abbiamo implementato un canale basato sul modello client-server, in cui l'EA fungeva da client, uno script era il server e un oggetto serviva da canale. Questo modello funziona bene fino al punto in cui decidi di cambiare il timeframe, dove diventa scomodo. Nonostante ciò, è il miglior sistema presentato, perché l'uso del modello client-server garantisce che l'EA non aspetterà un server remoto — leggerà semplicemente i dati contenuti nell'oggetto, indipendentemente da dove queste informazioni siano arrivate.

Nella terza e ultima soluzione, abbiamo migliorato il sistema client-server utilizzando un servizio. Così, abbiamo iniziato a utilizzare una risorsa della piattaforma MetaTrader 5, che è abbastanza poco studiata: le variabili globali del terminale. Questa soluzione ha risolto il problema con la modifica del timeframe, che era il più grande svantaggio del modello utilizzando gli script. Tuttavia, abbiamo un nuovo problema: il sistema delle variabili globali del terminale consente l'uso, solo del tipo double. Molti non sanno come evitarlo, e quindi passano varie informazioni, come un pezzo di testo, attraverso il canale fornito da MetaTrader 5.

In questo articolo, discuteremo come aggirare questa limitazione. Ma non aspettarti miracoli, perché ci vorrà molto lavoro per far funzionare il sistema nel modo desiderato.

Questa volta procederemo allo sviluppo di un sistema alternativo.


1. Pianificazione

Come sappiamo, possiamo utilizzare solo variabili di tipo double nel sistema del canale fornito da MetaTrader 5. Questo tipo è composto da 8 byte. Potresti pensare che non sia un'informazione molto utile. Ma cerchiamo di capire il seguente momento:

I sistemi informatici lavorano con i byte, sebbene molte persone abbiano dimenticato questo concetto. È molto importante comprendere questo sistema. Ogni byte è composto da 8 bit. 1 bit è il numero più piccolo possibile in un sistema informatico. Il tipo più piccolo e semplice presente nel linguaggio è il tipo Booleano, che consiste in un singolo bit. Questa è la più semplice delle basi.

Quindi, qualsiasi informazione, non importa quanto complessa possa essere, sarà contenuta in 1 byte. Ancora una volta, non importa quanto complessa è l’informazione, sarà sempre all'interno di un byte, che è composto da 8 bit. Quando uniamo 2 byte otteniamo il primo set composto nel sistema. Questo primo set è noto come WORD, il secondo set come DWORD che sarà 2 WORD e il terzo set sarà QWORD che sarà 2 DWORD. Questa è la nomenclatura utilizzata in assembly, che è la lingua madre di tutti i linguaggi moderni, quindi la maggior parte dei sistemi utilizzano gli stessi tipi. L'unica differenza è nel modo in cui questi tipi sono denominati.

Spero che siate stati in grado di seguire il ragionamento fino a questo punto. Per rendere le cose più facili per coloro che sono appena agli inizi, date un'occhiata alle figure qui sotto:

          

                         

Le immagini sopra mostrano i principali tipi attualmente disponibili, coprono da 1 a 64 bit. Potresti pensare: "Perché ho bisogno di questa spiegazione?". È importante conoscere queste informazioni al fine di capire cosa faremo nel corso di questo articolo, poiché manipoleremo questi tipi per poter essere in grado di passare informazioni con proprietà interne differenti.

Ciascuno di questi tipi può assumere nomi diversi a seconda del linguaggio utilizzato, nel caso di MQL5 sono mostrati nella tabella seguente:

Nome Numero di byte Nome basato sul linguaggio assembly (immagini sopra) 
bool   Utilizza solo 1 bit; un byte può avere 8 valori bool.  Utilizza solo 1 bit; un byte può avere 8 valori bool.
char 1
 Byte
short 2  Word
int  4  DWord
long 8  QWord

Questa tabella copre gli interi con segno, per maggiori dettagli in MQL5 vedere i tipi interi, altri nomi sono definiti lì. Successivamente, i tipi reali hanno alcune somiglianze con i tipi interi, ma hanno una loro formattazione e stile interno proprio. Un esempio di formattazione e modellazione può essere visto in un numero a doppia precisione, ma fondamentalmente corrisponderà alla tabella seguente:

Nome Numero di byte Nome basato sul linguaggio assembly (immagini sopra) 
Float 4  DWord
Double 8  QWord

Una cosa interessante da notare è che sia il modello a virgola mobile che quello intero utilizzano lo stesso database ma con lunghezze diverse. Ora siamo arrivati al punto che ci interessa davvero. Se capisci la logica, alla fine puoi giungere alla seguente conclusione, che può essere vista nell'immagine qui sotto:

QWORD è di 8 byte e quindi 'double' consente di inserire 8 byte di informazioni. Ad esempio, puoi passare 8 caratteri stampabili in una variabile globale del terminale e otterrai il risultato della connessione tra il servizio e l'EA, come mostrato di seguito.

I dati sono ok, penso che l'idea stessa sia comprensibile. Il grande dettaglio è che se il messaggio ha più di 8 caratteri stampabili, allora dovrà essere frammentato in più parti. Ma se l’informazione deve essere consegnata molto rapidamente, cioè in 1 ciclo, sarà necessario utilizzare tutte le variabili terminali globali necessarie per trasmettere i messaggi in un ciclo. poi devono essere incollati insieme per ripristinare il messaggio originale. Ma se può essere consegnato in pacchetti, dovremo creare un modulo per il server in modo che il servizio sappia che il client, che in questo caso è l'EA, leggerà il messaggio e attenderà il blocco successivo.

Questo tipo di problema ha più soluzioni. Se desideri comprendere o implementare queste soluzioni, non avrai bisogno di creare tutto da zero — puoi utilizzare la stessa modellazione dei protocolli di comunicazione di rete come TCP/ IP o UDP e adattare l'idea al sistema di trasferimento delle informazioni utilizzando le variabili terminali globali. Una volta capito come funzionano i protocolli, questo compito non è più complicato e diventa una questione di abilità e conoscenza del linguaggio che stai utilizzando. Questo è un argomento molto ampio che merita uno studio separato per ogni tipo di situazione e problema.


2. Implementazione

Ora che abbiamo compreso l'idea che useremo, possiamo realizzare un'implementazione iniziale per testare come il sistema trasferirà le informazioni tra il servizio e l'EA. Ma passeremo solo caratteri stampabili.

2.1. Modello base

Useremo un sistema dall'articolo precedente e modificheremo i file, a partire dal file di intestazione. Il suo nuovo contenuto è mostrato per intero nel codice qui sotto:

//+------------------------------------------------------------------+
#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#define def_GlobalNameChannel   "InnerChannel"
//+------------------------------------------------------------------+
union uDataServer
{
        double  value;
        char    Info[sizeof(double)];
};
//+------------------------------------------------------------------+

Questa intestazione è fondamentale. Contiene una dichiarazione della variabile globale del terminale. Ha anche una nuova struttura, una union. L'unione differisce dalla struttura in quanto una struttura è una combinazione di dati senza interleaving, mentre l'unione la utilizza sempre, quando i dati più piccoli sono all'interno del più grande. Nel caso precedente, abbiamo come base un valore double, che ha 8 byte al suo interno. Ma fai attenzione che utilizzo un sistema per catturare la lunghezza sizeof, quindi se in futuro avremo un double più grande, il che è improbabile, questo codice si adatterà automaticamente ad esso.

Come risultato, otteniamo quanto segue:

Nota che questo è simile all'immagine sopra, ma è quello che fa l’unione.

Il codice successivo da modificare è l'EA che corrisponde al client. Il codice completo può essere visto di seguito:

#property copyright "Daniel Jose"
#property description "Testing internal channel\nvia terminal global variable"
#property version "1.04"
//+------------------------------------------------------------------+
#include <Inner Channel.mqh>
//+------------------------------------------------------------------+
int OnInit()
{
        EventSetTimer(1);
        
        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick()
{
}
//+------------------------------------------------------------------+
void OnTimer()
{
        uDataServer loc;
        
        if (GlobalVariableCheck(def_GlobalNameChannel))
        {
                GlobalVariableGet(def_GlobalNameChannel, loc.value);
                Print(CharArrayToString(loc.Info, 0, sizeof(uDataServer)));
        }
}
//+------------------------------------------------------------------+

Nota che qui usiamo la funzione CharArrayToString per convertire un array uchar in una stringa. Tuttavia, fai attenzione che otteniamo ancora un valore double perché è l'unico che può essere ricevuto da una variabile globale del terminale. Al contrario, string in MQL5 segue il principio di C/C++ e quindi non possiamo usare alcun carattere, ma possiamo solo crearne uno nostro. Ma questa è un'altra storia. Qui non entreremo nei dettagli su come farlo: potresti voler utilizzare la compressione dei dati di modellazione per superare il limite di 8 byte.

Ma abbiamo ancora bisogno di un programma che funga da server. Nel nostro caso il server è un servizio. Di seguito è riportato il codice per testare il sistema:

//+------------------------------------------------------------------+
#property service
#property copyright "Daniel Jose"
#property version   "1.03"
//+------------------------------------------------------------------+
#include <Inner Channel.mqh>
//+------------------------------------------------------------------+
void OnStart()
{
        uDataServer loc;
        char car = 33;
        
        while (!IsStopped())
        {
                if (!GlobalVariableCheck(def_GlobalNameChannel)) GlobalVariableTemp(def_GlobalNameChannel);
                for (char c0 = 0; c0 < sizeof(uDataServer); c0++)
                {
                        loc.Info[c0] = car;
                        car = (car >= 127 ? 33 : car + 1);
                }
                GlobalVariableSet(def_GlobalNameChannel, loc.value);
                Sleep(1000);
        }
}
//+------------------------------------------------------------------+

Si tratta di qualcosa di semplice ma estremamente efficiente e funzionale.

Lanciando il programma nella piattaforma, otterremo il seguente risultato:


Può sembrare sciocco e inutile, ma con un po' di creatività qualcuno può rendere questo sistema abbastanza utile e fargli fare cose che gli altri non possono nemmeno immaginare.

Per dimostrarlo, modifichiamo il sistema e mostriamo una cosa molto semplice, giusto per suscitare curiosità e interesse. Pensa a quale funzionalità molto esotica può essere trovata per un tale sistema di comunicazione.


2.2. Adesivi di scambio

Lo scambio di adesivi è lo scambio di informazioni tra il client e il server durante il quale il server sa quali informazioni il client desidera ricevere e quindi il server può iniziare a produrre o cercare tali informazioni.

Il concetto è abbastanza semplice da capire. Ma la sua implementazione può essere una vera sfida, soprattutto quando si tratta di modellazione dei dati dove abbiamo solo 8 byte disponibili mentre il canale viene utilizzato per il trasferimento dei dati.

2.2.1. Test di comunicazione client-server

Dai un'occhiata al codice del servizio che è riportato per intero di seguito:

#property service
#property copyright "Daniel Jose"
#property version   "1.03"
//+------------------------------------------------------------------+
#include <Inner Channel.mqh>
//+------------------------------------------------------------------+
void OnStart()
{
        uDataServer loc, loc1, loc2;
        char car = 33;
        
        while (!IsStopped())
        {
                if (!GlobalVariableCheck(def_GlobalValueInChannel))
                {
                        GlobalVariableTemp(def_GlobalValueInChannel);
                        GlobalVariableTemp(def_GlobalMaskInfo);
                        GlobalVariableTemp(def_GlobalPositionInfos);
                }
                for (char c0 = 0; c0 < sizeof(uDataServer); c0++)
                {
                        loc.Info[c0] = car;
                        car = (car >= 127 ? 33 : car + 1);
                }
                GlobalVariableSet(def_GlobalValueInChannel, loc.value);
                GlobalVariableGet(def_GlobalMaskInfo, loc1.value);
                GlobalVariableGet(def_GlobalPositionInfos, loc2.value);
                Print(CharArrayToString(loc1.Info, 0, sizeof(uDataServer)), "   ",loc2.Position[0], "    ", loc2.Position[1]);
                Sleep(1000);
        }
}
//+------------------------------------------------------------------+

Presta attenzione ad alcune parti particolarmente interessanti nel nuovo codice del servizio (che funge da server). Ora abbiamo tre variabili invece di una. Lavorano per creare un canale abbastanza grande da consentire la comunicazione tra il client (che è un EA nel nostro caso) e il server (il nostro servizio). Prestare attenzione alla seguente riga:

Print(CharArrayToString(loc1.Info, 0, sizeof(uDataServer)), "   ",loc2.Position[0], "    ", loc2.Position[1]);

Questi sono i dati pubblicati dal client. Nota che stiamo usando 2 variabili per passare 3 diverse informazioni. Ma come è possibile? Per capire questo, dobbiamo vedere il codice dell'intestazione, che è mostrato per intero di seguito.

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#define def_GlobalValueInChannel        "Inner Channel"
#define def_GlobalMaskInfo                      "Mask Info"
#define def_GlobalPositionInfos         "Positions Infos"
//+------------------------------------------------------------------+
union uDataServer
{
        double  value;
        uint    Position[2];
        char    Info[sizeof(double)];
};
//+------------------------------------------------------------------+

Potresti pensare che ogni variabile all'interno di questa union sia isolata dall'altra. Ti consiglio di guardare all'inizio di questo articolo, perché sebbene abbiamo variabili con nomi diversi, qui vengono trattate come un'unica variabile, che è larga 8 byte. Per renderlo più chiaro, dai un'occhiata all'immagine qui sotto, che riflette esattamente ciò che sta accadendo:

Questo schema mostra cosa c'è dentro uDataServer.

Se ti sembra troppo complicato, dovresti provare a sperimentare con le union per capire come funzionano effettivamente, poiché sono molto utili nella programmazione.

Ma torniamo al sistema. La prossima cosa da fare è creare il codice per il client — l'EA. Può essere visto per intero qui sotto.

#property copyright "Daniel Jose"
#property description "Testing internal channel\nvia terminal global variable"
#property version "1.04"
//+------------------------------------------------------------------+
#include <Inner Channel.mqh>
//+------------------------------------------------------------------+
enum eWhat {DOW_JONES, SP500};
input eWhat     user01 = DOW_JONES;     //Search
//+------------------------------------------------------------------+
int OnInit()
{
        EventSetTimer(1);
        
        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick()
{
}
//+------------------------------------------------------------------+
void OnTimer()
{
        uDataServer loc;
        
        SetFind();
        if (GlobalVariableCheck(def_GlobalValueInChannel))
        {
                GlobalVariableGet(def_GlobalMaskInfo, loc.value);
                Print(CharArrayToString(loc.Info, 0, sizeof(uDataServer)), "  ", GlobalVariableGet(def_GlobalValueInChannel));
        }
}
//+------------------------------------------------------------------+
inline void SetFind(void)
{
        static int b = -1;
        uDataServer loc1, loc2;
        
        if ((GlobalVariableCheck(def_GlobalValueInChannel)) && (b != user01))
        {
                b = user01;
                switch (user01)
                {
                        case DOW_JONES  :
                                StringToCharArray("INDU:IND", loc1.Info, 0, sizeof(uDataServer));
                                loc2.Position[0] = 172783;
                                loc2.Position[1] = 173474;
                                break;
                        case SP500              :
                                StringToCharArray("SPX:IND", loc1.Info, 0, sizeof(uDataServer));
                                loc2.Position[0] = 175484;
                                loc2.Position[1] = 176156;
                                break;
                }
                GlobalVariableSet(def_GlobalMaskInfo, loc1.value);
                GlobalVariableSet(def_GlobalPositionInfos, loc2.value);
        }
};
//+------------------------------------------------------------------+

Nota che in questo EA trasmettiamo e riceviamo informazioni, ovvero possiamo controllare come dovrebbe funzionare il servizio. In una variabile, passiamo una piccola stringa che indicherà cosa dovrebbe cercare il servizio, e nell'altra passiamo i punti di 2 indirizzi.

In risposta, il servizio restituirà informazioni. Ma per capire questo primo punto, guarda il risultato nel video qui sotto:



3.1.2.2 - Creazione di una versione pratica

Ora che abbiamo visto come funziona il sistema, possiamo realizzare qualcosa di veramente funzionale. Questa volta raccoglieremo informazioni dal server web. Ciò richiede una serie di modifiche che assicurano una perfetta comprensione di cosa sta accadendo. A volte potremmo immaginare che stiamo ricevendo dati aggiornati anche se in realtà stiamo utilizzando spazzatura nelle analisi. Bisogna stare molto attenti durante la fase di programmazione per non esporsi a questo rischio. Quello che puoi fare è aggiungere il maggior numero di test possibile e provare a fare in modo che il sistema segnali qualsiasi strana attività che potrebbe rilevare durante l'esecuzione.

Ricorda: Le informazioni ti saranno utili solo se ti fidi di esse.

Innanzitutto, editiamo il file di intestazione in modo che assomigli a questo:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#define def_GlobalValueInChannel        "Inner Channel"
#define def_GlobalMaskInfo              "Mask Info"
#define def_GlobalPositionInfos         "Positions Infos"
//+------------------------------------------------------------------+
#define def_MSG_FailedConnection        "BAD"
#define def_MSG_FailedReturn            "FAILED"
#define def_MSG_FailedMask              "ERROR"
#define def_MSG_FinishServer            "FINISH"
//+------------------------------------------------------------------+
union uDataServer
{
        double  value;
        uint            Position[2];
        char            Info[sizeof(double)];
};
//+------------------------------------------------------------------+

Le parti evidenziate rappresentano i codici che useremo per segnalare qualche strana attività. Dovresti usare un massimo di 8 caratteri, ma devi anche creare una sequenza che è improbabile che venga creata dal mercato, il che non è una cosa facile da fare. Anche se tutto sembra a posto, c'è sempre il rischio che il mercato generi un valore corrispondente alla sequenza che utilizzerai come messaggi di errore del server. Ad ogni modo, puoi anche utilizzare una variabile globale del terminale per questo scopo, che aumenterà il numero delle possibili combinazioni, permettendoti così di creare più cose. Ma volevo usare il minor numero possibile di variabili globali del terminale. Tuttavia, in un caso reale, ci penserei e possibilmente utilizzerei una variabile solo per l'indicazione e la segnalazione degli errori o di attività anomale.

La parte successiva è il codice completo dell'EA.

#property copyright "Daniel Jose"
#property description "Testing internal channel\nvia terminal global variable"
#property version "1.04"
//+------------------------------------------------------------------+
#include <Inner Channel.mqh>
//+------------------------------------------------------------------+
enum eWhat {DOW_JONES, SP500};
input eWhat     user01 = DOW_JONES;             //Search
//+------------------------------------------------------------------+
int OnInit()
{
        EventSetTimer(1);
        
        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick()
{
}
//+------------------------------------------------------------------+
void OnTimer()
{
        ClientServer();
}
//+------------------------------------------------------------------+
inline void ClientServer(void)
{
        uDataServer loc1, loc2;
        string          sz0;
        
        SetFind();
        if (GlobalVariableCheck(def_GlobalValueInChannel))
        {
                GlobalVariableGet(def_GlobalMaskInfo, loc1.value);
                loc2.value = GlobalVariableGet(def_GlobalValueInChannel);
                sz0 = CharArrayToString(loc2.Info, 0, sizeof(uDataServer));
                if (sz0 == def_MSG_FailedConnection) Print("Failed in connection."); else
                if (sz0 == def_MSG_FailedReturn) Print("Error in Server Web."); else
                if (sz0 == def_MSG_FailedMask) Print("Bad Mask or position."); else
                if (sz0 == def_MSG_FinishServer) Print("Service Stop."); else
                Print(CharArrayToString(loc1.Info, 0, sizeof(uDataServer)), "  ", loc2.value);
        }
}
//+------------------------------------------------------------------+
inline void SetFind(void)
{
        static int b = -1;
        uDataServer loc1, loc2;
        
        if ((GlobalVariableCheck(def_GlobalValueInChannel)) && (b != user01))
        {
                b = user01;
                switch (user01)
                {
                        case DOW_JONES  :
                                StringToCharArray("INDU:IND", loc1.Info, 0, sizeof(uDataServer));
                                loc2.Position[0] = 172783;
                                loc2.Position[1] = 173474;
                                break;
                        case SP500              :
                                StringToCharArray("SPX:IND", loc1.Info, 0, sizeof(uDataServer));
                                loc2.Position[0] = 175487;
                                loc2.Position[1] = 176159;
                                break;
                }
                GlobalVariableSet(def_GlobalMaskInfo, loc1.value);
                GlobalVariableSet(def_GlobalPositionInfos, loc2.value);
        }
};
//+------------------------------------------------------------------+

Le linee evidenziate sono molto importanti e dovrebbero essere ben ponderate poiché vogliamo davvero sapere cosa sta succedendo. Come puoi vedere, possiamo dire all'utente qualcosa di più dettagliato di quanto offerto dalle sequenze create nel file di intestazione, in modo che diventi più facile programmare e mantenere la soluzione. Il resto del codice non è cambiato molto. Guarda il codice del servizio qui sotto.

#property service
#property copyright "Daniel Jose"
#property version   "1.03"
//+------------------------------------------------------------------+
#include <Inner Channel.mqh>
//+------------------------------------------------------------------+
void OnStart()
{
        uDataServer loc1, loc2;
        
        while (!IsStopped())
        {
                if (!GlobalVariableCheck(def_GlobalValueInChannel))
                {
                        GlobalVariableTemp(def_GlobalValueInChannel);
                        GlobalVariableTemp(def_GlobalMaskInfo);
                        GlobalVariableTemp(def_GlobalPositionInfos);
                }
                GlobalVariableGet(def_GlobalMaskInfo, loc1.value);
                GlobalVariableGet(def_GlobalPositionInfos, loc2.value);
                if (!_StopFlag)
                {
                        GlobalVariableSet(def_GlobalValueInChannel, GetDataURL(
                                                                                "https://tradingeconomics.com/stocks",
                                                                                100,
                                                                                "<!doctype html>",
                                                                                2,
                                                                                CharArrayToString(loc1.Info, 0, sizeof(uDataServer)),
                                                                                loc2.Position[0],
                                                                                loc2.Position[1],
                                                                                0x0D
                                                                               )
                                        );
                        Sleep(1000);
                }
        }
        GlobalVariableSet(def_GlobalValueInChannel, Codification(def_MSG_FinishServer));
}
//+------------------------------------------------------------------+
double GetDataURL(const string url, const int timeout, const string szTest, int iTest, const string szFind, int iPos, int iInfo, char cLimit)
{
        string          headers, szInfo = "";
        char                    post[], charResultPage[];
        int                     counter;
   
        if (WebRequest("GET", url, NULL, NULL, timeout, post, 0, charResultPage, headers) == -1) return Codification(def_MSG_FailedConnection);
        for (int c0 = 0, c1 = StringLen(szTest); (c0 < c1) && (!_StopFlag); c0++) if (szTest[c0] != charResultPage[iTest + c0]) return Codification(def_MSG_FailedReturn);
        for (int c0 = 0, c1 = StringLen(szFind); (c0 < c1) && (!_StopFlag); c0++) if (szFind[c0] != charResultPage[iPos + c0]) return Codification(def_MSG_FailedMask);
        if (_StopFlag) return Codification(def_MSG_FinishServer);
        for (counter = 0; charResultPage[counter + iInfo] == 0x20; counter++);
        for (;charResultPage[counter + iInfo] != cLimit; counter++) szInfo += CharToString(charResultPage[counter + iInfo]);
        
        return StringToDouble(szInfo);
}
//+------------------------------------------------------------------+
inline double Codification(const string arg)
{
        uDataServer loc;
        StringToCharArray(arg, loc.Info, 0, sizeof(uDataServer));
        
        return loc.value;
}
//+------------------------------------------------------------------+

La riga evidenziata è importante anch’essa — il servizio avviserà che non è più in esecuzione.

Quindi, quando esegui questo sistema, otterrai il seguente risultato:


Conclusioni

Spero di aver spiegato l'idea relativa alla ricerca, ricercando e utilizzando i dati web sulla piattaforma MetaTrader 5. Capisco che questo potrebbe non essere molto chiaro all’inizio, soprattutto per coloro che non hanno una conoscenza molto approfondita della programmazione, ma col tempo, attraverso la disciplina e l'apprendimento, alla fine padroneggerai la maggior parte di questo materiale. Qui ho cercato di condividere almeno un po' di quello che so.

Tradotto dal portoghese da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/pt/articles/10447

File allegati |
Servi0o_-_EA.zip (10.71 KB)
Impara come progettare un sistema di trading tramite la Deviazione Standard Impara come progettare un sistema di trading tramite la Deviazione Standard
Ecco un nuovo articolo della nostra serie su come progettare un sistema di trading con gli indicatori tecnici più popolari nella piattaforma di trading MetaTrader 5. In questo nuovo articolo, impareremo come progettare un sistema di trading tramite l'indicatore Deviazione Standard.
Sviluppare un Expert Advisor per il trading da zero (Parte 16): Accesso ai dati sul web (II) Sviluppare un Expert Advisor per il trading da zero (Parte 16): Accesso ai dati sul web (II)
Conoscere come inserire dati dal Web in un Expert Advisor non è così scontato. Non è così facile farlo, senza comprendere tutte le possibilità offerte da MetaTrader 5.
Impara come progettare un sistema di trading tramite Chaikin Oscillator Impara come progettare un sistema di trading tramite Chaikin Oscillator
Benvenuti nel nostro nuovo articolo della nostra serie sull'imparare a progettare un sistema di trading tramite gli indicatori tecnici più popolari. Attraverso questo nuovo articolo, impareremo come progettare un sistema di trading tramite l'indicatore Chaikin Oscillator.
Scienza dei dati e apprendimento automatico (Parte 06): Discesa del Gradiente Scienza dei dati e apprendimento automatico (Parte 06): Discesa del Gradiente
La discesa del gradiente gioca un ruolo significativo nell'addestramento delle reti neurali e di molti algoritmi di apprendimento automatico. È un algoritmo veloce e intelligente, nonostante il suo lavoro impressionante, è ancora frainteso da molti data scientist, vediamo di cosa si tratta.