Praktische Anwendung von Neuronalen Netzen im Handel (Teil 2). Computerbilder

Andrey Dibrov | 10 März, 2021

Einführung

Ein wesentliches Problem bei der Vorbereitung der Daten für das Training der Neuronalen Netze, die für den Handel bestimmt sind, ist mit der Vorbereitung der notwendigen Eingangsdaten verbunden. Betrachten wir zum Beispiel den Fall, dass wir ein Dutzend Indikatoren verwenden. Diese Indikatoren können einen Satz von mehreren informativen Charts darstellen. Wenn wir diese Indikatoren bis zu einer gewissen Tiefe berechnen, dann erhalten wir als Ergebnis bis zu hundert Einträge, und in manchen Fällen sogar mehr. Können wir das Training von Neuronalen Netzwerken durch den Einsatz von Computerbilder vereinfachen? Um dieses Problem zu lösen, sollten wir Convolutional Neuronale Netzwerke verwenden, die oft zur Lösung von Klassifizierungs- und Erkennungsproblemen eingesetzt werden.


Architektur eines Convolutional Neuronalen Netzwerks

In diesem Artikel wird ein Convolutional Neuronales Netzwerk verwendet. Seine Architektur ist in der folgenden Abbildung dargestellt. Dieses Schema zeigt das allgemeine Prinzip zur Konstruktion eines Convolutional Neural Network (CNN)

In diesem Fall haben wir:

  1. CNN-Eingabe, die ein Bild der Größe 449x449 Pixel ist.
  2. Die erste Convolutional-Schicht aus 96 Merkmalskarten (maps). Jede Karte ist ein Bild der Größe 447x447. Convolutional-Kernel 3x3.
  3. Subsample-Schicht von 96 Merkmalskarten mit einer Größe von 223x223, mit einem Kernel 2x2.
  4. Zweite Convolutional-Schicht mit 32 Merkmalskarten. Jede Karte ist ein Bild der Größe 221x221. Convolutional-Kernel 3x3.
  5. Subsample-Schicht von 32 Merkmalskarten mit einer Größe von 110x110, mit einem Kernel 2x2.
  6. Dritte Convolutional-Schicht mit 16 Merkmalskarten. Jede Karte ist ein Bild der Größe 108x108. Convolutional-Kernel 3x3.
  7. Subsample-Schicht von 16 Merkmalskarten mit einer Größe von 54x54, mit einem Kernel 2x2. In der Abbildung nicht dargestellt.
  8. Vollverknüpfte Schicht mit 64 Neuronen.
  9. Ausgangsschicht aus einem Neuron. Diese beiden Schichten stellen die Klassifikationseinheit dar.

Wenn Sie neu im Bereich der Convolutional Neuronalen Netze sind, machen Sie sich keine Sorgen über die scheinbare Schwerfälligkeit und Komplexität der Konstruktion. Ein Neuronales Netz einer bestimmten Architektur wird automatisch aufgebaut. Sie müssen nur die wichtigsten Parameter einstellen. 

Vorbereiten eines Arrays von Bildern für das Training und Testen eines Neuronalen Netzwerks

Bevor Sie ein Array von Bildern vorbereiten, definieren Sie den Zweck Ihres Neuronalen Netzwerks. Ideal wäre es, das Netzwerk auf Pivots zu trainieren. Diesem Zweck entsprechend müssten wir Screenshots mit dem letzten extremen Balken erstellen. Dieses Experiment hat jedoch keinen praktischen Wert. Deshalb werden wir einen anderen Satz von Bildern verwenden. Weiterhin können Sie mit verschiedenen Arrays experimentieren, auch mit dem oben genannten. Dies kann auch zusätzliche Beweise für die Effizienz von Neuronalen Netzwerken bei der Lösung von bildbasierten Klassifizierungsaufgaben liefern. Die Antworten des Neuronalen Netzes, die auf eine kontinuierliche Zeitreihe erhalten werden, erfordern eine zusätzliche Optimierung. 

Lassen Sie uns das Experiment nicht verkomplizieren und uns auf zwei Kategorien von Bildern konzentrieren:

Kaufen   Buy1  Buy2  Buy3

Zu Trainingszwecken des Neuronalen Netzes wird die Bewegung in eine beliebige Richtung als das Erreichen neuer Extremwerte in Trendrichtung durch den Preis bestimmt. Zu diesen Momenten werden Chart-Screenshots erstellt. Der Moment der Trendumkehr ist ebenfalls wichtig für das Training des Netzwerks. Ein Chart-Screenshot wird auch erstellt, wenn der Preis das Tageshoch oder -tief erreicht.

Bevor wir mit der Arbeit beginnen, müssen wir das Aussehen des Charts vorbereiten. Verwenden Sie die Vorlage CNN.tpl. Speichern Sie sie in \AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Profiles\Templates.

CNN.tpl

Definieren Sie den Text in den Diagrammeigenschaften als "Weiß".

CNN.tpl


Sie können auch beliebige andere Indikatoren anhängen. Ich habe diese Indikatoren willkürlich gewählt. Es ist auch empfehlenswert, eine optimale Chartgröße entsprechend Ihrer Hardwarefähigkeiten zu finden.

Verwenden Sie das folgende Skript zum Erstellen eines Arrays von Bildern.

//+------------------------------------------------------------------+
//|                                                        CNNet.mq5 |
//|                                   Copyright 2021, Andrey Dibrov. |
//|                           https://www.mql5.com/en/users/tomcat66 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Andrey Dibrov."
#property link      "https://www.mql5.com/en/users/tomcat66"
#property version   "1.00"
#property strict
#property script_show_inputs

input string Date="2017.01.02 00:00";
input string DateOut="2018.12.13 23:00";
input string DateTest="2019.01.02 00:00";
input string Dataset="Train";

string Date1;
int count,countB,countS;
int day;
double DibMin;
double DibMax;
int HandleDate;
long WIDTH;
long HEIGHT;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   MqlDateTime stm;
   ChartSetInteger(0,CHART_SHIFT,false);
   ChartSetInteger(0,CHART_AUTOSCROLL,false);
   ChartSetInteger(0,CHART_SHOW_OBJECT_DESCR,false);
   WIDTH=ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);
   ChartSetInteger(0,CHART_SHOW_PRICE_SCALE,false);

   if(Dataset=="Test")
     {
      HandleDate=FileOpen(Symbol()+"Date.csv",FILE_CSV|FILE_READ|FILE_WRITE|FILE_ANSI,";");
      ChartNavigate(0,CHART_END,-(iBarShift(NULL,PERIOD_H1,StringToTime(DateTest))));
      Sleep(1000);

      for(int i=iBarShift(NULL,PERIOD_H1,StringToTime(DateTest)); i>0; i--)
        {
         Date1=TimeToString(iTime(NULL,PERIOD_H1,i));
         if(DateTest<=Date1)
           {
            if(ChartNavigate(0,CHART_END,-i))
              {
               Sleep(20);
               if(ChartScreenShot(0, (string)count + ".png", (int)WIDTH, (int)WIDTH, ALIGN_LEFT))
                 {
                  FileWrite(HandleDate,TimeToString(iTime(NULL,PERIOD_H1,i)));
                  count++;
                  Sleep(20);
                 }
              }
           }
        }
     }
   if(Dataset=="Train")
     {
      ChartNavigate(0,CHART_END,-iBarShift(NULL,PERIOD_H1,StringToTime(Date)));
      Sleep(1000);
      for(int i=iBarShift(NULL,PERIOD_H1,StringToTime(Date)); i>=iBarShift(NULL,PERIOD_H1,StringToTime(DateOut)); i--)
        {
         TimeToStruct(iTime(NULL,PERIOD_H1,i),stm);
         Date1=TimeToString(iTime(NULL,PERIOD_H1,i));
         if(DateOut>=Date1 && Date<=Date1)
           {
            if(ChartNavigate(0,CHART_END,-i))
              {
               Sleep(20);
               if(day != stm.day)
                 {
                  FileCopy("Sell" + (string)countS + ".png", 0, "Buy" + (string)(countB+1) + ".png", FILE_REWRITE);
                  FileDelete("Sell" + (string)countS + ".png", 0);
                  FileCopy("Buy" + (string)countB + ".png", 0, "Sell" + (string)(countS+1) + ".png", FILE_REWRITE);
                  FileDelete("Buy" + (string)countB + ".png", 0);
                  countB ++;
                  countS ++;
                 }
               day = stm.day;
               if(stm.hour == 0)
                 {
                  DibMin = iOpen(NULL, PERIOD_H1, i);
                  DibMax = iOpen(NULL, PERIOD_H1, i);
                 }
               if(iLow(NULL, PERIOD_H1, i+1) < DibMin)
                 {
                  DibMin = iLow(NULL, PERIOD_H1, i+1);
                  countS ++;
                  ChartScreenShot(0, "Sell" + (string)countS + ".png", (int)WIDTH, (int)WIDTH, ALIGN_LEFT);
                 }
               if(iHigh(NULL, PERIOD_H1, i+1) > DibMax)
                 {
                  DibMax = iHigh(NULL, PERIOD_H1, i+1);
                  countB ++;
                  ChartScreenShot(0, "Buy"  +(string)countB + ".png", (int)WIDTH, (int)WIDTH, ALIGN_LEFT);
                 }
               Sleep(20);
              }
           }
         else
            break;
        }
     }
  }

Das Skript arbeitet in zwei Modi: "Train" - erstellt ein Array von Bildern für das Training, und "Test" - erstellt ein Array von Bildern für den Erhalt von Antworten des Neuronalen Netzes, auf deren Basis ein Indikator generiert wird. Dieser Indikator wird dann für die Optimierung der Handelsstrategie verwendet. 

Lassen Sie das Skript im Modus "Train" laufen.

Train

Variable "Date" — Anfangsdaten für die Stichprobe, in der Bilder für das Training ausgewählt werden. "DateOut" — das Enddatum des Stichprobenzeitraums, in dem Bilder für das Training ausgewählt werden. "DateTest" — das Startdatum für die Auswahl von Bildern, um stündliche Antworten des Neuronalen Netzes zu erhalten. Das Enddatum ist die Startstunde des Skripts. 

Eine Reihe von Kauf- (Buy..) und Verkaufsbildern (Sell..) wird im Ordner ...\MQL5\Files des Datenverzeichnisses gespeichert. Die Gesamtzahl der Bilder beträgt 6125.

Tren

Bereiten Sie als Nächstes Verzeichnisse für das Trainings-, Validierungs- und Testset vor. Legen Sie der Einfachheit halber den Ordner "CNN" auf dem Desktop an, und erstellen Sie darin drei Ordner - "Train", "Val", "Test".

CNN

Erstellen Sie in den Verzeichnissen "Train" und "Val" die Unterverzeichnisse "Buy" und "Sell". Legen Sie in "Test" das Unterverzeichnis "Resp" an.

Train

Schneiden Sie aus dem Ordner ...\MQL5\Files alle Dateien "Buy..." aus und fügen Sie sie in ...\Train\Buy ein. Es sind 3139 Bilder. Wiederholen Sie das Gleiche für "Sell..." und fügen Sie sie in ...\Train\Sell ein. Hier sind es 2986 Bilder. Verschieben Sie aus den Ordnern "Buy" und "Sell" 30 % der letzten (mit den höchsten Zahlen) Bilder in die entsprechenden Unterordner unter "Val" ein.

Was wir jetzt haben 

Wir haben eine Reihe von Bildern für das Training des Netzwerks vorbereitet. Ich habe Bilder der Größe 449x449 Pixel.

Bereiten Sie eine Reihe von Bildern zum Testen vor. Führen Sie das Skript im Modus "Test" aus.

Test

Eine Reihe von aufeinanderfolgenden stündlichen Screenshots wird in ...\MQL5\Dateien gespeichert. Jetzt sind es 12558. Trennen oder gruppieren Sie sie nicht, da das Neuronale Netz diese Gruppierung selbst vornehmen sollte. Genauer gesagt, sollte das Netz die Wahrscheinlichkeit anzeigen, dass ein Bild den Bedingungen entspricht, unter denen das Netz trainiert wurde. Aufwärts bewegen und abwärts umkehren. Abwärts bewegen und nach oben drehen. 

Verschieben Sie diese Dateien in ...CNN\Test\Resp ein.

Test

Wir haben eine Reihe von Bildern vorbereitet, um die Antworten zu testen und die Strategie zu optimieren. Die Dateien mit Datum und Uhrzeit EURUSDDate, die unter ...\MQL5\Files verbleiben, sollten in den CNN-Ordner verschoben werden.

Ich möchte auf eine Besonderheit des MetaTrader 5 hinweisen. Es wäre bequemer und zuverlässiger, eine Reihe von Bildern mit Hilfe eines Expert Advisors im Strategietester vorzubereiten. MetaTrader 5 bietet jedoch nicht die Möglichkeit, Screenshots im Strategietester zu erstellen. Wie auch immer, diese spezielle Funktion hat keinen Einfluss auf die Erstellung von Handelsrobotern.


Training des Neuronalen Netzes

Wir werden mit Convolutional Netzen unter Verwendung der Anaconda-Umgebung arbeiten. Sie sollte so konfiguriert sein, dass sie mit CPU und GPU (wenn Sie eine NVIDIA-Grafikkarte haben) arbeitet. Diese Grafikkarte wird benötigt, um den Lernprozess zu beschleunigen. Sie bringt zwar einige Einschränkungen bei der Erstellung der Architektur des Neuronalen Netzes mit sich - Abhängigkeit von der Größe des Arbeitsspeichers der Grafikkarte. Aber die Lerngeschwindigkeit wird deutlich erhöht. In meinem Fall dauert zum Beispiel eine Trainingsepoche auf einer CPU 20 Minuten, auf einer GPU dauert es 1-2 Minuten. Wenn das Netzwerk auf 40 Epochen trainiert wird, dann würde ich 13 und 1,5 Stunden benötigen. Die Verwendung von GPU kann den Suchprozess für Neuronale Netze im Forschungsstadium erheblich beschleunigen.

  1. Laden und installieren Sie die neueste Version von Anaconda Navigator. Verwenden Sie bei allen Schritten die Standardeinstellungen.
  2. Starten Sie "Anaconda Prompt" über das Menü "Start\Anaconda3".
  3. Führen Sie den Befehl "pip install tensorflow" aus. Installieren Sie die Programmbibliothek fürmachine learning developed by Google entwickelt wurde.
    tensorflow

  4. Führen Sie den Befehl "pip install keras" aus. Installieren Sie die Bibliothek für Neuronale Netze von Keras.
    keras

  5. Erstellen Sie eine neue "conda"-Umgebung unter GPU. Geben Sie den Befehl conda create --name PythonGPU ein. Aktivieren Sie die Umgebung - activate PythonGPU.  GPU

  6. Um tensorflow gpu zu installieren, geben Sie den Befehl conda create -n PythonGPU python=3.6 tensorflow-gpu ein. Bitte beachten Sie, dass tensorflow gpu für Python 3.6 installiert sein sollte
    .   tensorflow gpu

  7. Um keras gpu zu installieren, geben Sie den Befehl conda install -c anaconda keras-gpu ein.
    keras gpu

  8. Installieren Sie die Jupyter-Schnittstelle für die Programmierung in der Python-GPU-Umgebung. CPU Jupyter wurde bereits während der Installation von Anaconda installiert. Geben Sie den Befehl - conda install jupyter ein.  Jupyter

  9. Installieren Sie zwei weitere Bibliotheken, Pandas und Pillow - conda install -c anaconda pandas. Dann - conda install pillow. Diese Bibliotheken sollten auch für die CPU installiert werden, wenn Sie keine Grafikkarte verwenden wollen.
    pandas 

  10. pillow

  11. Wir können nun mit dem Training unseres Convolutional Neuronalen Netzes beginnen. Fügen Sie dem zuvor erstellten CNN-Ordner zwei Dateien hinzu: Train.ipynb und Test.ipynb. Dies sind Dateien im Format von Jupyter Notebook, mit denen wir arbeiten werden. Starten Sie Jupyter Notebook (PythonGPU) und öffnen Sie die Datei Train.  CNN  

Betrachten wir nun jeden Block des Programmcodes.

Laden Sie zunächst die notwendigen Module der Bibliotheken des Neuronalen Netzes.

from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Conv2D, MaxPooling2D
from tensorflow.python.keras.layers import Activation, Dropout, Flatten, Dense
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras.models import load_model

Dann werden die benötigten Hyperparameter festgelegt.

# Directory with data for training
train_dir = 'train'
# Directory with data for validation
val_dir = 'val'
# Image dimensions
img_width, img_height = 449, 449
# Image-based tensor dimension for input to the neural network
# backend Tensorflow, channels_last
input_shape = (img_width, img_height, 3)
# Number of epochs
epochs = 20
# Mini-sample size
batch_size = 7
# Number of images for training
nb_train_samples = 4289
# Number of images for validation
nb_validation_samples = 1836
# Number of images for testing
#nb_test_samples = 3736

Erstellen wir nun die Netzwerkarchitektur.

  • Wir legen die sequentielle Convolutional Neuronale Netz-Architektur fest
  • Das Eingangsbild hat die Größe 449x449 Pixel, dreikanalig (rot, grün und blau). Hier verwenden wir ein Farbbild. Sie können auch ein monochromes Bild ausprobieren
  • Erstellen wir die erste Convolutional-Schicht für die Arbeit mit zweidimensionalen Daten: 96 Merkmalskarten mit je einem eigenen 3x3-Convolutional-Kernel. Jedes Neuron der Convolutional-Schicht ist mit einem 3x3 quadratischen Ausschnitt des Bildes verbunden 
  • Aktivierungsschicht mit der Funktion "relu", die weniger rechenintensiv ist
  • Um die Dimension zu reduzieren, fügen wir eine Subsampling-Schicht mit einem 2x2-Kernel mit der Auswahl des Maximalwertes aus diesem Quadrat hinzu
  • Fügen wir anschließend zwei weitere Convolutional-Schichten mit 32 und 16 Kernen, zwei Aktivierungsschichten und zwei Subsamples hinzu
  • Wir konvertieren die zweidimensionalen Daten in ein eindimensionales Format
  • Die konvertierten Daten werden an die vollverknüpfte Schicht mit 64 Neuronen übergeben
  • Mit der Regularisierungsschichtfunktion Dropout(0.5) versuchen wir eine Überanpassung zu vermeiden
  • Fügen wir eine voll verbundene Ausgabeschicht mit einem Neuron hinzu. Es werden zwei Bildklassen verwendet, so dass die Antwort des Netzwerks als binäre Antwort empfangen wird. Es ist auch möglich, mehrere Klassen zu verwenden. Zum Beispiel zwei für Trend und eine für Seitwärts. In diesem Fall würde die Ausgabeschicht drei Neuronen haben. Außerdem müssten wir die Bilder in drei Klassen einteilen.
  • Die Aktivierungsfunktion "sigmoid". Sie ist gut für die Klassifizierung geeignet und hat bei meinen Experimenten die beste Leistung gezeigt

Dieses Architekturbeispiel lässt sich leicht modernisieren - wir können die Anzahl der Schichten und ihre Größe erhöhen, ihre Position in Abhängigkeit von der Sequenz ändern, die Dimension des Faltungs-Kernels ändern, Aktivierungsfunktionen modifizieren und mit voll verbundenen Schichten arbeiten. Allerdings entsteht hier ein Dilemma: bei der Verwendung einer GPU ist es notwendig, den Arbeitsspeicher einer Grafikkarte zu erhöhen, falls wir die Architektur eines Neuronalen Netzes vergrößern wollen. Optional sollte die Bildgröße reduziert werden. Andernfalls können wir viel Zeit mit der CPU verbringen.

model = Sequential()
model.add(Conv2D(96, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(16, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))

Kompilieren Sie das Neuronale Netz. Verwenden Sie die Fehlerfunktion: Binär-Crossentropie. In diesem Fall wird eine Antwort verwendet, die aus zwei Klassen besteht, die im Idealfall die Werte 0 oder 1 annehmen sollten. Die tatsächlichen Werte werden jedoch von 0 bis 1 verteilt sein. Wählen Sie den Optimierer "Gradient Descent". Er scheint für das Training des Neuronalen Netzes am besten geeignet zu sein. Wählen Sie die Genauigkeitsmetrik, d. h. den Prozentsatz der richtigen Antworten. 

model.compile(loss='binary_crossentropy',
              optimizer='sgd',
              metrics=['accuracy'])

Normalisierung der Daten nach der Intensität der Bildpixel.

datagen = ImageDataGenerator(rescale=1. / 255)

Verwenden Sie Keras-Generatoren, um Daten von der Festplatte zu lesen und die Trainings- und Validierungsbild-Arrays für das Neuronale Netz zu erstellen. Auch hier ist class_mode 'binary'. Setzen Sie Shuffle auf 'False'. Das Mischen von Bildern ist also deaktiviert.

train_generator = datagen.flow_from_directory(
    train_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='binary',
    shuffle=False)
val_generator = datagen.flow_from_directory(
    val_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='binary',
    shuffle=False)

Die Funktion callbacks speichert das trainierte Neuronale Netz nach jeder Epoche. Dies ermöglicht die Auswahl des am besten geeigneten Netzes in Bezug auf Fehlerwerte und Trefferquote.

callbacks = [ModelCheckpoint('cnn_Open{epoch:1d}.hdf5')]

Fahren Sie nun mit dem Netzwerktraining fort.

model.fit(
    train_generator,
    steps_per_epoch=nb_train_samples // batch_size,
    epochs=epochs,
    validation_data=val_generator,
    validation_steps=nb_validation_samples // batch_size,
    callbacks=callbacks)

12. Lassen Sie das Programm laufen, wie im Bild dargestellt.

Lauf


Wenn die vorherigen Schritte korrekt durchgeführt wurden, beginnt das Neuronale Netz mit dem Lernen.

Fit

Nach dem Ende des Trainingsprozesses erscheinen 20 trainierte Neuronale Netze unter dem Ordner CNN.

CNN

Lassen Sie sich die Trainingsergebnisse anzeigen und wählen Sie ein Neuronales Netz für die weitere Verwendung aus.


NN

Auf den ersten Blick lernt das Neuronale Netz in Epoche 18 mit einer Fehlerrate von 30 % und mit 85 % richtigen Ergebnissen. Wenn wir das Neuronale Netz jedoch auf dem Validierungsset ausführen, sehen wir, dass der Fehler wächst und der Prozentsatz der richtigen Antworten sinkt. So sollten wir ein Netzwerk auswählen, das mit Epoche 11 trainiert wurde. Es hat die geeignetsten Ergebnisse auf dem Validierungsset: val_loss = 0,6607 und val_accuracy = 0,6129. Idealerweise sollte der Fehlerwert gegen 0 tendieren (oder zumindest nicht mehr als 35-40%), während die Genauigkeit nahe bei 1 liegen sollte (zumindest nicht weniger als 55-60%). In diesem Fall könnte die Optimierung entfallen oder mit minimalen Parametern durchgeführt werden, um die Handelsqualität zu verbessern. Auch mit diesen Trainingsergebnissen ist es möglich, ein profitables Handelssystem zu erstellen.


Interpretation der Antwort des Neuronalen Netzes

Lassen Sie uns nun überprüfen, ob all die obigen Arbeiten eine praktische Bedeutung haben.

Starten Sie Jupyter Notebook ohne GPU-Unterstützung und öffnen Sie Test.jpynb aus dem CNN-Verzeichnis.

Test

Kommen wir nun zu den Codeblöcke.

Laden Sie zunächst die notwendigen Module der Bibliotheken des Neuronalen Netzes.

from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Conv2D, MaxPooling2D
from tensorflow.python.keras.layers import Activation, Dropout, Flatten, Dense
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras.models import load_model
import pandas as pd

Festlegen der benötigten Parameter.

predict_dir = 'Test'
img_width, img_height = 449, 449
nb_predict_samples = 12558

Abfrage der Daten und Zeit der getesteten Bilder aus der Datei.

Date=pd.read_csv('EURUSDDate.csv', delimiter=';',header=None)

Laden Sie das Neuronale Netz, das nach der 11. Epoche gespeichert wurde.

model=load_model('cnn_Open11.hdf5')

Normalisieren der Bilder.

datagen = ImageDataGenerator(rescale=1. / 255)

Lesen der Daten mit Hilfe des Generators von der Platte.

predict_generator = datagen.flow_from_directory(
    predict_dir,
    target_size=(img_width, img_height),
    shuffle=False)

Antworten aus dem Neuronalen Netz abrufen.

indicator=model.predict(predict_generator, nb_predict_samples )

Darstellen des Ergebnisses. Das Abrufen von Rückmeldungen nimmt viel Zeit in Anspruch, daher folgt eine Meldung über den Abschluss des Prozesses.

print(indicator)

Speichern des erhaltenen Ergebnisses in einer Datei.

Date=pd.DataFrame(Date)
Date['0'] =indicator
Date.to_csv('Indicator.csv',index=False, header=False,sep=';')

Führen Sie das Programm aus. Nach Beendigung wird die Datei "Indikator.csv" unter dem Verzeichnis CNN erstellt.

Indikator

Verschieben Sie sie nach C:\Users\...\AppData\Roaming\MetaQuotes\Terminal\Common\Files.

Führen Sie den Indikator NWI auf dem EURUSD H1-Chart aus.

NWI

 

//+------------------------------------------------------------------+
//|                                                          NWI.mq5 |
//|                                 Copyright © 2019, Andrey Dibrov. |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2019, Andrey Dibrov."
#property link      "https://www.mql5.com/en/users/tomcat66"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Red
#property indicator_color2  DodgerBlue


int Handle;
int i;
int h;
input int Period=5;
double    ExtBuffer[];
double    SignBuffer[];
datetime Date1;
datetime Date0;
string File_Name="Indicator.csv";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
   SetIndexBuffer(0,ExtBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,SignBuffer,INDICATOR_DATA);
   IndicatorSetInteger(INDICATOR_DIGITS,5);
   Handle=FileOpen(File_Name,FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   //FileClose(Handle);
  }
//+------------------------------------------------------------------+
//| Relative Strength Index                                          |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
   MqlDateTime stm;
   Date0=StringToTime(FileReadString(Handle));
   i=iBarShift(NULL,PERIOD_H1,Date0,false);
   Handle=FileOpen(File_Name,FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   ArraySetAsSeries(ExtBuffer,true);
   ArraySetAsSeries(SignBuffer,true);
   while(!FileIsEnding(Handle) && !IsStopped())
     {
      Date1=StringToTime(FileReadString(Handle));
      ExtBuffer[i]=StringToDouble(FileReadString(Handle));
      h=Period-1;
      if(i>=0)
        {
         while(h>=0)
           {
            SignBuffer[i]=SignBuffer[i]+ExtBuffer[i+h];
            h--;
           }
        }
      SignBuffer[i]=SignBuffer[i]/Period;
      TimeToStruct(Date1,stm);
      i--;
     }
   FileClose(Handle);
   return(rates_total);
  }
//+------------------------------------------------------------------+

Der Einfachheit halber interpretieren wir die Netzwerkantworten anhand des Schnittpunkts der Hauptindikatorlinie mit einer einfachen Durchschnittslinie. Verwenden wir den TestCNN Expert Advisor.

//+------------------------------------------------------------------+
//|                                                      TestCNN.mq5 |
//|                                 Copyright © 2019, Andrey Dibrov. |
//+------------------------------------------------------------------+
#property copyright " Copyright © 2019, Andrey Dibrov."
#property link      "https://www.mql5.com/en/users/tomcat66"
#property version   "1.00"
#property strict

#include<Trade\Trade.mqh>

CTrade  trade;

input int Period=5;
input int H1;
input int H2;
input int H3;
input int H4;
input int LossBuy;
input int ProfitBuy;
input int LossSell;
input int ProfitSell;

ulong TicketBuy1;
ulong TicketSell0;

datetime Count;

double Per;
double Buf_0[];
double Buf_1[];
bool send1;
bool send0;

int h=4;
int k;
int K;
int bars;
int Handle;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   Handle=FileOpen("Indicator.csv",FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");

   while(!FileIsEnding(Handle)&& !IsStopped())
     {
      StringToTime(FileReadString(Handle));
      bars++;
     }
   FileClose(Handle);
   ArrayResize(Buf_0,bars);
   ArrayResize(Buf_1,bars);
   Handle=FileOpen("Indicator.csv",FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");

   while(!FileIsEnding(Handle)&& !IsStopped())
     {
      Count=StringToTime(FileReadString(Handle));
      Buf_0[k]=StringToDouble(FileReadString(Handle));
      h=Period-1;
      if(k>=h)
        {
         while(h>=0)
           {
            Buf_1[k]=Buf_1[k]+Buf_0[k-h];
            h--;
           }
         Buf_1[k]=Buf_1[k]/Period;
        }
      k++;
     }
   FileClose(Handle);

   int deviation=10;
   trade.SetDeviationInPoints(deviation);
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
   trade.SetAsyncMode(true);

//---
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   MqlDateTime stm;
   TimeToStruct(TimeCurrent(),stm);

   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
   double PriceAsk=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double PriceBid=SymbolInfoDouble(_Symbol,SYMBOL_BID);

   double SL1=NormalizeDouble(PriceBid-LossBuy*point,digits);
   double TP1=NormalizeDouble(PriceAsk+ProfitBuy*point,digits);
   double SL0=NormalizeDouble(PriceAsk+LossSell*point,digits);
   double TP0=NormalizeDouble(PriceBid-ProfitSell*point,digits);

   if(LossBuy==0)
      SL1=0;

   if(ProfitBuy==0)
      TP1=0;

   if(LossSell==0)
      SL0=0;

   if(ProfitSell==0)
      TP0=0;

//---------Buy1
   if(send1==false && K>0 && Buf_0[K-1]>Buf_1[K-1] && Buf_0[K]<Buf_1[K] && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2) && stm.hour>H1 && stm.hour<H2 && H1<H2)
     {
      send1=trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,PriceAsk,SL1,TP1);
      TicketBuy1 = trade.ResultDeal();
     }

   if(send1==true && K>0 && Buf_0[K-1]<Buf_1[K-1] && Buf_0[K]>Buf_1[K] && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }

//---------Sell0

   if(send0==false && K>0 && Buf_0[K-1]<Buf_1[K-1] && Buf_0[K]>Buf_1[K] && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2) && stm.hour>H3 && stm.hour<H4 && H3<H4)
     {
      send0=trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,1,PriceBid,SL0,TP0);
      TicketSell0 = trade.ResultDeal();
     }

   if(send0==true && K>0 && Buf_0[K-1]>Buf_1[K-1] && Buf_0[K]<Buf_1[K] && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketSell0);
      send0=false;
     }
   K++;
  }
//+------------------------------------------------------------------+


Lassen Sie uns gleichzeitig durch die Signallinie Zeitraum, Zeit und Stop-Orders für Geschäfte in beide Richtungen optimieren.


Optim

Optim1

Das Neuronale Netz wurde im Zeitraum vor der Diagrammlinie trainiert, und die Optimierung wurde bis zur vertikalen roten Linie durchgeführt. Dann wurde ein Test für die optimierten Antworten des Neuronalen Netzes durchgeführt. Die obigen Diagramme zeigen zwei zufällige positive Optimierungsergebnisse, die der Optimierer als das Ergebnis mit der höchsten Priorität angezeigt hat.


Visualisierung von Schichten des Neuronalen Netzes und Verbesserung der CNN-Qualität

Das Neuronale Netz scheint eine Art Blackbox zu sein. Das ist aber nicht ganz so, denn wir können in Merkmalskarten in Schichten sehen, welche Merkmale das Neuronale Netz hervorhebt. Dies liefert Informationen für die weitere Analyse und die Verbesserung der Netzwerkqualität. Schauen wir uns das mal an.

Führen Sie Visual.ipynb aus dem Ordner CNN aus.

Laden Sie zunächst die notwendigen Module der Bibliotheken des Neuronalen Netzes.

from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Model, load_model
import pandas as pd
from tensorflow.python.keras.preprocessing import image 
import matplotlib.pyplot as plt
import numpy as np

Laden des gesicherten Modells.

model=load_model('cnn_Open11.hdf5')

Schauen wir uns die Netzarchitektur an.

model.summary()

Conv2d

Was analysieren die Convolutional-Schichten?

Laden wir ein paar Bilder.

img_path='Train/Buy/Buy81.png'
img=image.load_img(img_path,target_size=(449,449))
plt.figure(figsize=(8, 8))
plt.imshow(img)
plt.show

Buy81

Konvertieren wir das Bild in ein Numpy-Array und normalisieren es.

x=image.img_to_array(img)
x=np.expand_dims(x,axis=0)
x/=255

Schneiden des Modells auf ein paar Convolutional-Schichten. Die Nummern der Convolutional-Schichten sind 0, 3, 6. Beginnen wir bei Null. Tatsächlich erstellen wir ein neues, bereits trainiertes Modell, von dem wir vor der Klassifizierung ein Zwischenergebnis erhalten werden.

model=Model(inputs=model.input, outputs=model.layers[0].output)

Danach können wir die Schichten 3 und 6 anzeigen.

#model=Model(inputs=model.input, outputs=model.layers[3].output)
#model=Model(inputs=model.input, outputs=model.layers[6].output)

Ein paar Informationen über das beschnittene Modell.

model.summary()

Conv2d-0

Prüfen wir die erste Convolutional-Schicht 0.

Antwort des Neuronalen Netzes abrufen.

model=model.predict(x)

Eine der Merkmalskarten ausgeben, 18.

print(model.shape)
im=model[0,:,:,18]
plt.figure(figsize=(10, 10))
plt.imshow(im)
plt.show()


PLT

Wie Sie sehen können, hat das Netzwerk hier Aufwärtskerzen hervorgehoben. In diesem Stadium ist es für das Neuronale Netz schwer, zwischen Abwärtskerzen und den Punkten der Parabolic zu unterscheiden. Das liegt daran, dass für sie die gleiche Farbe verwendet wird. Daher sollten alle Elemente des Charts in verschiedenen Farben dargestellt werden. 

Alle Merkmalskarten prüfen

rows=12
filters=model.shape[-1]
size=model.shape[1]
cols=filters//rows
display_grid=np.zeros((cols*size,rows*size))
for col in range(cols):
    for row in range(rows):
        channel_image=model[0,:,:,col*rows+row]
        channel_image-=channel_image.mean()
        channel_image/=channel_image.std()
        channel_image*=64
        channel_image+=128
        channel_image=np.clip(channel_image,0,255).astype('uint8')
        display_grid[col*size:(col+1)*size,row*size:(row+1)*size]=channel_image
scale=1./size
plt.figure(figsize=(scale*display_grid.shape[1],scale*display_grid.shape[1]))
plt.grid(False)
plt.imshow(display_grid,aspect='auto',cmap='viridis')

Form

Schauen Sie auf die dritte Merkmalskarte (2).

Form2

Hier hebt das Neuronale Netz alle Kerzen hervor, allerdings mit unterschiedlichen Dochten. Dadurch ähnelt das Bild einem dreidimensionalen Bild. Aber auch hier können Sie sehen, dass die Dochte der Abwärtskerzen und Parabolic die gleiche Farbe haben.

Betrachten Sie nun die Karte 5 der nächsten Convolutional-Schicht (3).


Form5

Hier überschneiden sich die Punkte von Parabolic, und das CNN identifiziert sie als Zeichen für das Muster einer Seitwärtsbewegung. Gemäß der vorherigen Abbildung hat das Neuronale Netz diesen Abschnitt anders gerendert. Daraus können wir schließen, dass sich die Kategorien der Bilder für das Training erweitert haben. Wir müssen eine weitere Kategorie einführen, um das Neuronale Netz zu trainieren - Seitwärtsbewegung (Flat).

Die visuelle Untersuchung der Merkmalskarten des Convolutional Neuronalen Netzes ermöglicht also eine klarere Spezifikation der Trainingsaufgaben. Dies kann auch bei der Erweiterung der vom CNN identifizierten Merkmalskategorien sowie bei der Reduzierung des Rauschens helfen.

Schlussfolgerung

Durch die Verwendung öffentlich verfügbarer Tools und Fähigkeiten von Convolutional Neuronalen Netzen können wir einen interessanten und unkonventionellen Ansatz zur technischen Analyse anwenden. Gleichzeitig kann dadurch die Aufbereitung der Daten für das Training des Neuronalen Netzes stark vereinfacht werden. Die Visualisierung der darin ablaufenden Prozesse hilft bei der Analyse, welche Eingangsdaten die Qualität des Trainings am meisten beeinflussen. 

Zum Schluss möchte ich noch die Optimierung erwähnen. Wie ich bereits geschrieben habe, handelt es sich um eine sehr einfache Optimierung. Sie sollte jedoch mit den Aufgaben in Einklang gebracht werden, die wir für unser Netzwerk gestellt haben. In Übereinstimmung mit diesen Aufgaben sollte das Trainingsfeld in Kategorien eingeteilt werden. Außerdem sollten diese Bedingungen bei der Erstellung eines Handelsroboters verwendet werden.