神经网络在交易中的实际应用 (第二部分). 计算机视觉

16 三月 2021, 10:58
Andrey Dibrov
0
642

介绍

为交易设计的训练神经网络准备数据的一个基本问题是准备必要的输入数据。例如,当我们使用十几个指标时,请考虑这种情况。这些指标可能代表一组若干信息图表。如果我们将这些指标计算到一定的深度,那么结果将多达100个条目,在某些情况下甚至更多。我们能用计算机视觉使神经网络训练更容易吗?为了解决这个问题,让我们使用卷积神经网络,这是经常用来解决分类和识别问题。


卷积神经网络结构

在本文中,我们将使用卷积神经网络,其架构如图所示。该方案给出了构造卷积神经网络(CNN)的一般原理。 

在这种情况下,我们有:

  1. CNN输入,大小为449x449像素的图像。
  2. 第一个卷积层包含96个特征图(feature map),每张图都是447x447大小的图像。卷积核为 3x3。
  3. 子样本层包含96个特征图,大小为223x223,内核为2x2。
  4. 第二层卷积32个特征图,每张图都是大小为221x221的图像。卷积核为 3x3。
  5. 32个特征映射的子样本层,大小为110x110,内核为2x2。
  6. 第三层卷积16个特征图,每张图都是108x108大小的图像。卷积核为 3x3。
  7. 子样本层包含16个特征图,大小为54x54,内核为2x2,图中未显示。
  8. 64个神经元的完全连接层。
  9. 一个神经元的输出层。这两层代表分类单元。

CNN

如果你是新的卷积神经网络,不要担心看似繁琐和复杂的建设。给定结构的神经网络是自动建立的,您只需要设置主要参数。 

为神经网络训练和测试准备一组图像

在准备一组图像之前,先定义神经网络的用途。理想情况下,在轴枢点上训练网络会很好。根据这个目的,我们需要用最后一个极值柱做截图。然而,这个实验没有实际价值。这就是为什么我们将使用另一组图像。此外,还可以使用不同的数组进行实验,包括上面提到的数组。这也可能为神经网络在解决基于图像的分类任务时的效率提供额外的证据。在连续时间序列上获得的神经网络响应需要额外的优化。 

让我们不要把实验复杂化,集中在两类图像上:

  • 买入 - 当价格上涨或达到每日低点时
  • 卖出 - 当价格下跌或达到每日高点时

买入   买入1  买入2  买入3

出于神经网络训练的目的,任何方向的移动都将被确定为价格在趋势方向上达到新的极值。此时将制作图表截图。趋势反转时刻对网络训练也很重要。当价格达到每日高点或低点时,还将制作图表截图。

在开始操作之前,我们需要准备图表外观。使用 CNN.tpl 模板。把它保存到 \AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Profiles\Templates.

CNN.tpl

在图表属性中将文本定义为“White”。

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

脚本在两种模式下工作:“Train”-创建一个用于训练的图像数组,“Test”-创建一个用于获取神经网络响应的图像数组,根据该数组将生成一个指标。此外,该指标将用于优化交易策略。 

让我们以“Train”模式运行脚本。

Train

变量“Date”- 样本的初始数据,将在其中选择用于训练的图像。"DateOut' — 选择用于训练的图像的采样周期的结束日期。"DateTest" — 从神经网络中选择图像以获得每小时响应的开始日期。结束日期将是脚本启动时间。 

一系列买入。。。卖出。。。图像将保存在数据目录的…\MQL5\Files文件夹中。图片总数为6125张。

Tren

接下来,为训练、验证和测试集准备目录。为方便起见,在桌面上创建“CNN”文件夹,并在其中创建三个文件夹-“Train”、“Val”、“Test”。

CNN

在“Train”和“Val”目录中,创建子目录“Buy”和“Sell”。在“Test”下创建一个子目录“Resp”。

Train

从文件夹..\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”模式运行脚本。

测试

一组连续的每小时屏幕截图将保存到 ...\MQL5\文件中。它们现在是12558个。不要将它们分开或分组,因为神经网络应该自己进行分组。更准确地说,网络应该显示图像与网络训练条件相对应的概率。向上和向下移动。向下移动并向上翻转。 

将这些文件剪切粘贴到 ...CNN\Test\Resp。

测试

我们准备了一组图像,用于测试响应和优化策略。日期和时间为 EURUSDDate 的文件,保留在..\MQL5\files下,应该移动到CNN文件夹。

我想指出 MetaTrader 5 的一个特殊特性。在策略测试器中使用专家顾问来准备一组图像将更加方便和可靠。但是,MetaTrader 5不提供在策略测试器中创建屏幕截图的功能。无论如何,这个特定功能不会影响交易机器人的创建。


训练神经网络

我们将使用 Anaconda 环境处理卷积网络。它应该配置为与 CPU 和 GPU(如果你有一个NVIDIA显卡)一起工作。这个显卡是加快学习过程所需要的。尽管如此,它还是对创建神经网络体系结构施加了一些限制——依赖于显卡的RAM数量。但学习速度明显提高。例如,在我的例子中,CPU上的一个训练 epoch 持续20分钟,而GPU上需要1-2分钟。如果网络是40个 epoch 的训练,那么我将需要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. 在GPU下创建一个新的“conda”环境。键入命令 conda create--name PythonGPU。激活环境 - activate PythonGPU.
    GPU

  6. 安装 tensorflow gpu, 键入命令 conda create -n PythonGPU python=3.6 tensorflow-gpu. 请注意,应为 python 3.6 安装 tensorflow gpu。
      tensorflow gpu

  7. 安装 keras gpu, 键入命令 conda install -c anaconda keras-gpu.
    keras gpu

  8. 在 Python GPU 环境中安装用于编程的 Jupyter 接口。CPU Jupyter 在安装 Anaconda 时已经安装好了。键入命令 - conda install jupyter.
      Jupyter

  9. 安装另外两个库, Pandas 和 Pillow - conda install -c anaconda pandas. 然后 - conda install pillow. 如果您不打算使用显卡,也应该为CPU安装这些库。
    pandas 

  10. pillow

  11. 我们现在可以开始训练卷积神经网络了。将两个文件添加到先前创建的CNN文件夹: Train.ipynb and Test.ipynb. 这些是 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像素,三通道(红色、绿色和蓝色)。这里我们使用彩色图像,你也可以尝试单色图像
  • 创建第一个用于处理二维数据的卷积层:96个特征图,每个特征图都有3x3卷积内核。卷积层的每个神经元连接到图像的一个3x3的正方形部分 
  • 激活层使用“relu”函数,计算量较小
  • 为了减少维数,添加一个带有2x2内核的子采样层,从这个正方形中选择最大值
  • 接下来,再添加两个卷积层(32核和16核)、两个激活层和两个子样本
  • 将二维数据转换为一维格式
  • 将转换后的数据传递到具有64个神经元的完全连接层
  • 使用Dropout(0.5)正则化层函数尽量避免过拟合
  • 添加一个带有一个神经元的完全连接的输出层。使用了两个图像类,因此网络响应将以二进制响应的形式接收。也可以尝试几个类。例如,两个表示趋势,一个表示横盘。在这种情况下,输出层将有三个神经元。另外,我们需要将图像分为三类。
  • “sigmoid”激活函数。它很适合用于分类,并且在我的实验中已显示出最好的性能

这个架构的例子可以很容易地更新-我们可以增加层的数量和它们的大小,根据序列改变它们的位置,改变卷积核的维数,修改激活函数和使用完全连接的层。然而,这里出现了一个难题:当使用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。但是,实际值将从0到1分布。选择梯度下降(Gradient Descent)优化器。它似乎是最适合神经网络训练的。选择准确度指标,即正确答案的百分比。 

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

对图像像素强度数据进行归一化处理。

datagen = ImageDataGenerator(rescale=1. / 255)

使用Keras生成器从磁盘读取数据,并为神经网络创建训练和验证图像阵列。同样, class_mode 是 'binary'. 将 Shuffle 设置为“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

After the end of the training process, 20 trained neural networks will appear under the CNN folder.

CNN

Let us view training results and select a neural network for further use.


NN

乍一看,在第18个epoch时,神经网络的学习错误率为30%,正确率为85%。然而,当在验证集上运行神经网络时,我们看到错误增加,正确答案的百分比下降。所以,我们应该选择一个在第11 epoch 训练的网络。它在验证集有最合适的结果: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 epoch 后保存的神经网络。

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.

在 EURUSD H1 图表上运行 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++;
  }
//+------------------------------------------------------------------+


让我们同时优化的信号线期间,时间和止损订单的交易在两个方向上。


优化

优化1

在图表线之前的一段时间内对神经网络进行训练,并对垂直红线进行优化。然后对优化后的神经网络响应进行测试。上面的图表显示了两个随机的正优化结果,优化器将其显示为最高优先级的结果。


神经网络层次的可视化与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)

打印一个特征图,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')

形状

看看第三个特征图(2)。

形状2

在这里,神经网络突出所有的烛形,但使用了不同的灯芯。由于这一点,这幅画像是三维的。但是,你可以再次看到下跌烛形灯芯和抛物线有相同的颜色。

现在看下一个卷积层(3)第5张图。


形状5

在这里,抛物线点重叠,CNN 将其识别为横盘模式的标志。根据上图,神经网络对这一部分的渲染方式有所不同。因此,我们可以得出这样的结论:用于训练的图像类别已经扩展。我们需要引入另一个类别来训练神经网络-横盘。

因此,视觉检查卷积神经网络的特征图,使训练任务的规格更明确。这也可能有助于扩大CNN识别的特征类别,以及减少噪音。

结论

利用卷积神经网络的公开工具和功能,我们可以将一种有趣且非传统的方法应用于技术分析。同时,这可以大大简化神经网络训练数据的准备。内部过程的可视化有助于分析哪些输入数据对培训质量影响最大。 

最后,我想提到优化。正如我之前写的,这是一个非常简单的优化。但是,它应该与我们为网络设定的任务保持一致。根据这些任务,训练数组应该被划分为类别。此外,在创建交易机器人时应使用这些条件。


本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: 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)
神经网络变得轻松(第十部分):多目击者关注 神经网络变得轻松(第十部分):多目击者关注
我们以前曾研究过神经网络中的自关注机制。 在实践中,现代神经网络体系结构会采用多个并行的自关注线程来查找序列元素之间的各种依存关系。 我们来研究这种方法的实现,并评估其对整体网络性能的影响。
神经网络变得轻松(第九部分):操作归档 神经网络变得轻松(第九部分):操作归档
我们已经经历了很长一段路,并且函数库中的代码越来越庞大。 这令跟踪所有连接和依赖性变得难以维护。 因此,我建议为先前创建的代码创建文档,并保持伴随每个新步骤进行更新。 正确准备的文档将有助我们看到操作的完整性。
自适应算法(第三部分): 放弃优化 自适应算法(第三部分): 放弃优化
如果采用基于历史数据的优化方法来选择参数,就不可能得到真正稳定的算法。一个稳定的算法应该知道在任何时候操作任何交易工具时需要哪些参数。它不应该预测或猜测,它应该确定知道。
利用 CatBoost 算法寻找外汇市场的季节性模式 利用 CatBoost 算法寻找外汇市场的季节性模式
本文探索了用时间过滤器建立机器学习模型,并讨论了这种方法的有效性。现在,只要简单地指示模型在一周中某一天的某个时间进行交易,就可以消除人为因素。模式搜索可以由单独的算法提供。