取引におけるニューラルネットワークの実用化(実践編)

Andrey Dibrov | 8 10月, 2020

はじめに

前回の記事「取引におけるニューラルネットワークの実用化」では、ニューラルネットワークモジュール(NNM)を使用して取引システムを作成する際の一般的なポイントについて説明しました。本稿では、実際にNNMをテストします。また、NNMベースの自動取引システムの作成も試みます。

すべての操作はEURUSDペアに対して実行されます。ただし、ニューラルネットワークモジュールはプログラムとして普遍的であり、さまざまな取引商品およびそれらの組み合わせで機能します。したがって、異なる通貨ペア用に訓練された複数のニューラルネットワークを統合する1つのNNMを使用することが可能です。

ニューラルネットワークの訓練に必要な履歴データの準備に関するテクノロジは、本稿の範囲を超えています。ここでのNNMは、記事の公開時間に近い履歴データで訓練されたニューラルネットワークを使用します。

結果として得られるNNMは、取引に使用する準備が完全に整っています。1つの記事で複合体を紹介できるようにするには、複数のニューラルネットワークモジュール機能を1つのプログラムに組み合わせるように変更する必要がありました。また、取引エキスパートアドバイザーからNNMに特定の取引実行条件を移しました。後者は、実際の取引を目的としたNNM部分のみに関係します。オフラインモードでのニューラルネットワークテストとその応答最適化に関しては、関連するすべての機能と取引実行条件は引き続き、適切なエキスパートアドバイザーによって実行されます。私は個人的には、取引機能しかないNNモジュールが好きです。取引に使用するNNMは可能な限りシンプルで、追加機能を含まないようにする必要があると思うのです。機能自体は、取引複合体の外部で実装する必要があります。ここでは、これらの機能には取引、テスト、最適化が含まれます。シグナルをバイナリ形式で受信できるように、取引実行条件はNNMでより適切に実装する必要があります。ただし、すべてのNNM実行オプションは、実際の実行可能性を確認しています。

MatlabプラットフォームでのNNMの準備と取引のテクノロジについては、次の記事で詳しく説明します。

また、システムは将来Pythonに変換される可能性があります。本稿末尾には関連する短いビデオがあります。

NNMは、取引先のブローカーから受け取った履歴データを使用してテストすると、より長いテスト期間で肯定的な結果を生成します。この部分も統一できますが、役に立たないと思います。 

EURUSD_MT5ニューラルネットワークモジュール

下の図は、最初の起動時のニューラルネットワークモジュールの外観を示しています。

НСМ EURUSD_MT5

  1. Onlineブロックは、実際の取引中およびビジュアルモードでのテスト時にニューラルネットワークを開始および停止するように設計されています。
  2. Onlineブロックがアクティブ化されたときに、ニューラルネットワークの応答ラインと交差するシグナルラインの条件を含む情報フィールド 
  3. Trainは、ニューラルネットワークの訓練と「再トレーニング」(?)用に設計されたデモンストレーションブロックです。
  4. ニューラルネットワークの応答値を出力するためのフィールド(左 - ニューラルネットワークの応答、右 - シグナル線、下 - 現在のバー、上 - 前のバー)
  5. Offlineブロックは、テストサンプルのニューラルネットワーク応答を配列に出力するように設計されています。
  6. Onlineブロックを使用する場合のニューラルネットワーク応答ラインの平均値を入力するためのフィールド(シグナル線期間)(編集可能な値)
  7. ブロック「Net1,2,3」—時系列の異なるセグメントで訓練されたネットワークの3つのサブモジュールで、各ブロックには2つのニューラルネットワークが含まれています。
  8. Onlineブロック使用時のNNM操作終了時刻。
  9. Onlineブロック使用時にNNM操作期間を時間単位で入力するためのフィールド(編集可能な値)
  10. Onlineブロック使用時にNNMの開始から経過した時間をカウントします。

添付ファイル

  1. MyAppInstaller_mcr.exe — インストールファイル
  2. EURUSD_MT5.exe — ニューラルネットワークモジュール
  3. EURUSD_MT5var.exe — ニューラルネットワークモジュールのバリアント
  4. net1-net6.mat — 3つのサブネット(Net1-Net3)のニューラルネットワーク。訓練とテストの例として使用されます。 
  1. ExpertMatlabPodkach_MT5.mq5およびExpertMatlab_MT5.mq5 — NNMオフラインテストの履歴データを準備するために必要な2つのEA
  2. NWI.mq5 — NNM応答を視覚的に表示する指標
  3. Matlab_MT5.mq5 —ストラテジーテスターでNNM応答をテストおよび最適化するためのEA
  4. ExpertMatlabReal_MT5.mq5 — 実際の口座またはデモ口座でのオンライン操作、および視覚化モードでのテスト用のEA
  5. EURUSDData.csv — 訓練データを持つファイル

プログラムのインストール



Matlabによってコンパイルされたアプリケーションを最初に使用する前に、MyAppInstaller_mcr.exeを使用する必要があります。このアプリケーションは、MATLABランタイムとニューラルネットワークモジュール自体をインストールするために使用されます。

プログラムのインストール後、EURUSD_MT5.exeショートカットをデータディレクトリの...\Common\Filesフォルダに配置します。システムを起動するのが便利になります。すべてのエキスパートアドバイザーとNNMは、このフォルダにファイルを書き込みます。NNMは、ショートカットが配置されているディレクトリからファイルを検索することを提案します。 

ファイルEURUSD_MT5

1. ショートカットEURUSD_MT5

作業フォルダを割り当てます。

パスの指定

2. パスの指定


実用的な使い方

次に、NNMを使用するには4つのオプションがあります。

  1. デモ口座または実口座でのオンライン取引
  2. ビジュアルモードでのNNMテスト
  3. ニューラルネットワークトレーニング
  4. 取引戦略を最適化するためのニューラルネットワークブロックからの応答の受信

上記の点の論理的な順序が異なるとおっしゃるかもしれませんが、ニューラルネットワークノジュールは当初最初のポイントを実行するために作成されたため、私はこの実装を好みます。2番目、3番目、4番目のオプションは、一般的なシステムセットアップ中に実行できるため、NNMを超えています。本稿では、実際の作業のための一般的なシステム準備のプロセスをよりよく理解するために、これらすべての段階を1つのモノブロックにまとめました。

これらのオプションについて詳しく見ていきましょう。

1. デモ口座または実口座でのオンライン取引


ご覧のとおり、システムの起動時間は5分未満です。

その前に、Excelを設定する必要があります。構成の目的は、スクリプトおよびエキスパートアドバイザーからのデータが数値形式で書き込まれるようにすることです。そうしないと、Matlabはこのデータを誤って読み取ります。整数部分と小数部分の区切り文字としてポイントを設定します。これは、直接、またはシステムセパレータを使用して実行できます。

Excelパラメータ

3. Excelパラメータ

NNMを最初に起動する前に、エキスパートアドバイザーを使用して履歴ダウンロードファイルを作成します。ストラテジーテスターでExpertMatlabPodkach_MT5.ex5を起動します。 


    チャート

ExpertMatlabPodkach_MT5を起動する

4. ExpertMatlabPodkach_MT5.ex5を起動する

ご覧のとおり、EAの起動時間は、運用開始前の3日間をカバーするように選択する必要があります。

その結果、EURUSDTestPodkach.csvファイルを受け取ります。


ファイルEURUSDPodkach_MT5

5. ファイルEURUSDTestPodkach.csv


ファイルを開き、システムの起動日の前日の最後の1時間の開始に関するデータを除くすべての行を削除して、ファイルを編集します。

不必要な行を削除する

6. 不必要な行を削除する


ExpertMatlabReal_MT5.ex5を起動します。

#include<Trade\Trade.mqh>
//--- An object for performing trading operations
CTrade  trade;

input int LossBuy;
input int ProfitBuy;
input int LossSell;
input int ProfitSell;

int BarMax;
int BarMin;
int handleInput;
int handleInputPodkach;
int handleBar;
int Con;
int Bar;

double DibMax;
double DibMin;

double in[32];

int Order01;
int Order1;

ulong TicketBuy1;
ulong TicketSell0;

bool send1;
bool send0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   handleInputPodkach=FileOpen("EURUSDTestPodkach.csv",FILE_READ|FILE_CSV|FILE_ANSI|FILE_COMMON,";");
   if(handleInputPodkach==INVALID_HANDLE)
      Alert("No file EURUSDTestPodkach.csv");

   in[0]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[1]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[2]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[3]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[4]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[5]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[6]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[7]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[8]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[9]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[10]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[11]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[12]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[13]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[14]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[15]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[16]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[17]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[18]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[19]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[20]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[21]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[22]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[23]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[24]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[25]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[26]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[27]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[28]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[29]=1/StringToDouble(FileReadString(handleInputPodkach))-1;

   FileClose(handleInputPodkach);

//--- Setting MagicNumber to identify EA's orders
   int MagicNumber=123456;
   trade.SetExpertMagicNumber(MagicNumber);
//--- Setting allowable slippage in points for buying/selling
   int deviation=10;
   trade.SetDeviationInPoints(deviation);
//--- order filling mode, use the mode that is allowed by the server
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
//--- The function to be used for trading: true - OrderSendAsync(), false - OrderSend()
   trade.SetAsyncMode(true);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   FileClose(handleInput);
   FileClose(handleBar);
  }

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

   if(stm.hour==1)
      DibMax=iHigh(NULL,PERIOD_H1,1);
   if(stm.hour>0)
     {
      if(iHigh(NULL,PERIOD_H1,1)>DibMax && iTime(NULL,PERIOD_H1,0)>1)
        {
         in[20]=iOpen(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_H1,1);
         in[21]=iHigh(NULL,PERIOD_H1,1)-iOpen(NULL,PERIOD_D1,0);
         in[22]=iHigh(NULL,PERIOD_D1,1)-iLow(NULL,PERIOD_D1,1);
         in[23]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
         in[24]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);
        }
     }
   if(iHigh(NULL,PERIOD_H1,1)>DibMax)
      DibMax=iHigh(NULL,PERIOD_H1,1);
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(stm.hour==1)
      DibMin=iLow(NULL,PERIOD_H1,1);
   if(stm.hour>0)
     {
      if(iLow(NULL,PERIOD_H1,1)<DibMin && iTime(NULL,PERIOD_H1,0)>1)
        {
         in[25]=iOpen(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_H1,1);
         in[26]=iHigh(NULL,PERIOD_H1,1)-iOpen(NULL,PERIOD_D1,0);
         in[27]=iHigh(NULL,PERIOD_D1,1)-iLow(NULL,PERIOD_D1,1);
         in[28]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
         in[29]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);
        }
     }
   if(iLow(NULL,PERIOD_H1,1)<DibMin)
      DibMin=iLow(NULL,PERIOD_H1,1);

   in[30]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
   in[31]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);

   if(Bar<Bars(NULL,PERIOD_H1)&& stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }


   handleInput=FileOpen("Input_mat.txt",FILE_TXT|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON,";");

   FileWrite(handleInput,

             1/(in[0]+1),1/(in[1]+1),1/(in[2]+1),1/(in[3]+1),1/(in[4]+1),1/(in[5]+1),1/(in[6]+1),1/(in[7]+1),1/(in[8]+1),1/(in[9]+1),1/(in[10]+1),1/(in[11]+1),1/(in[12]+1),1/(in[13]+1),1/(in[14]+1),1/(in[15]+1),
             1/(in[16]+1),1/(in[17]+1),1/(in[18]+1),1/(in[19]+1),1/(in[20]+1),1/(in[21]+1),1/(in[22]+1),1/(in[23]+1),1/(in[24]+1),1/(in[25]+1),1/(in[26]+1),1/(in[27]+1),1/(in[28]+1),1/(in[29]+1),1/(in[30]+1),1/(in[31]+1));

   FileClose(handleInput);

   handleBar=FileOpen("Bar.txt",FILE_TXT|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON,";");

   FileWrite(handleBar,stm.hour);

   FileClose(handleBar);

   Order01=FileOpen("Open1.txt",FILE_CSV|FILE_READ|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON," ");

   Order1=StringToInteger(FileReadString(Order01));
   
   FileClose(Order01);

   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(Bar<Bars(NULL,PERIOD_H1))
      Con=0;

   Comment(Order1,"  ",Con);

   if(LossBuy==0)
      SL1=0;

   if(ProfitBuy==0)
      TP1=0;

   if(LossSell==0)
      SL0=0;

   if(ProfitSell==0)
      TP0=0;

   if(Order1==0 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send0=true;

   if(Order1==1 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send1=true;


//---------Buy0

   if(send1==false  &&  Bar==Bars(NULL,PERIOD_H1) && Order1==1 && Con>=1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2) && stm.hour>15 && stm.hour<20)
     {
      send1=trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,PriceAsk,SL1,TP1);
      TicketBuy1 = trade.ResultDeal();
     }

   if(send1==true &&  Bar==Bars(NULL,PERIOD_H1) && Order1==0 && Con>=1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }
//---------Sell0
   if(send0==false  &&  Bar==Bars(NULL,PERIOD_H1) && Order1==0 && Con>=1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2) && stm.hour>
        11 && stm.hour<14)
     {
      send0=trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,1,PriceBid,SL0,TP0);
      TicketSell0 = trade.ResultDeal();
     }

   if(send0==true &&  Bar==Bars(NULL,PERIOD_H1) && Order1==1 && Con>=1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketSell0);
      send0=false;
     }
//-----------------------------------------------------------------------
   Bar=Bars(NULL,PERIOD_H1);
   Con++;
  }
//------------------------------------------------------------------------

取引用に設計されたEAの時間制限については、最適化後にコードに直接追加することをお勧めします。これは、外部変数で発生する可能性のあるエラーのリスクを最小限に抑えるために行います。

ExpertMatlabReal_MT5

7. ExpertMatlabReal_MT5.ex5を起動する

最適化のために設計されたエキスパートアドバイザーについては、外部変数として示す必要があります。

Matlab_MT5.ex5

7.1Matlab_MT5.ex5

履歴ダウンロードファイルの生成を忘れると、EAが誤ったシグナルを生成しないように警告が表示されます。

警告

8. 警告


EAは2つのファイルを ...\Common\Files folderに書き入れます。Input_mat.txtファイルにはNNMの入力データが含まれます。

エキスパートアドバイザーの応答

9. エキスパートアドバイザーの応答

EURUSD_MT5.exeニューラルネットワークモジュールを起動します。ワークスペースが表示されます。

ワークスペース

10. NSMワークスペース


このプログラムバリアントではブロックNet2およびNet3の変更可能なパラメータは変更できません。

[Start]を押して、net1.mファイル(または別のニューラルネットワークファイル)を選択します。

[Start]を押す

11. [Start]を押す

最初の記事からNNMの外観が少し変わっていることにお気付きかもしれませんが、その機能は同じままです。

ニューラルネットワークモジュールが動作を開始します。

NNMが取引している

12. NNMが取引状態である


NNMの操作中は、そのパラメータを変更できません。

チャートの左上隅には、エキスパートアドバイザーがNNMから受け取った数値(1.0、-1.0、0.0)が表示されます。これは、EAが買い(売り)のシグナルを受け取ったことを意味します。Net2から — 取引するべきではありません。Net3から — 買(売)シグナル。このプログラムバージョンは評価を目的としているため、Net1およびNet2から可変シグナルを受信することはありません。

この例では、システムは5時間平滑化されたNNM応答のシグナル線を使用します。誤った初期シグナルの受信を回避するために、ポジションを開く条件に基づいて、モジュールは取引時間の5時間前に起動する必要があります。時間は平滑化パラメータによって異なります。

履歴ダウンロードファイルの使用、ディスクを使用したデータ交換、およびデータの待機はすべて、着信データを双方向で制御する必要性に関連していることに注意してください。NNMウィンドウ、チャート、およびファイルOpen1、2、3のデータは同一である必要があります。

情報管理

13. 情報管理

この図は、net1、net2、およびnet3からの応答のみをEAに渡すニューラルネットワークモジュールのバリアントを示しています。ポジションを開く条件は、エキスパートアドバイザーで指定されています。これが私の好みの方法です。ここでの場合、NNMは準備の整ったシグナルを提供し、EA取引を制限するのは時間だけです。

このような制御は、システムをデバッグするときに特に役立ちます。また、テストや取引中のパフォーマンスを視覚的に制御する必要があります。

NNMバリアント

14. NNMバリアント

上の図は、ニューラルネットワークモジュールの別のバリアントを示しています。このバリアントでは、ニューラルネットワークを実行可能ファイルに直接統合する方が適切です。緑色のボタンをクリックするときは、Input_mat.txtファイルを選択するだけです。仕事にも同様のモデルを使用することをお勧めします。このバリアントには、訓練ブロックとテストブロックがなく、取引ブロックのみがあります。システムの準備段階は明らかに複雑ですが、これによって取引が最大限に簡素化されることを忘れないでください。主な市場分析はNNMで実行されます。ニューラルネットワークを使用しているためこの手順は瞬時に行われます。他の最適化条件を使用しない場合、自動売買ロボットは受信した2桁を解釈するだけで済みます。 

 if(send1==false && Order1==1)
     {
      send1=trade.Buy(1);
      TicketBuy1 = trade.ResultDeal();
     }

 if(send1==true && Order1==0)
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }

結論として、MetaTrader4ターミナルで作業するためにExpertMatlabReal_MT4.ex4を起動する際のいくつかの違いについて詳しく説明したいと思います。これは、ストラテジーテスターの特定の機能、つまり、テストのコントロールポイントを決定する方法に関連しています。MetaTrader 5では、テストは前日の最後のバーで終了しますが、MetaTrader 4では、現在のバーが使用されます。そのため、MetaTrader4のEAに「Hours」外部変数を導入しました。

「Hours」外部変数

14.1「Hours」外部変数

ExpertMatlabPodkach_MT4.ex4を使用して、現在のバー行を含む履歴ダウンロードファイルを生成します。そのため、最初の起動時に「Hours」変数で現在のタイムバーを指定する必要があります。YAの開始後、そのプロパティを開き、変数を0に戻します。これにより、00:00にさらにデータシフトが実行されます。

時間 - 0

14.2時間 - 0

2. ビジュアルモードでのNNMテスト


このテストで準備が完了します。したがって、ニューラルネットワークモジュールは、準備、ニューラルネットワークトレーニング、受信した応答の配列、応答の視覚化、およびさらなる最適化に従って、望ましい結果を提供します。ここで、ポイント1からアクションを繰り返します。つまり、取引のようにNNMを起動します。また、視覚化を使用して、ストラテジーテスターでExpertMatlabReal_MT5.ex5を起動します。MetaTrader5で「1分OHLC」モードを有効にします。MetaTrader 4で、「コントロールポイント」を有効にします。NNMを使用する場合、バーが開いた後のティックで取引が実行されるため、信頼できるテスト結果を取得するには、これらのモデルを使用する必要があります。 「始値のみ」モデルを使用する場合、テスト中にポジションの始値が1バー遅れます。このモードでは、EURUSD_MT5var.exeモジュールを使用して応答遅延を簡単に考慮することができます。もちろん、これは実際の取引では起こりません。一般に、このシステムはすべてのタイプのテストでほぼ同じ結果を示します。これは、その実行可能性のもう1つの確認です。

視覚化

視覚化

15. 視覚モード


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


提供されているバージョンのこのニューラルネットワークモジュールモードは、ニューラルネットワークの訓練プロセスと実際の作業の準備を示すために使用されます。モジュールはすでに訓練済みのニューラルネットワークを使用していて、これらのニューラルネットワークは再訓練できないため、これはデモンストレーションモデルです。訓練はオフラインモードで実行され、最も効率的で信頼性の高いのはMATLAB環境で直接ニューラルネットワークを訓練することであるため、このようなサブモジュールを作業プログラムに追加する必要はありません。

 Net1サブモジュールの2つのニューラルネットワークをテストするには、ニューラルネットワークnet1-2と、訓練データを含むEURUSDData.csvファイルを...\Common\Filesディレクトリに配置する必要があります。

データ

16. データファイル

訓練データは実際のものです。これは、Onlineブロックを使用して取引システムを準備するために使用されるデータです。ニューラルネットワークを使用して市場の状況を評価することの利点をもう一度指摘したいと思います。EURUSDData.csvテーブルには、ニューラルネットワークの入力データとして使用される一連の順次値を表す90列があります。簡単に言えば、これらは入力です。各列が個別の指標であり、エキスパートアドバイザーによって事前に計算され、ニューラルネットワークを訓練するためのデータとして抽出されると想像してください。これはすべて、システムの準備時にオフラインモードで実行されます。ここで、取引中にこの印象的なデータセットを作業中のエキスパートアドバイザーで直接分析しようとすると想像してみてください。

本稿を書くにあたって、アクションの順序をよりよく理解するためにボタン名の名前を変更しました。

ボタン名の更新

17. ボタン名の更新


「Train net1」を押してnet1.matファイルを開き、Net1ブロック用にnet1とnet2の2つのネットワークを訓練します。Net2の場合はnet3とnet4、Net3の場合はnet5とnet6などです。

net1の訓練

18. net1の訓練


繰り返しになりますが、最も便利な方法は、作業ファイルが配置されているフォルダにプログラムショートカットを配置し、そのプロパティで「作業フォルダ」へのパスを変更することです。次に、NNMはネットワークを訓練します。

4. 取引戦略を最適化するためにニューラルネットワークブロックから応答を受信


ニューラルネットワークモジュールでは、オフラインモードでニューラルネットワークをテストする機能を追加しました。言い換えると、これは、システムの最適化を可能にするシグナル指標を作成するために、履歴データに基づいてニューラルネットワーク応答を受信する可能性です。これは、Net1から受信した応答の例です。

まず、\AppData\Roaming\MetaQuotes\Terminal\Common\FilesフォルダにあるEURUSDTestPodkach_MT5.csvファイルを準備します。これを行うには、ストラテジーテスターでExpertMatlabPodkach_MT5EAを起動します。これは、テスト開始日の前の日付から開始する必要があります(必要な履歴量がダウンロードされていることを確認してください)。

以下は例です。

Podkach

19. ExpertMatlabPodkach_MT5.ex5を起動する


結果のファイルの1行を除くすべての行を削除します。

EURUSDTestPodkach

20. 1行だけ残す


テスト期間データを含むファイルを生成するには、ストラテジーテスターでExpertMatlab_MT5.ex5を起動します。

ExpertMatlab

21. ExpertMatlab_MT5.ex5を起動する

期間の開始日の選択方法に注意してください。


EURUSDTest、EURUSDDate

22. EURUSDTest.csvとEURUSDDate.csvを取得する


ExpertMatlab_MT5.ex5は、2つのテストファイルEURUSDDate.csvとEURUSDTest.csvを生成します。ニューラルネットワークモジュールを起動し、[Test net1]をクリックして、net1.matを選択します。

net1をテストする

23. [Test net1]を押す

Indicator1.csv応答ファイルが生成されるまでしばらく待ちます。

Indicator1

24. 応答を含むIndicator1.csvファイルが生成される


Indicator1を指標として保存します。ニューラルネットワークブロックが「互換モード」で「Indicator1.csv」を保存している場合は、[Save As]タブからcsv形式で保存する必要があります。

指標

25. ndicator1.csvをIndicator.csvとして保存する


EURUSD H1チャートで、ビジュアルモードでのNNM応答を確認してみましょう。これを行うには、NWI.ex5指標を使用します。

NWI

26. NWI.ex5指標を起動する

デフォルト期間値は5です。私の実験によると、シグナル線のこの周期値はEURUSD H1に対して最良の結果を提供します。ただし、独自の値を見つけることを試んでください。

NWI

27. NWIの可視化


Matlab_MT5.ex5を使用して、受信した応答をテストし、さらに最適化することができます。

#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=Период-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++;
  }

//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double ret=0.0;
//---

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

Matlab_MT5

Matlab_MT5

28. Matlab_MT5.ex5を起動する

残高

29. 残高

フォワードテストを実施しても意味がありません。バックテストの後、フォワードテストは次の日付から開始されますが、ファイルにはバックテストが開始された開始日がロードされます。したがって、結果は正しくありません。

最適化を実行しましょう。以前のテストは、制限レベルなしで、本に記載されているシステム準備の原則に従って実施されました。最適化のために、より多くのレベルが導入されました。

最適

最適

最適

30. 最適化を実施する

最適化期間は2011年から2013年で、赤い線の前です。その後、2013年から2016年の期間がテストに使用されます。もちろん、ニューラルネットワークは時々再訓練する必要があるため、実際には、最適化後のこのような期間に取引する人は誰もいません。ここでの練習では、テストは1か月以内に実行する必要があります。チャートでは、赤い線と青い線の間の期間は4か月です。

この期間を個別にテストしてみましょう。

検証

検証

参照テスト 参照テスト

参照テスト

31. 参照テスト

私は以前にこれらのテストを実施したことがなかったので、これはすべて、記事のこのセクションを作成する過程で行われました。もちろん、他のオプションも使用できます。また、ヘッジニューラルネットワークを準備する必要もあります。ニューラルネットワークがシステムの準備と取引プロセスをどれだけ簡素化するかを強調したいと思います。

このテスト中にエミュレートされた取引は理想的な条件であったと言えます。したがって、このテストの結果を参考にします。

5. エラーの修正

この部分で作業しているときに、最初に戻って、この部分が非常に長い理由を説明することにしました。事実、この記事のセクションを書いている間、「エラーの修正」がリアルタイムで実行されました。これは前のセクションにも関係します。すべてがMetaTrader4のために準備されましたが、MetaTrader5のためにはリアルタイムモードで作業しなければなりませんでした。これは私にとって非常に有益な経験でした。とにかく、準備ステップは非常に重要であるため、非常に注意する必要があることに注意してください。

ポイント2に戻り、視覚化モードで結果(参照と呼びます)をテストする必要があります。

これが私たちが持っているものです。

レポート

32. 不合格のテスト

結果は良好ですが、前の結果とはまったく異なります。つまり、プログラムコードにエラーがあるので見つける必要があります。便利な機能は、すべてのデータ転送手順を追跡できることです。

Net1サブモジュールの出力フィールド(4)の応答と、ExpertMtatlab_MT5.ex5EAを使用して受信したNNM応答を比較してみましょう。同じバーを使用します。

応答の比較

33. 応答の比較

ご覧のとおり、Net1サブモジュールの応答とNNMの応答が一致していません。ニューラルネットワークの同じブロックを使用しているため、これら2つのテスト中に入力されたデータは異なると結論付けることができます。 

任意のバーを選択して、ファイルEURUSDTest.csvとInput_mat.txtのデータを比較します。

Input_mat.txt

34. データが一致するかどうかを比較します。


思った通り、データは本当に異なっています。そこで、ExpertMtatlab_MT5.ex5とExpertMatlabReal_MT5.ex5のプログラムコードを確認してみましょう。 

ExpertMtatlab_MT5.ex5
if(stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }
ExpertMatlabReal_MT5.ex5
if(Bar<Bars(NULL,PERIOD_H1) && stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }

ExpertMatlabReal_MT5.ex5コードでエラーが見つかりました。このファイルには、00時間のデータシフトの主な条件が含まれていませんでした。実際の作業では、NNMは、ネットワークが受信する必要のある情報に対応しない情報をターミナルから受信します。これは「誤った応答」を生成します。ニューラルネットワークは実際、通常の応答を生成するため、引用符を付けましたが、ネットワークに間違った情報を提供したため、これは誤りです。

ここでも、Net1サブモジュールの出力フィールド(4)の応答と、ExpertMtatlab_MT5.ex5EAを使用して受信したNNM応答を比較してみましょう。 

応答の比較

35. 応答の比較

これで、NNMに入力された情報が正しいことがわかります。

エラーを修正した後、もう一度ビジュアルモードでテストします。


検証

36. テストは参照とは異なる

結果はやや近くなりますが、それでも大幅に異なります。さらに、ニューラルネットワークモジュールは自ら終了しました。

確認したところ、ExpertMatlabReal_MT5.mq5の売りポジションの終了条件にエラーが見つかりました。1分間のOHLC、視覚化モードでもう一度テストします。

ティック待機なし

ティック待機なし ティック待機なし

ティック待機なし

37. ティック待機なしのテスト

結果が参照値と一致しません。

参照テスト

38. Reference

分析の結果、これは不利な条件下でエミュレートされた取引の結果であると結論付けることができます。これは、より多くの誤ったシグナルと不必要な取引につながりました。このような状況は、ポジションを開くシグナルが前のバーに表示され、反対の取引を開始するか、市場から離れるシグナルが次のバーに表示されたときに発生します。テストは加速モードで実行されるため、NNMからの情報が遅れる可能性があり、したがってEAは前のシグナルに基づいて取引を実行できます。ただし、この場合、このようなテストは、不利な市場条件下でシステムがどのように動作するかを確認する機会を与えてくれるので便利です。

上記の状況でEAポジションを開く制限を追加した後の結果を見てみましょう。

 if(Order1==0 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send0=true;
   
 if(Order1==1 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send1=true;

//---------Buy

テストは、ティックを使用して、最高の視覚化速度で実行されます。ビデオでプロセスをご確認ください。

条件でテストする

条件でテストする 条件でテストする

条件でテストする

39. 結果は参照に近い


ご覧のとおり、結果は参照に近いものです。とはいえ、テスト速度を落とせば、前回のテストも参考に近いと思います。ご自分でお試しください。


それでは、NNMが終了した理由を調べてみましょう。この部分はスキップできますが、テストモードでこのバグを見つけたのは良いことです。実際の取引中に問題が検出された場合は、状況はもっと悪かったでしょう。NNMのニューラルネットワークが訓練されていない場合、または取引EAの起動前にモジュールを起動した場合、その時点までにInput_mat.txtファイルは生成されておらず、[Start]をクリックした後もNNMは応答しません。当初、警告ウィンドウと内部タイマーの強制終了を追加しました。この論理エラーは削除しましたが、警告を残しました。ただし、作業中にウィンドウがポップアップした場合は、[OK]をクリックしてウィンドウを非表示にしてください。プログラムは動作を継続します。

エラーウィンドウ

40. エラーウィンドウ

注意が必要な問題があと1つあります。MetaTrader 5では、戦略データを使用してデータを書き込むと、生成されたバーの数がグラフに表示されている数よりも多くなります。このため、結果の指標はやや「長く」なります。ただし、これはテストの品質には影響しません。余分なバーはテストパスで考慮されますが、チャートには表示されません。これは、ステップバイステップパスで確認できます。

MetaTrader5指標

41. MetaTrader 5のNWI指標

MetaTrader5指標

42. タイムシフトがある

この問題はMetaTrader4には存在しません。

MetaTrader4指標

43. MetaTrader 4の1_MT4指標

MetaTrader4指標

44. シフトなし

次の図は、これが発生する理由を示しています。

23:59

45. シフトの理由の解明

終わりに

ニューラルネットワークを使用する目的は何でしょうか。

  1. ニューラルネットワークは、市場外の大量の情報の処理を可能にします。
  2. 情報はオフラインモードで処理されるため、市場を追いかけるのではなく、市場を先取りすることができます。さもなければ、少なくとも市場についていくことができます。
  3. したがって、トレンドが変化した場合や他の要因が市場に影響を与えた場合に、大きな損失をなくすことができます。その結果、ニューラルネットワークは、取引中だけでなく、準備段階でも、市場の状況の変化にタイムリーに対応することができます。
  4. 本稿で紹介されている特定のニューラルネットワークとその訓練方法に関して、この組み合わせの疑いのない利点は、ニューラルネットワークが訓練された期間に受信した応答を使用してEAを最適化できることです。他のアーキテクチャに基づくニューラルネットワークは訓練モードでは良好な結果を示しますが、テスト期間の結果は大幅に異なります。ここでの場合、結果はほぼ同じです。これにより、現在の日付の近くでNNをテストし、履歴で利用可能な市場要因を考慮に入れることができます。この部分は本稿では取り上げられていませんが、ご自分でお調べください。

この記事を書いているとき、私は当初、記事の公開時までに訓練されたNet1ニューラルネットワークのみをNNMに統合したいと考えていました。しかし、完了時に、2019年12月31日までにNet2用に訓練されたニューラルネットワークとNet3様の2010年12月31日までのデータを統合することにしました。現在の市況でそれらをテストすることは興味深いです。NNM内の他のすべての作業では、Net1のニューラルネットワークのみが使用されます。

ファイルをダウンロードした後

ビデオが長いことをお詫びします。プロセスはほぼ1フレームで撮影されました。


Python