English Русский 中文 Español Deutsch Português
preview
取引におけるニューラルネットワークの実用化(第2部)コンピュータービジョン

取引におけるニューラルネットワークの実用化(第2部)コンピュータービジョン

MetaTrader 5トレーディング | 17 5月 2021, 15:26
931 0
Andrey Dibrov
Andrey Dibrov

はじめに

取引用に設計されたニューラルネットワークを訓練するためのデータを準備する際の本質的な問題は、必要な入力データの準備に関連しています。たとえば、12個の指標を使用する場合を考えてみます。これらの指標は、いくつかの有益なチャートのセットを表すとします。これらの指標を特定の深さまで計算すると、結果として最大100のエントリが得られます。場合によってはさらに多くのエントリが得られます。コンピュータービジョンを使用してニューラルネットワークの訓練を簡単にすることはできるでしょうか。この問題を解決するために、分類と認識の問題を解決するためによく使用される畳み込みニューラルネットワークを使用しましょう。


畳み込みニューラルネットワークアーキテクチャ

本稿では、畳み込みニューラルネットワークを使用します。そのアーキテクチャを次の図に示します。このスキームは、畳み込みニューラルネットワーク(CNN)を構築するための一般的な原理を示しています。 

この場合は次のようになります。

  1. CNN入力(サイズが449x449ピクセルの画像)
  2. 96個の特徴マップの最初の畳み込み層 - 各マップはサイズ447x447の画像 - 畳み込みカーネル3x3
  3. サイズが223x223、カーネルが2x2の96個の特徴マップのサブサンプル層 -
  4. 32個の特徴マップの2番目の畳み込み層 - 各マップはサイズ221x221の画像 - 畳み込みカーネル3x3
  5. サイズが110x110、カーネルが2x2の32個の特徴マップのサブサンプル層 -
  6. 16個の特徴マップの3番目の畳み込み層 - 各マップはサイズ108x108の画像 - 畳み込みカーネル3x3
  7. サイズが54x54、カーネルが2x2の16個のフィーチャマップのサブサンプル層 - 図には示されていない
  8. 64個のニューロンの全結合層
  9. 1つのニューロンの出力層 - これらの2つの層は、分類単位を表す

CNN

畳み込みニューラルネットワークを初めて使用する場合は、構築が煩雑で複雑に見えても心配する必要はありません。特定のアーキテクチャのニューラルネットワークは自動的に構築されるので、自分でやるのは主なパラメータを設定することだけです。 

ニューラルネットワークの訓練とテストのための画像の配列の準備

画像の配列を準備する前に、ニューラルネットワークの目的を定義します。理想的には、ピボットでネットワークを訓練するのは素晴らしいことです。この目的に応じて、最後の極度のバーでスクリーンショットを作成する必要がありますが、この実験では実用的な価値が示されませんでした。そのため、別の画像セットを使用して、さらに、上記のアレイを含むさまざまなアレイを試すことができます。これはまた、画像ベースの分類タスクを解決する際のニューラルネットワークの効率の付加的な証明を提供する可能性があります。連続時系列で得られたニューラルネットワーク応答には、さらなる最適化が必要です。 

実験を複雑にせず、2つのカテゴリの画像に焦点を当てましょう。

  • 買 - 価格が上昇したときまたは価格が1日の安値に達したとき
  • 売 - 価格が下がったときまたは価格が1日の高値に達したとき

買   買1  買2  買3

ニューラルネットワーク訓練の目的では、任意の方向への動きは、価格がトレンド方向で新しい極値に達することとして定められます。これらの瞬間ではチャートのスクリーンショットが作成されます。トレンド反転の瞬間もネットワーク訓練にとって重要であり、価格が1日の高値または安値に達すると、チャートのスクリーンショットが作成されます。

操作を開始する前に、チャートの外観を準備します。CNN.tplテンプレートを使用するので、\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Profiles\Templatesに保存します。

CNN.tpl

チャートのプロパティでテキストを「白」として定義します。

CNN.tpl


他の指標を添付することもできます。これらの指標は恣意的に選ばれました。また、ハードウェアの機能に応じて最適なチャートサイズを見つけることをお勧めします。

次のスクリプトを使用して、画像の配列を作成します。

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

スクリプトは2つのモードで機能します。「Train」は訓練用の画像の配列を作成し、「Test」はニューラルネットワーク応答を取得するための画像の配列を作成し、これに基づいて指標が生成されます。さらに、この指標は取引ストラテジーを最適化するために使用されます。 

「Train」モードでスクリプトを実行してみましょう。

訓練

Date変数は、訓練用の画像が選択される標本の初期データです。DateOutは、訓練用の画像が選択される標本期間の終了日です。DateTestは、ニューラルネットワークから1時間ごとの応答を取得するための画像を選択するための開始日です。終了日はスクリプトの起動時間になります。 

買...および売...画像のセットは、データディレクトリの...\MQL5\Filesフォルダに保存されます。画像の総数は6125です。

訓練

次に、訓練、検証、テストセット用のディレクトリを準備します。便宜上、デスクトップにCNNフォルダを作成し、その中にTrain、Val、Testの3つのフォルダを作成します。

CNN

TrainディレクトリとValディレクトリに、BuyサブディレクトリとSellサブディレクトリを作成します。Testの下にRespサブディレクトリを作成します。

訓練

...\MQL5\Files」フォルダから、「Buy....」のすべてのファイルを切り取り「...\Train\Buy」に貼り付けます。3139個の画像があります。「Sell ...」についても同じことを繰り返し、「...\Train\Sell」に追加します。ここには2986個の画像があります。BuyフォルダとSellフォルダから、最後の(最大数の)画像の30%を切り取り、Valの下の適切なサブフォルダに貼り付けます。

まとめてみましょう。 

  • ...\Train\Buy - 2198画像 
  • ...\Val\Buy   - 941画像
  • ...\Train\Sell - 2091画像
  • ...\Val\Sell   - 895画像

ネットワークを訓練するための一連の画像を用意しました。画像サイズは449x449ピクセルです。

テスト用に一連の画像を準備して、「Test」モードでスクリプトを実行します。

検証

1時間ごとの連続したスクリーンショットのセットが「...\MQL5\Files」に保存されます。現在は12558個です。グループ化はニューラルネットワークが単独で実行する必要があるため、分離したりグループ化したりしないでください。より正確には、ネットワークは、画像がネットワークが訓練された条件に対応する確率を示す必要があります。上向きの動きが下に向き、下向きの動きが上に向きます。 

これらのファイルを切り取って「...CNN\Test\Resp」に貼り付けます。

検証

応答をテストし、ストラテジーを最適化するための一連の画像を用意しました。「...\MQL5\Files」の下に残っている、日付と時刻がEURUSDDateのファイルは、CNNフォルダに移動する必要があります。

MetaTrader5の1つの特定の機能に注意したいと思います。ストラテジーテスターのエキスパートアドバイザーを使用して一連の画像を準備する方が便利で信頼性が高くなりますが、MetaTrader 5には、ストラテジーテスターでスクリーンショットを作成する機能がありません。何にしても、この特定の機能は取引ロボットの作成には影響しません。


ニューラルネットワークの訓練

Anaconda環境を使用して畳み込みネットワークを操作します。この環境はCPUおよびGPUで動作するように構成する必要があります(NVIDIAグラフィックカードを使用している場合)。このグラフィックカードは、学習プロセスを高速化するために必要です。ただし、ニューラルネットワークアーキテクチャの作成にはいくつかの制限があります。グラフィックカードのRAMの量に依存するということです。しかし、学習速度は大幅に向上します。たとえば、私の場合、CPUでの1つの訓練エポックは20分続き、GPUでは1〜2分かかります。ネットワークが40エポックで訓練されている場合、13時間と1.5時間かかります。GPUを使用すると、研究段階でニューラルネットワークの検索プロセスを大幅に高速化できます。

  1. 最新のAnaconda Navigatorバージョンをダウンロードしてインストールします。すべての手順でデフォルト設定を使用します。
  2. メニュー[Start\Anaconda3]を使用して[Anaconda Prompt]を起動します。
  3. コマンド「pip install tensorflow」を実行して、 Googleによって開発された機械学習用のプログラムライブラリをインストールします。
    tensorflow

  4. コマンド「pip install keras」を実行して、Kerasニューラルネットワークライブラリをインストールします。
    keras

  5. コマンド「conda create --name PythonGPU」を実行して、GPUの下に新しい「conda」環境を作成します。 環境をアクティブ化します。PythonGPUをアクティブ化しますGPU

  6. コマンド「conda create -n PythonGPU python=3.6 tensorflow-gpu」を実行して、tensorflow gpuをインストールします。Python3.6ではtensorflow gpuをインストールする必要があることに注意してください。
      tensorflow gpu

  7. コマンド「conda install -c anaconda keras-gpu」を実行して、keras gpuをインストールします。
    keras gpu

  8. Python GPU環境でプログラミングするためのJupyterインターフェイスをインストールします。CPU Jupyterは、Anacondaのインストール中にすでにインストールされています。コマンド「conda install jupyter」を実行します。  Jupyter

  9. コマンド「conda install -c anaconda pandas.」を実行して、さらに2つのライブラリ(PandasとPillow)をインストールします。次に「conda install pillow」を実行します。グラフィックカードを使用しない場合でも、これらのライブラリはCPU用にインストールする必要があります。
    pandas 

  10. pillow

  11. これで、畳み込みニューラルネットワークの訓練を開始できます。以前に作成したCNNフォルダにTrain.ipynbTest.ipynbの2つのファイルを追加します。これらは、Jupyter Notebook形式のファイルです。Jupyter Notebook(PythonGPU)を実行し、ファイルTrainを開きます。 CNN  

プログラムコードのすべてのブロックについて考えてみましょう。

まず、ニューラルネットワークライブラリの必要なモジュールを読み込みます。

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

次に、必要なハイパーパラメータを設定します。

# 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

ネットワークアーキテクチャを作成しましょう。

  • シーケンシャル畳み込みニューラルネットワークアーキテクチャを設定します。
  • 入力画像はサイズが449x449ピクセルで3チャンネル(赤、緑、青)です。ここではカラー画像を使用しますが、モノクロ画像も試すことができます。
  • 2次元データを操作するための最初の畳み込み層を作成します。96個の特徴マップにそれぞれ3x3の畳み込みカーネルが播種されています。畳み込み層の各ニューロンは画像の3x3の正方形のセクションにリンクされています。 
  • 計算量の少ない「relu」関数を使用した活性化層
  • 次元を減らすには、この正方形から最大値を選択して、2x2カーネルのサブサンプリング層を追加します。
  • 次に、32コアと16コアの畳み込み層をさらに2つ、活性化層を2つ、サブサンプルを2つ追加します。
  • 2次元データから1次元形式への変換
  • 変換されたデータを、64個のニューロンを持つ完全結合層に渡します。
  • Dropout(0.5)正則化層関数を使用した過剰適合を回避する試み
  • 1つのニューロンで全結合出力層を追加します。2つの画像クラスが使用されるため、ネットワーク応答はバイナリ応答で受信されます。複数のクラスを試すこともできます。例は、トレンド用に2つ、レンジ用に1つで、この場合、出力層には3つのニューロンがあって画像を3つのクラスに分類する必要があります。
  • 「シグモイド」活性化関数は分類に適しており、実験中に最高のパフォーマンスを示しました。

このアーキテクチャの例は、簡単に最新化できます。層の数とサイズを増やし、シーケンスに応じて位置を変更し、畳み込みカーネルの次元を変更し、活性化関数を変更して、全結合層を操作できます。ただし、ここでジレンマが発生します。GPUを使用する場合、ニューラルネットワークのアーキテクチャを増やしたければビデオカードのRAMを増やす必要があります。必要に応じて、画像サイズを小さくする必要があります。そうしないと、CPUの使用に多くの時間を費やすようになります。

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'))

ニューラルネットワークをコンパイルします。エラー関数: binary-crossentropyを使用します。この場合、理想的には値0または1を取る必要がある2つのクラスで構成される応答を使用します。ただし、実際の値は0から1に分配されます。最急降下法オプティマイザを選択します。これは、ニューラルネットワークの訓練に最適のようです。精度の指標(正解の割合)を選択します。 

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

画像ピクセルの強度に関するデータを正規化します。

datagen = ImageDataGenerator(rescale=1. / 255)

Keras生成器を使用して、ディスクからデータを読み取り、ニューラルネットワークの訓練および検証画像配列を作成します。繰り返しますが、class_modeは「binary」です。シャッフルを「False」に設定するため、画像のシャッフルは無効になっています。

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)

コールバック関数は、各エポックの後に訓練されたニューラルネットワークを保存します。これにより、エラー値とヒット率の観点から最適なネットワークを選択できます。

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

次に、ネットワーク訓練に進みます。

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. 図に示すようにプログラムを実行します。

実行


前の手順が正しく実行されている場合、ニューラルネットワークは学習を開始します。

Fit

訓練プロセスの終了後、20個の訓練済みニューラルネットワークがCNNフォルダーの下に表示されます。

CNN

訓練結果を表示し、さらに使用するニューラルネットワークを選択しましょう。


NN

一見したところ、エポック18で、ニューラルネットワークは30%のエラー率と85%の正しい結果で学習しました。ただし、検証セットでニューラルネットワークを実行すると、エラーが大きくなり、正解の割合が低下することがわかります。したがって、エポック11で訓練されたネットワークを選択する必要があります。検証セットで最も適切な結果(val_loss = 0.6607およびval_accuracy = 0.6129)が得られます。理想的には、エラー値は0(または少なくとも35〜40%以下)になる傾向があり、精度は1 (少なくとも55〜60%以上)に近い必要があります。この場合、取引品質を向上させるために、最適化を省略したり最小限のパラメータで実行したりできます。これらの訓練結果にかかわらず、収益性の高い取引システムを作成することは可能です。


ニューラルネットワーク応答の解釈

上記のすべての作業に実用的な意味があるかどうかを確認してみましょう。

GPUに対応していないJupyter Notebookを実行してCNNディレクトリからTest.jpynbを開きます。

検証

コードブロックについて考えてみましょう。

まず、ニューラルネットワークライブラリの必要なモジュールを読み込みます。

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

必要なパラメータを設定します。

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

テストした画像のデータと時刻をファイルから読み取ります。

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

11番目のエポックの後に保存されたニューラルネットワークを読み込みます。

model=load_model('cnn_Open11.hdf5')

画像を正規化します。

datagen = ImageDataGenerator(rescale=1. / 255)

生成器を使用してディスクからデータを読み取ります。

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

ニューラルネットワークから応答を取得します。

indicator=model.predict(predict_generator, nb_predict_samples )

結果を表示します。フィードバック取得プロセスには時間がかかるため、以下にプロセス完了の通知を示します。

print(indicator)

得られた結果をファイルに保存します。

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

プログラムを実行します。完了すると、Indicator.csvファイルがCNNディレクトリの下に作成されます。

指標

C:\Users\...\AppData\Roaming\MetaQuotes\Terminal\Common\Filesに移動します。

EURUSDH1チャートで指標NWIを実行します。

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);
  }
//+------------------------------------------------------------------+

簡単にするために、メイン指標ラインと単純な平均ラインの交点を使用してネットワーク応答を解釈します。TestCNNエキスパートアドバイザーを使用します。

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


シグナルラインの期間、時間、および両方向の取引のストップ注文によって同時に最適化しましょう。


最適

Optim1

ニューラルネットワークは、折れ線グラフの前の期間に訓練され、垂直の赤い線まで最適化が実行されました。次に、最適化されたニューラルネットワーク応答のテストが実行されました。上記のグラフは、オプティマイザが最も優先度の高い結果として示した2つのランダムな肯定的な最適化結果を示しています。


ニューラルネットワーク層の視覚化とCNN品質の向上

ニューラルネットワークは一種のブラックボックスのように見えるかもしれませんが、層の特徴マップでニューラルネットワークが強調表示している特徴を確認できるため、これは部分的にしか正しくありません。これにより、さらなる分析とネットワーク品質の向上のための情報が提供されます。見てみましょう。

CNNフォルダからVisual.ipynbを実行します。

まず、ニューラルネットワークライブラリの必要なモジュールを読み込みます。

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

保存したモデルを読み込みます。

model=load_model('cnn_Open11.hdf5')

ネットワークアーキテクチャを見てみましょう。

model.summary()

Conv2d

これらの畳み込み層は何を分析するのでしょうか。

画像を読み込みます。

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

画像をnumpy配列に変換し、正規化します。

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

畳み込み層でモデルをトリミングします。畳み込み層番号は0、3、6です。0から始めます。実際、すでに訓練済みの新しいモデルを作成し、そこから分類前に中間結果を受け取ります。

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

その後、層3と6を表示できます。

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

トリミングされたモデルに関する情報を表示します。

model.summary()

Conv2d-0

最初の畳み込み層0を確認します。

ニューラルネットワークの応答を取得します。

model=model.predict(x)

機能マップの1つである18を印刷します。

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


PLT

ご覧のとおり、ネットワークはここで強気のローソク足を強調しています。この段階では、ニューラルネットワークが弱気のローソク足と放物線ポイントを区別するのは困難です。同じ色が使われているからです。チャートのすべての要素は異なる色で表示する必要があります。 

すべての機能マップを確認します。

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')

形状

3番目の特徴マップ(2)を見てください。

形状2

ここで、ニューラルネットワークはすべてのローソク足を強調表示していますが、実体は異なります。このため、画像は立体的なものに似ています。しかし、繰り返しになりますが、弱気のローソク足芯と放物線は同じ色であることがわかります。

次に、次の畳み込み層(3)のマップ5を見てください。


形状5

ここでは、放物線の点が重なっており、CNNはそれらをレンジのパターンの兆候として識別します。前の図によると、ニューラルネットワークはこのセクションを異なる方法でレンダリングしました。したがって、訓練用の画像のカテゴリが拡大したと結論付けることができます。ニューラルネットワークを訓練するために、もう1つのカテゴリであるレンジを導入する必要があります。

このように、畳み込みニューラルネットワークの特徴マップを視覚的に調べることで、訓練タスクをより明確に指定できます。これは、CNNによって識別された機能のカテゴリを拡張するのに役立つだけでなく、ノイズを減らすのにも役立ちます。

終わりに

公開されているツールと畳み込みニューラルネットワークの機能を使用して、テクニカル分析に興味深く型破りなアプローチを適用できると同時に、ニューラルネットワーク訓練用のデータの準備を大幅に簡素化できます。内部で発生するプロセスの視覚化は、どの入力データが訓練の品質に最も影響を与えるかを分析するのに役立ちます。 

結論として、私は最適化について言及したいと思います。前述したように、これは非常に単純な最適化でした。ただし、ネットワークに設定したタスクと一致させて、これらのタスクに従って訓練アレイをカテゴリに分割しなければなりません。さらに、これらの条件は、取引ロボットを作成するときに使用されるべきです。


MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/8668

添付されたファイル |
CNN.tpl (5.72 KB)
NWI.mq5 (4.98 KB)
CNNet.mq5 (4.16 KB)
Train.ipynb (11.48 KB)
Test.ipynb (2.92 KB)
Visual.ipynb (10.31 KB)
TestCNN.mq5 (9.38 KB)
自動取引のための便利でエキゾチックな技術 自動取引のための便利でエキゾチックな技術
本稿では、自動取引のためのいくつかの非常に興味深く有用な技術を紹介します。それらのいくつかには馴染みがあるかもしれません。最も興味深い手法を取り上げ、なぜ使用する価値があるのかを説明します。さらに、これらの技術の実際面での傾向を示します。エキスパートアドバイザーを作成し、説明されているすべての技術を相場履歴を使用してテストします。
DoEasyライブラリでのその他のクラス(第66部): MQL5.comシグナルコレクションクラス DoEasyライブラリでのその他のクラス(第66部): MQL5.comシグナルコレクションクラス
本稿では、シグナルを管理する関数を備えたMQL5.comシグナルサービスのシグナルコレクションクラスを作成します。さらに、DOMの売買取引高の合計を表示するように板情報スナップショットオブジェクトクラスを改善します。
多層パーセプトロンとバックプロパゲーションアルゴリズム 多層パーセプトロンとバックプロパゲーションアルゴリズム
これら2つの手法の人気が高まり、Matlab、R、Python、C ++などで多くのライブラリが開発されています。これらのライブラリは、入力として訓練セットを受け取り、問題に適切なネットワークを自動的に作成します。基本的なニューラルネットワークタイプ(単一ニューロンパーセプトロンと多層パーセプトロンを含む)がどのように機能するかを理解してみましょう。ネットワークを訓練するためのエキサイティングなアルゴリズムである勾配降下法とバックプロパゲーションについて検討します。既存の複雑なモデルは、多くの場合、このような単純なネットワークモデルに基づいています。
DoEasyライブラリでの価格(第65部): 板情報コレクションとMQL5.comシグナル操作クラス DoEasyライブラリでの価格(第65部): 板情報コレクションとMQL5.comシグナル操作クラス
本稿では、すべての銘柄の板情報コレクションクラスを作成し、シグナルオブジェクトクラスを作成することによってMQL5.comシグナルサービスを使用するための機能の開発を開始します。