English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Utilizzo degli indicatori MetaTrader 5 con il framework di apprendimento automatico ENCOG per la previsione delle serie temporali

Utilizzo degli indicatori MetaTrader 5 con il framework di apprendimento automatico ENCOG per la previsione delle serie temporali

MetaTrader 5Esempi | 17 dicembre 2021, 15:21
307 0
investeo
investeo

Introduzione

Questo articolo introdurrà MetaTrader 5 a ENCOG, rete neurale avanzata e framework di apprendimento automatico sviluppato da Heaton Research. Conosco metodi descritti in precedenza che consentono a MetaTrader di utilizzare tecniche di apprendimento automatico: FANN, NeuroSolutions, Matlab e NeuroShell. Spero che ENCOG sia una soluzione complementare poiché è un codice robusto e ben progettato.

Perché ho scelto ENCOG? Ci sono alcune ragioni.

  1. ENCOG è utilizzato in altri due pacchetti software di trading. Uno è basato su C#, il secondo su JAVA. Ciò significa che è già stato testato per prevedere i dati delle serie temporali finanziarie. 
  2. ENCOG è un software gratuito e open source. Se vuoi vedere cosa sta succedendo all'interno di una rete neurale puoi sfogliare il codice sorgente. Questo è ciò che ho effettivamente fatto per comprendere le parti del problema della previsione delle serie temporali. C# è un linguaggio di programmazione pulito e di facile comprensione.
  3. ENCOG è molto ben documentato. Mr Heaton, fondatore di Heaton Research, offre un corso online gratuito su reti neurali, apprendimento automatico e utilizzo di ENCOG per prevedere i dati futuri. Ho seguito molte delle sue lezioni prima di scrivere questo articolo. Mi hanno aiutato molto a capire le reti neurali artificiali. Inoltre ci sono degli e-book sulla programmazione di ENCOG in JAVA e C# sul sito web di Heaton Research. La documentazione completa di ENCOG è disponibile online.
  4. ENCOG non è un progetto morto. Al momento della stesura di questo articolo, ENCOG 2.6 è ancora in fase di sviluppo. Recentemente è stata pubblicata la tabella di marcia per ENCOG 3.0.
  5. ENCOG è robusto. È ben progettato, può utilizzare più core della CPU e multithreading per accelerare i calcoli della rete neurale. Parti del codice iniziano a essere trasferite per OpenCL - calcoli abilitati GPU.
  6. Funzionalità attualmente supportate da ECNOG: 

Tipi di apprendimento automatico

Architetture di rete neurale

Tecniche di allenamentoFunzioni di attivazioneTecniche di randomizzazione
  • Randomizzazione dell'intervallo
  • Numeri casuali gaussiani
  • Fan-In
  • Nguyen-Widrow

Caratteristiche previste:

Come puoi vedere, questo è un elenco di funzionalità piuttosto lungo.

Questo articolo introduttivo si concentra sull'architettura di rete neurale feedforward con il training di Resilient Propagation (RPROP). Comprende anche le basi della preparazione dei dati: timeboxing e normalizzazione per la previsione delle serie temporali provvisorie.

La conoscenza che mi ha permesso di scrivere questo articolo si basa su tutorial disponibili sul sito web di Heaton Research e articoli molto recenti sulla previsione delle serie temporali finanziarie su NinjaTrader. Da notare che ENCOG è basato su JAVA e C#. Non mi sarebbe possibile scrivere questo articolo senza il mio lavoro precedente: Esposizione del codice C# a MQL5 tramite esportazioni non gestite. Questa soluzione ha permesso di utilizzare la DLL C# come ponte tra l'indicatore Metatrader 5 e l’indicatore delle serie temporali ENCOG.


1. Utilizzo dei valori degli indicatori tecnici come input per una rete neurale

La rete neurale artificiale è un algoritmo progettato dall'uomo che cerca di emulare la rete neurale del cervello.

Sono disponibili vari tipi di algoritmi neurali ed esiste una varietà di architetture di rete neurale. Il campo di ricerca è così ampio che esistono interi libri dedicati a un singolo tipo di rete neurale. Poiché tali dettagli non rientrano nell'ambito di questo articolo, posso solo consigliare di seguire i tutorial di Heaton Research o di leggere un libro sull'argomento. Mi concentrerò sugli input e sugli output della rete neurale feedforward e cercherò di descrivere l'esempio pratico della previsione delle serie temporali finanziarie.

Per iniziare a prevedere le serie temporali finanziarie dobbiamo pensare a cosa dobbiamo fornire alla rete neurale e cosa possiamo aspettarci in cambio. Nel pensiero più astratto della black box, otteniamo profitti o perdite assumendo posizioni long o short sul contratto di un determinato titolo e chiudendo l'operazione dopo un po' di tempo.

Attraverso l'osservazione dei prezzi passati di un titolo e dei valori degli indicatori tecnici, cerchiamo di prevedere il sentimento futuro o la direzione dei prezzi al fine di acquistare o vendere un contratto e assicurarci che la nostra decisione non venga presa lanciando una moneta. La situazione sembra meno simile alla figura seguente:

Figura 1. Previsione delle serie trimestrali finanziarie mediante indicatori tecnici

Figura 1. Previsione di serie temporali finanziarie utilizzando gli indicatori tecnici 

Cercheremo di ottenere lo stesso con l'intelligenza artificiale. La rete neurale proverà a riconoscere i valori degli indicatori e deciderà se c'è la possibilità che il prezzo salga o diminuisca. Come lo otteniamo? Dal momento che faremo previsioni sulle serie temporali finanziarie utilizzando l'architettura della rete neurale feedforward, penso che dobbiamo prima introdurre la sua architettura.

La rete neurale feedforward è costituita da neuroni raggruppati in strati. Devono essere presenti almeno 2 livelli: un livello di input che contiene neuroni di input e uno strato di output che contiene neuroni di output. Possono esserci anche livelli nascosti che si trovano tra i livelli di input e di output. Il livello di input può essere semplicemente pensato come un array di valori doppi e il livello di output può essere costituito da uno o più neuroni che formano anche un array di valori doppi. Vedi la figura qui sotto:

 Figura 2. Livelli di rete neurale feedforward

Figura 2. Strati di rete neurale feedforward 

Le connessioni tra i neuroni non sono state tracciate per semplificare il disegno. Ogni neurone dello strato di input è connesso a un neurone dello strato nascosto. Ciascun neurone dello strato nascosto è connesso a un neurone dello strato di output.

Ogni connessione ha il suo peso, che è anche un doppio valore e una funzione di attivazione con una soglia, la quale è responsabile dell'attivazione di un neurone e del passaggio dell'informazione al neurone successivo. Questo è il motivo per cui viene chiamata rete "feedforward": le informazioni basate sugli output dei neuroni attivati vengono trasmesse da uno strato a un altro strato di neuroni. Per i video introduttivi dettagliati sulle reti neurali feedforward puoi visitare i link:

Dopo aver appreso dell'architettura della rete neurale e dei suoi meccanismi, potresti essere ancora perplesso.

I problemi principali sono:

  1. Quali dati dobbiamo fornire a una rete neurale?
  2. Come li forniamo?
  3. Come preparare i dati di input per una rete neurale? 
  4. Come scegliere l'architettura di rete neurale? Di quanti neuroni di input, neuroni nascosti e neuroni di output abbiamo bisogno?
  5. Come addestrare la rete?
  6. Quale dovrebbe essere l'output?

 

2. Con quali dati alimentare la rete neurale

Poiché abbiamo a che fare con previsioni finanziarie basate sui risultati degli indicatori, dobbiamo alimentare la rete con i valori dei risultati degli indicatori. Per questo articolo ho scelto Stochastic %K, Stochastic Slow %D e Williams %R come input.

Figura 3. Indicatori tecnici utilizzati per la previsione

Figura 3. Indicatori tecnici utilizzati per la previsione

Per estrarre i valori degli indicatori possiamo utilizzare le funzioni iStochastic e iWPR MQL5:

double StochKArr[], StochDArr[], WilliamsRArr[];

ArraySetAsSeries(StochKArr, true);   
ArraySetAsSeries(StochDArr, true);   
ArraySetAsSeries(WilliamsRArr, true);

int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
CopyBuffer(hStochastic, 0, 0, bufSize, StochKArr);
CopyBuffer(hStochastic, 1, 0, bufSize, StochDArr);
CopyBuffer(hWilliamsR, 0, 0, bufSize, WilliamsRArr);

Dopo che questo codice è stato eseguito, tre array StochKArr, StochDArr e WilliamsRArr devono essere compilati con i valori di output degli indicatori. A seconda della dimensione del campione di addestramento, questo può raggiungere alcune migliaia di valori. Tieni presente che questi due indicatori sono stati scelti solo per scopi didattici.

Ti invito a sperimentare con tutti gli indicatori che ritieni appropriati per la previsione. Potresti voler alimentare la rete con i prezzi dell'oro e del petrolio per prevedere gli indici azionari o puoi utilizzare coppie forex correlate per prevedere un'altra coppia di valute. 

 

3. Dati di input Timeboxing

Avendo raccolto dati di input da diversi indicatori, abbiamo bisogno di applicare il 'timebox' all'input prima di inserirlo nella rete neurale. Il timeboxing è una tecnica che consente di presentare gli input per la rete come sezioni di dati in movimento. Puoi immaginare una scatola in movimento di dati di input che si sposta in avanti sull'asse del tempo. Ci sono fondamentalmente due passaggi coinvolti in questa procedura:

1. Raccolta di dati di input da ciascun buffer dell'indicatore. Abbiamo bisogno di copiare un numero di elementi INPUT_WINDOW dalla posizione di partenza verso il futuro. La finestra di input è il numero di barre utilizzate per la previsione. 

 Figura 4. Raccolta dei dati della finestra di input dal buffer dell'indicatore

Figura 4. Raccolta dei dati della finestra di input dal buffer dell'indicatore 

Come puoi vedere nell'esempio sopra, INPUT_WINDOW è uguale a 4 barre e abbiamo copiato gli elementi nell'array I1. I1[0] è il primo elemento I1[3] è l'ultimo. Allo stesso modo, i dati devono essere copiati da altri indicatori in array di dimensioni INPUT_WINDOW. Questa cifra è valida per gli array di serie temporali con il flag AS_SERIES impostato su true. 

2. Combinazione di array INPUT_WINDOW in un array che viene inserito nel livello di input della rete neurale. 

Figura 5. Array di finestre di input con Timebox 

Figura 5. Array di finestre di input con timebox

Ci sono 3 indicatori. All'inizio prendiamo il primo valore di ogni indicatore, poi il secondo valore di ogni indicatore e continuiamo fino a riempire la finestra di input come nella figura sopra. Tale matrice combinata dagli output degli indicatori può essere alimentata al livello di input della nostra rete neurale. Quando arriva una nuova barra, i dati vengono suddivisi di un elemento e l'intera procedura viene ripetuta. Se sei interessato a maggiori dettagli sulla preparazione dei dati per la previsione, puoi guardare un video sull'argomento.

 

4. Normalizzazione dei dati di input

Per rendere efficace la rete neurale dobbiamo normalizzare i dati. Ciò è necessario per il corretto calcolo delle funzioni di attivazione. La normalizzazione è un processo matematico che converte i dati nell'intervallo 0..1 o -1..1. I dati normalizzati possono essere denormalizzati, in altre parole riconvertiti nell'intervallo originale.

La denormalizzazione è necessaria per decodificare l'output della rete neurale in una forma leggibile dall'uomo. Per fortuna, ENCOG si occupa della normalizzazione e denormalizzazione, quindi non è necessario implementarla. Se sei curioso di sapere come funziona, puoi analizzare il seguente codice:

/**
         * Normalize the specified value.
         * @param value The value to normalize.
         * @return The normalized value.
         */
        public static double normalize(final int value) {
                return ((value - INPUT_LOW) 
                                / (INPUT_HIGH - INPUT_LOW))
                                * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW;
        }
        
        /**
         * De-normalize the specified value.
         * @param value The value to denormalize.
         * @return The denormalized value.
         */
        public static double deNormalize(final double data) {
                double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH
                                * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW)
                                / (OUTPUT_LOW - OUTPUT_HIGH);
                return result;
        }

e leggere un articolo sulla normalizzazione per ulteriori dettagli. 

 

5. Scelta dell'architettura di rete e del numero di neuroni

Per un principiante in materia, la scelta dell'architettura di rete corretta è una parte difficile. In questo articolo sto limitando l'architettura della rete neurale feedfoward a tre livelli: uno strato di input, uno strato nascosto e uno strato di output. Sei libero di sperimentare con un numero maggiore di livelli.

Per il livello di input e output saremo in grado di contare con precisione il numero di neuroni necessari. Per un livello nascosto cercheremo di ridurre al minimo l'errore della rete neurale utilizzando un algoritmo di selezione diretta. Ti invito a utilizzare altri metodi; potrebbero esserci degli algoritmi genetici per calcolare il numero di neuroni.

Un altro metodo utilizzato da ENCOG è l’algoritmo di selezione in regressione o pruning che, in sostanza, valuta le connessioni tra i livelli e rimuove i neuroni nascosti con connessioni ponderate zero. Potresti anche provarlo.

5.1. Strato di neuroni di input

A causa del timeboxing, il numero di neuroni nel livello di input deve essere uguale al numero di indicatori per il numero di barre utilizzate per prevedere la barra successiva. Se usiamo 3 indicatori come input e la dimensione della finestra di input è pari a 6 barre, il livello di input sarà composto da 18 neuroni. Il livello di input viene alimentato con i dati preparati dal timeboxing.

5.2. Strato di neuroni nascosti

Il numero di reti nascoste deve essere stimato in base alle prestazioni della rete neurale addestrata. Non esiste un'equazione matematica semplice per un numero di neuroni nascosti. Prima di scrivere l'articolo, ho utilizzato diversi approcci per tentativi ed errori e ho trovato un algoritmo sul sito di Heaton Research che aiuta a comprendere l'algoritmo di selezione in avanti:

Figura 6. Algoritmo di selezione diretta per il numero di neuroni nascosti  

Figura 6. Algoritmo di selezione in avanti per il numero di neuroni nascosti 

5.3. Strato di neuroni di uscita

Per i nostri scopi, il numero di neuroni di output è il numero di barre che stiamo cercando di prevedere. Ricorda che maggiore è il numero di neuroni nascosti e di output, più tempo impiega la rete per l'addestramento. In questo articolo sto cercando di prevedere una barra in futuro, quindi il livello di output è costituito da un neurone.

 

6. Esportazione dei dati di addestramento da MetaTrader 5 a ENCOG

Encog accetta file CSV per l'addestramento della rete neurale.

Ho esaminato il formato del file esportato da altri software di trading a ENCOG e ho implementato lo script MQL5 che prepara lo stesso formato di file per l'addestramento. Lo presenterò inizialmente esportando un indicatore e continuerò poi con più indicatori. 

La prima riga di dati è un'intestazione separata da virgole:

DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3

Le prime tre colonne contengono i valori di data, ora e chiusura, mentre le colonne successive contengono i nomi degli indicatori. Le righe successive del file di addestramento devono contenere dati separati da virgole e i valori degli indicatori devono essere scritti in formato scientifico:  

20110103,0000,0.93377000,-7.8970208860e-002

Osserva lo script già pronto per l’indicatore riportato di seguito.

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 400;
extern int  maPeriod = 210;

MqlRates srcArr[];
double expBullsArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(expBullsArr, true);      
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hBullsPower = iBullsPower(Symbol(), Period(), maPeriod);
   
   CopyBuffer(hBullsPower, 0, 0, trainSize, expBullsArr);
   
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,BullsPower\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(expBullsArr[i], -10));
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

 Il file dei risultati che può essere utilizzato per l'addestramento deve essere simile al seguente output: 

DATE,TIME,CLOSE,BullsPower
20110103,0000,0.93377000,-7.8970208860e-002
20110104,0000,0.94780000,-6.4962292188e-002
20110105,0000,0.96571000,-4.7640374727e-002
20110106,0000,0.96527000,-4.4878854587e-002
20110107,0000,0.96697000,-4.6178012364e-002
20110110,0000,0.96772000,-4.2078647318e-002
20110111,0000,0.97359000,-3.6029181466e-002
20110112,0000,0.96645000,-3.8335729509e-002
20110113,0000,0.96416000,-3.7054869514e-002
20110114,0000,0.96320000,-4.4259373120e-002
20110117,0000,0.96503000,-4.4835729773e-002
20110118,0000,0.96340000,-4.6420936126e-002
20110119,0000,0.95585000,-4.6868984125e-002
20110120,0000,0.96723000,-4.2709941621e-002
20110121,0000,0.95810000,-4.1918330800e-002
20110124,0000,0.94873000,-4.7722659418e-002
20110125,0000,0.94230000,-5.7111591557e-002
20110126,0000,0.94282000,-6.2231529077e-002
20110127,0000,0.94603000,-5.9997865295e-002
20110128,0000,0.94165000,-6.0378312069e-002
20110131,0000,0.94414000,-6.2038328069e-002
20110201,0000,0.93531000,-6.0710334438e-002
20110202,0000,0.94034000,-6.1446445012e-002
20110203,0000,0.94586000,-5.2580791504e-002
20110204,0000,0.95496000,-4.5246755566e-002
20110207,0000,0.95730000,-4.4439392954e-002

Tornando all'esempio dell'articolo originale con Stochastic e R di William, dobbiamo esportare tre colonne separate da virgola. Ogni colonna contiene valori di indicatori separati, quindi dobbiamo espandere il file e aggiungere ulteriori buffer:

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 2000;

MqlRates srcArr[];
double StochKArr[], StochDArr[], WilliamsRArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(StochKArr, true);   
   ArraySetAsSeries(StochDArr, true);   
   ArraySetAsSeries(WilliamsRArr, true);
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
   
   CopyBuffer(hStochastic, 0, 0, trainSize, StochKArr);
   CopyBuffer(hStochastic, 1, 0, trainSize, StochDArr);
   CopyBuffer(hWilliamsR, 0, 0, trainSize, WilliamsRArr);
    
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,StochK,StochD,WilliamsR\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), 
                                                 DoubleToString(StochKArr[i], -10),
                                                 DoubleToString(StochDArr[i], -10),
                                                 DoubleToString(WilliamsRArr[i], -10)
                                                 );
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

Il file dei risultati deve avere tutti i valori dell'indicatore:

DATE,TIME,CLOSE,StochK,StochD,WilliamsR
20030707,0000,1.37370000,7.1743119266e+001,7.2390220187e+001,-6.2189054726e-001
20030708,0000,1.36870000,7.5140977444e+001,7.3307139273e+001,-1.2500000000e+001
20030709,0000,1.35990000,7.3831775701e+001,7.3482018082e+001,-2.2780373832e+001
20030710,0000,1.36100000,7.1421933086e+001,7.2795323083e+001,-2.1495327103e+001
20030711,0000,1.37600000,7.5398313027e+001,7.3662986398e+001,-3.9719626168e+000
20030714,0000,1.37370000,7.0955352856e+001,7.2760441884e+001,-9.6153846154e+000
20030715,0000,1.38560000,7.4975891996e+001,7.3498925255e+001,-2.3890784983e+000
20030716,0000,1.37530000,7.5354107649e+001,7.4117319386e+001,-2.2322435175e+001
20030717,0000,1.36960000,7.1775345074e+001,7.3336661282e+001,-3.0429594272e+001
20030718,0000,1.36280000,5.8474576271e+001,6.8382632945e+001,-3.9778325123e+001
20030721,0000,1.35400000,4.3498596819e+001,6.0087954237e+001,-5.4946524064e+001
20030722,0000,1.36130000,2.9036761284e+001,4.9737556586e+001,-4.5187165775e+001
20030723,0000,1.34640000,1.6979405034e+001,3.8818172735e+001,-6.5989159892e+001
20030724,0000,1.34680000,1.0634573304e+001,2.9423639592e+001,-7.1555555556e+001
20030725,0000,1.34400000,9.0909090909e+000,2.2646062758e+001,-8.7500000000e+001
20030728,0000,1.34680000,1.2264922322e+001,1.9185682613e+001,-8.2705479452e+001
20030729,0000,1.35250000,1.4960629921e+001,1.7777331716e+001,-7.2945205479e+001
20030730,0000,1.36390000,2.7553336360e+001,2.1035999930e+001,-5.3979238754e+001
20030731,0000,1.36990000,4.3307839388e+001,2.8459946416e+001,-4.3598615917e+001
20030801,0000,1.36460000,5.6996412096e+001,3.7972101643e+001,-5.2768166090e+001
20030804,0000,1.34780000,5.7070193286e+001,4.4338132191e+001,-8.1833910035e+001
20030805,0000,1.34770000,5.3512705531e+001,4.7396323304e+001,-8.2006920415e+001
20030806,0000,1.35350000,4.4481132075e+001,4.6424592894e+001,-7.1972318339e+001
20030807,0000,1.35020000,3.3740028156e+001,4.2196404648e+001,-7.7681660900e+001
20030808,0000,1.35970000,3.0395426394e+001,3.8262745230e+001,-6.1245674740e+001
20030811,0000,1.35780000,3.4155781326e+001,3.6893757262e+001,-6.4532871972e+001
20030812,0000,1.36880000,4.3488943489e+001,3.9092152671e+001,-4.5501730104e+001
20030813,0000,1.36690000,5.1160443996e+001,4.3114916446e+001,-4.8788927336e+001
20030814,0000,1.36980000,6.2467599793e+001,4.9565810895e+001,-2.5629290618e+001
20030815,0000,1.37150000,6.9668246445e+001,5.6266622745e+001,-2.1739130435e+001
20030818,0000,1.38910000,7.9908906883e+001,6.4147384124e+001,-9.2819614711e+000

Puoi modificare il secondo esempio per produrre facilmente uno script che soddisfi le tue esigenze.


7. Training della rete neurale

L’addestramento della rete è già stata preparata in C# da Heaton Research. ENCOG 2.6 implementa lo spazio dei nomi Encog.App.Quant, una base per la previsione delle serie temporali finanziarie. Lo script di addestramento è molto flessibile e può essere facilmente adattato a qualsiasi numero di indicatori di input. Devi cambiare solo la posizione della directory MetaTrader 5 nella costante DIRECTORY.

L'architettura di rete e i parametri di addestramento possono essere facilmente personalizzati modificando le seguenti variabili:

        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

Il codice è molto esplicativo, quindi la cosa migliore sarà leggerlo attentamente:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Encog.App.Quant.Normalize;
using Encog.Util.CSV;
using Encog.App.Quant.Indicators;
using Encog.App.Quant.Indicators.Predictive;
using Encog.App.Quant.Temporal;
using Encog.Neural.NeuralData;
using Encog.Neural.Data.Basic;
using Encog.Util.Simple;
using Encog.Neural.Networks;
using Encog.Neural.Networks.Layers;
using Encog.Engine.Network.Activation;
using Encog.Persist;

namespace NetworkTrainer
{
    public class Program
    {
        /// <summary>
        /// The directory that all of the files will be stored in.
        /// </summary>
        public const String DIRECTORY = "d:\\mt5\\MQL5\\Files\\";

        /// <summary>
        /// The input file that starts the whole process.  This file should be downloaded from NinjaTrader using the EncogStreamWriter object.
        /// </summary>
        public const String STEP1_FILENAME = DIRECTORY + "mt5export.csv";

        /// <summary>
        /// We apply a predictive future indicator and generate a second file, with the additional predictive field added.
        /// </summary>
        public const String STEP2_FILENAME = DIRECTORY + "step2_future.csv";

        /// <summary>
        /// Next the entire file is normalized and stored into this file.
        /// </summary>
        public const String STEP3_FILENAME = DIRECTORY + "step3_norm.csv";

        /// <summary>
        /// The file is time-boxed to create training data.
        /// </summary>
        public const String STEP4_FILENAME = DIRECTORY + "step4_train.csv";

        /// <summary>
        /// Finally, the trained neural network is written to this file.
        /// </summary>
        public const String STEP5_FILENAME = DIRECTORY + "step5_network.eg";
       
        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

        static void Main(string[] args)
        {
            // Step 1: Create future indicators
            Console.WriteLine("Step 1: Analyze MT5 Export & Create Future Indicators");
            ProcessIndicators ind = new ProcessIndicators();
            ind.Analyze(STEP1_FILENAME, true, CSVFormat.DECIMAL_POINT);
            int externalIndicatorCount = ind.Columns.Count - 3;
            ind.AddColumn(new BestReturn(RESULT_WINDOW,true)); 
            ind.Process(STEP2_FILENAME);          
            Console.WriteLine("External indicators found: " + externalIndicatorCount);
            //Console.ReadKey();

            // Step 2: Normalize
            Console.WriteLine("Step 2: Create Future Indicators");
            EncogNormalize norm = new EncogNormalize();
            norm.Analyze(STEP2_FILENAME, true, CSVFormat.ENGLISH);
            norm.Stats[0].Action = NormalizationDesired.PassThrough; // Date
            norm.Stats[1].Action = NormalizationDesired.PassThrough; // Time
            
            norm.Stats[2].Action = NormalizationDesired.Normalize; // Close
            norm.Stats[3].Action = NormalizationDesired.Normalize; // Stoch K
            norm.Stats[4].Action = NormalizationDesired.Normalize; // Stoch Dd
            norm.Stats[5].Action = NormalizationDesired.Normalize; // WilliamsR
       
            norm.Stats[6].Action = NormalizationDesired.Normalize; // best return [RESULT_WINDOW]

            norm.Normalize(STEP3_FILENAME);

            // neuron counts
            int inputNeurons = INPUT_WINDOW * externalIndicatorCount;
            int outputNeurons = PREDICT_WINDOW;

            // Step 3: Time-box
            Console.WriteLine("Step 3: Timebox");
            //Console.ReadKey();
            TemporalWindow window = new TemporalWindow();
            window.Analyze(STEP3_FILENAME, true, CSVFormat.ENGLISH);
            window.InputWindow = INPUT_WINDOW;
            window.PredictWindow = PREDICT_WINDOW;
            int index = 0;
            window.Fields[index++].Action = TemporalType.Ignore; // date
            window.Fields[index++].Action = TemporalType.Ignore; // time
            window.Fields[index++].Action = TemporalType.Ignore; // close
            for(int i=0;i<externalIndicatorCount;i++)
                window.Fields[index++].Action = TemporalType.Input; // external indicators
            window.Fields[index++].Action = TemporalType.Predict; // PredictBestReturn

            window.Process(STEP4_FILENAME);

            // Step 4: Train neural network
            Console.WriteLine("Step 4: Train");
            Console.ReadKey();
            INeuralDataSet training = (BasicNeuralDataSet)EncogUtility.LoadCSV2Memory(STEP4_FILENAME, inputNeurons, 
                                                                                      outputNeurons, true, CSVFormat.ENGLISH);

            BasicNetwork network = new BasicNetwork();
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, inputNeurons));
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, HIDDEN1_NEURONS));
            network.AddLayer(new BasicLayer(new ActivationLinear(), true, outputNeurons));
            network.Structure.FinalizeStructure();
            network.Reset();

            //EncogUtility.TrainToError(network, training, TARGET_ERROR);
            EncogUtility.TrainConsole(network, training, 3);

            // Step 5: Save neural network and stats
            EncogMemoryCollection encog = new EncogMemoryCollection();
            encog.Add("network", network);
            encog.Add("stat", norm.Stats);
            encog.Save(STEP5_FILENAME);
            Console.ReadKey();
        }
    }
}

Potresti notare che ho commentato una riga e ho cambiato la funzione di addestramento da EncogUtility.TrainToError() a EncogUtility.TrainConsole()

EncogUtility.TrainConsole(network, training, 3);

Il metodo TrainConsole specifica un numero di minuti per l'addestramento della rete. Nell'esempio addestro la rete per tre minuti. A seconda della complessità della rete e delle dimensioni dei dati di addestramento, l'addestramento della rete può richiedere alcuni minuti, ore o addirittura giorni. Consiglio di leggere di più su calcolo degli errori e addestramento degli algoritmi sul sito web di Heaton Research o su qualsiasi altro libro sull'argomento.

I metodi EncogUtility.TrainToError() interrompono l'addestramento della rete dopo che è stato raggiunto un errore di rete di destinazione. Puoi commentare EncongUtiliy.TrainConsole() e decommentare EncogUtility.TrainToError() per addestrare la rete fino a un errore desiderato come nell'esempio originale 

EncogUtility.TrainToError(network, training, TARGET_ERROR);

Da notare che a volte la rete non può essere addestrata a un certo errore perché il numero di neuroni potrebbe essere troppo piccolo.


8. Utilizzo della rete neurale addestrata per costruire l'indicatore neurale MetaTrader 5

La rete addestrata può essere utilizzata da un indicatore di rete neurale che cercherà di prevedere il miglior ritorno sull'investimento.

L'indicatore neurale ENCOG per MetaTrader 5 è costituito da due parti. Una parte è scritta con MQL5 e fondamentalmente prende gli stessi indicatori di quelli con cui la rete è stata addestrata e alimenta la rete con i valori degli indicatori della finestra di input. La seconda parte è scritta con C# e archivia i dati di input e restituisce l'output della rete neurale a MQL5. La parte dell'indicatore C# si basa sul mio precedente articolo sull'esposizione del codice C# a MQL5.

using System;
using System.Collections.Generic;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using Encog.Neural.Networks;
using Encog.Persist;
using Encog.App.Quant.Normalize;
using Encog.Neural.Data;
using Encog.Neural.Data.Basic;

namespace EncogNeuralIndicatorMT5DLL
{

    public class NeuralNET
    {
        private EncogMemoryCollection encog;
        public BasicNetwork network;
        public NormalizationStats stats;

        public NeuralNET(string nnPath)
        {
            initializeNN(nnPath);
        }

        public void initializeNN(string nnPath)
        {
            try
            {
                encog = new EncogMemoryCollection();
                encog.Load(nnPath);
                network = (BasicNetwork)encog.Find("network");
                stats = (NormalizationStats)encog.Find("stat");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }
    };

   class UnmanagedExports
   {

      static NeuralNET neuralnet; 

      [DllExport("initializeTrainedNN", CallingConvention = CallingConvention.StdCall)]
      static int initializeTrainedNN([MarshalAs(UnmanagedType.LPWStr)]string nnPath)
      {
          neuralnet = new NeuralNET(nnPath);

          if (neuralnet.network != null) return 0;
          else return -1;
      }

      [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                           int len, 
                                           [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                           int rates_total)
      {
          INeuralData input = new BasicNeuralData(3 * len);
          
          int index = 0;
          for (int i = 0; i <len; i++)
          {
              input[index++] = neuralnet.stats[3].Normalize(t1[i]);
              input[index++] = neuralnet.stats[4].Normalize(t2[i]);
              input[index++] = neuralnet.stats[5].Normalize(t3[i]);
          }

          INeuralData output = neuralnet.network.Compute(input);
          double d = output[0];
          d = neuralnet.stats[6].DeNormalize(d);        
          result[rates_total-1]=d;

          return 0;
      }  
   }
}

Se desideri utilizzare un numero di indicatori diverso da tre, devi modificare il metodo computeNNIndicator() in base alle tue esigenze. 

 [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                         int len, 
                                         [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                         int rates_total)

In questo caso, i primi tre parametri di input sono tabelle che contengono i valori di input dell'indicatore, il quarto parametro è la lunghezza della finestra di input.

SizeParamIndex = 3 punti alla variabile di lunghezza della finestra di input, poiché il conteggio delle variabili di input viene aumentato da 0 in poi. Il quinto parametro è una tabella che contiene i risultati della rete neurale. 

La parte dell'indicatore MQL5 deve importare un C# EncogNNTrainDLL.dll e utilizzare le funzioni initializeTrainedNN() e computeNNIndicator() esportate dalla dll.

//+------------------------------------------------------------------+
//|                                         NeuralEncogIndicator.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
#property indicator_separate_window

#property indicator_plots 1
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1  2

#import "EncogNNTrainDLL.dll"
   int initializeTrainedNN(string nnFile);
   int computeNNIndicator(double& ind1[], double& ind2[],double& ind3[], int size, double& result[], int rates);  
#import


int INPUT_WINDOW = 6;
int PREDICT_WINDOW = 1;

double ind1Arr[], ind2Arr[], ind3Arr[]; 
double neuralArr[];

int hStochastic;
int hWilliamsR;

int hNeuralMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, neuralArr, INDICATOR_DATA);
   
   PlotIndexSetInteger(0, PLOT_SHIFT, 1);

   ArrayResize(ind1Arr, INPUT_WINDOW);
   ArrayResize(ind2Arr, INPUT_WINDOW);
   ArrayResize(ind3Arr, INPUT_WINDOW);
     
   ArrayInitialize(neuralArr, 0.0);
   
   ArraySetAsSeries(ind1Arr, true);   
   ArraySetAsSeries(ind2Arr, true);  
   ArraySetAsSeries(ind3Arr, true);
  
   ArraySetAsSeries(neuralArr, true);   
               
   hStochastic = iStochastic(NULL, 0, 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   hWilliamsR = iWPR(NULL, 0, 21);
 
   Print(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
   initializeTrainedNN(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
      
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
   int calc_limit;
   
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
        calc_limit=rates_total-34; 
   else calc_limit=rates_total-prev_calculated;
    
   ArrayResize(neuralArr, rates_total);
  
   for (int i=0; i<calc_limit; i++)     
   {
      CopyBuffer(hStochastic, 0, i, INPUT_WINDOW, ind1Arr);
      CopyBuffer(hStochastic, 1, i, INPUT_WINDOW, ind2Arr);
      CopyBuffer(hWilliamsR,  0, i, INPUT_WINDOW, ind3Arr);    
      
      computeNNIndicator(ind1Arr, ind2Arr, ind3Arr, INPUT_WINDOW, neuralArr, rates_total-i); 
   }
     
  //Print("neuralArr[0] = " + neuralArr[0]);
  
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Consulta l'output dell'indicatore addestrato sui dati giornalieri USDCHF, Stochastic e R di Williams:

 Figura 7. Indicatore Neural Encog

Figura 7. Indicatore di codifica neurale

L'indicatore mostra il ritorno migliore sull'investimento previsto sulla barra successiva.

Potresti aver notato che ho spostato l'indicatore di una barra nel futuro:

PlotIndexSetInteger(0, PLOT_SHIFT, 1);

Questo per indicare che l'indicatore è predittivo. Poiché abbiamo costruito un indicatore neurale, siamo pronti a creare un Expert Advisor basato sull'indicatore.


9. Expert Advisor basato su un indicatore neurale

L'Expert Advisor prende l'output dell'indicatore neurale e decide se acquistare o vendere un titolo. La mia prima impressione è stata che deve acquistare ogni volta che l'indicatore è sopra lo zero e vendere quando è sotto lo zero, il che significa acquistare quando la migliore previsione di rendimento in una determinata finestra temporale è positiva e vendere quando la migliore previsione di rendimento è negativa.

Dopo alcuni test iniziali, si è scoperto che la performance potrebbe essere migliore, quindi ho introdotto le variabili "forte trend rialzista" e "forte trend ribassista", il che significa che non c'è motivo di uscire dal trading quando siamo in una forte tendenza secondo la famoso regola del "il trend ti è amico".

Inoltre, mi è stato consigliato sul forum di Heaton Research di utilizzare l'ATR per spostare gli stop loss, quindi ho usato l'indicatore ATR di Chandelier che ho trovato sul forum MQL5. Questo ha effettivamente aumentato il guadagno di equità durante il backtest. Incollo il codice sorgente dell'Expert Advisor di seguito.

//+------------------------------------------------------------------+
//|                                           NeuralEncogAdvisor.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

double neuralArr[];

double trend;
double Lots=0.3;

int INPUT_WINDOW=8;

int hNeural,hChandelier;

//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArrayResize(neuralArr,INPUT_WINDOW);
   ArraySetAsSeries(neuralArr,true);
   ArrayInitialize(neuralArr,0.0);

   hNeural=iCustom(Symbol(),Period(),"NeuralEncogIndicator");
   Print("hNeural = ",hNeural,"  error = ",GetLastError());

   if(hNeural<0)
     {
      Print("The creation of ENCOG indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("ENCOG indicator initialized");

   hChandelier=iCustom(Symbol(),Period(),"Chandelier");
   Print("hChandelier = ",hChandelier,"  error = ",GetLastError());

   if(hChandelier<0)
     {
      Print("The creation of Chandelier indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("Chandelier indicator initialized");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(),0,0,1,tickCnt);
   if(tickCnt[0]==1)
     {
      if(!CopyBuffer(hNeural,0,0,INPUT_WINDOW,neuralArr)) { Print("Copy1 error"); return; }

      // Print("neuralArr[0] = "+neuralArr[0]+"neuralArr[1] = "+neuralArr[1]+"neuralArr[2] = "+neuralArr[2]);
      trend=0;

      if(neuralArr[0]<0 && neuralArr[1]>0) trend=-1;
      if(neuralArr[0]>0 && neuralArr[1]<0) trend=1;

      Trade();
     }
  }
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---

//---
   return(0.0);
  }
//+------------------------------------------------------------------+

void Trade()
  {
   double bufChandelierUP[2];
   double bufChandelierDN[2];

   double bufMA[2];

   ArraySetAsSeries(bufChandelierUP,true);
   ArraySetAsSeries(bufChandelierUP,true);

   ArraySetAsSeries(bufMA,true);

   CopyBuffer(hChandelier,0,0,2,bufChandelierUP);
   CopyBuffer(hChandelier,1,0,2,bufChandelierDN);

   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,3,rates);

   bool strong_uptrend=neuralArr[0]>0 && neuralArr[1]>0 && neuralArr[2]>0 &&
                      neuralArr[3]>0 && neuralArr[4]>0 && neuralArr[5]>0 &&
                       neuralArr[6]>0 && neuralArr[7]>0;
   bool strong_downtrend=neuralArr[0]<0 && neuralArr[1]<0 && neuralArr[2]<0 &&
                        neuralArr[3]<0 && neuralArr[4]<0 && neuralArr[5]<0 &&
                        neuralArr[6]<0 && neuralArr[7]<0;

   if(PositionSelect(_Symbol))
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;

      if((type==POSITION_TYPE_BUY) && (trend==-1))

         if(!(strong_uptrend) || (bufChandelierUP[0]==EMPTY_VALUE)) close=true;
      if((type==POSITION_TYPE_SELL) && (trend==1))
         if(!(strong_downtrend) || (bufChandelierDN[0]==EMPTY_VALUE))
            close=true;
      if(close)
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
      else // adjust s/l
        {
         CTrade trade;

         if(copied>0)
           {
            if(type==POSITION_TYPE_BUY)
              {
               if(bufChandelierUP[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierUP[0],0.0);
              }
            if(type==POSITION_TYPE_SELL)
              {
               if(bufChandelierDN[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierDN[0],0.0);
              }
           }
        }
     }

   if((trend!=0) && (!PositionSelect(_Symbol)))
     {
      CTrade trade;
      MqlTick tick;
      MqlRates rates[];
      ArraySetAsSeries(rates,true);
      int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,INPUT_WINDOW,rates);

      if(copied>0)
        {
         if(SymbolInfoTick(_Symbol,tick)==true)
           {
            if(trend>0)
              {
               trade.Buy(Lots,_Symbol,tick.ask);
               Print("Buy at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
            if(trend<0)
              {
               trade.Sell(Lots,_Symbol,tick.bid);
               Print("Sell at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
           }
        }
     }

  }
//+------------------------------------------------------------------+

L'Expert Advisor è stato eseguito su dati D1 valuta USDCHF. Circa il 50% dei dati era out of sample per l’addestramento.


10. Risultati di backtesting sull’Expert Advisor

Incollo i risultati del backtest di seguito. Il backtest è stato eseguito dal 01.01.2000 al 26.03.2011.

Figura 8. Risultati di backtesting dell’Expert Advisor neurale

Figura 8. Risultati di backtesting dell’Expert Advisor neurale

Figura 9. Grafico di backtesting Balance/Equity dell’Expert Advisor neurale

Figura 9. Grafico di backtesting Balance/Equity dell’Expert Advisor neurale

Da notare che questa performance potrebbe essere totalmente diversa per altri periodi di tempo e altri titoli.

Ti chiedo di trattare questo EA come educativo e renderlo un punto di partenza per ulteriori ricerche. La mia opinione personale è che la rete potrebbe essere riqualificata durante ogni certo periodo di tempo per renderla più robusta. Forse qualcuno lo farà o ha già trovato un buon modo per raggiungere questo obiettivo. Forse c'è un modo migliore per fare previsioni di acquisto/vendita basate su un indicatore neurale. Incoraggio i lettori a sperimentare.


Conclusione

Nel seguente articolo ho presentato un modo per costruire un indicatore predittivo neurale e un Expert Advisor basato su tale indicatore con l'aiuto del framework di apprendimento automatico ENCOG. Il codice sorgente, i binari compilati, le DLL e una rete addestrata esemplare sono allegati all'articolo.


A causa del "doppio wrapping della DLL in .NET", i file Cloo.dll, encog-core-cs.dll e log4net.dll devono trovarsi nella cartella del client terminal.
Il file EncogNNTrainDLL.dll deve trovarsi nella cartella \Terminal Data folder\MQL5\Libraries\.


Tradotto dall’inglese da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/en/articles/252

File allegati |
encogcsharp.zip (2202.77 KB)
files.zip (270.14 KB)
libraries.zip (321.62 KB)
experts.zip (1.56 KB)
scripts.zip (1.03 KB)
indicators.zip (2.24 KB)
Utilizzo di pseudo-modelli come alternativa ai modelli C++ Utilizzo di pseudo-modelli come alternativa ai modelli C++
L'articolo descrive un modo per programmare senza usare i modelli, ma mantenendo lo stile di programmazione inerente ad essi. L’articolo parla dell'implementazione dei modelli utilizzando metodi personalizzati e ha uno script già pronto allegato per la creazione di un codice sulla base di modelli specificati.
Modello di regressione universale per la previsione dei prezzi di mercato Modello di regressione universale per la previsione dei prezzi di mercato
Il prezzo di mercato è formato da un equilibrio stabile tra domanda e offerta che, a sua volta, dipende da una varietà di fattori economici, politici e psicologici. Le differenze di natura e le cause di influenza di questi fattori rendono difficile considerare direttamente tutti i componenti. Questo articolo espone un tentativo di prevedere il prezzo di mercato sulla base di un modello di regressione elaborato.
Il ruolo delle distribuzioni statistiche nel lavoro del trader Il ruolo delle distribuzioni statistiche nel lavoro del trader
Questo articolo è una continuazione logica del mio articolo Statistical Probability Distributions in MQL5 che espone le classi per lavorare con alcune distribuzioni statistiche teoriche. Ora che abbiamo una base teorica, suggerisco di procedere direttamente a set di dati reali e provare a fare un uso informativo di questa base.
Esposizione del codice C# in MQL5 utilizzando esportazioni non gestite Esposizione del codice C# in MQL5 utilizzando esportazioni non gestite
In questo articolo ho presentato diversi metodi di interazione tra il codice MQL5 e il codice gestito C#. Ho anche fornito diversi esempi su come eseguire il marshalling di strutture MQL5 contro C# e come richiamare le funzioni DLL esportate negli script MQL5. Credo che gli esempi forniti possano servire come base per ricerche future sulla scrittura di DLL nel codice gestito. Questo articolo apre anche le porte a MetaTrader per utilizzare le tante librerie che sono già implementate in C#.