English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
「サル」でもわかるMQL:オブジェクトクラスの設計 構築方法

「サル」でもわかるMQL:オブジェクトクラスの設計 構築方法

MetaTrader 5エキスパートアドバイザー | 5 10月 2015, 14:02
6 037 0
Sergey Pavlov
Sergey Pavlov

オブジェクト指向プログラミング(OOP)への入門

「初心者」の方の質問:手続き型プログラミングへの曖昧な理解のまま、OOPをマスターし、自動トレーディング戦略の作成を行うことができるのでしょうか?この作業は普通のユーザーには難しすぎるものでしょうか?

一般的に、オブジェクト指向プログラミング の規則を使用せずとも、MQL5エキスパートアドバイザーやインジケーターの作成にオブジェクト指向プログラミング言語を用いることができます。開発において新しい技術の使用は必須ではありません。あなたの思う最も簡単な方法を選択してください。また、OOPのアプリケーションは、あなたの作成する取引システムの収益性を保証することはできません。

しかしながら、(オブジェクト指向の)新しい手法への移行は、トレーディング戦略のより複雑な数学的モデルを、市場の動き、外部環境の変化に応じるエキスパートアドバイザーに適応させるための基盤を築くことができます。

それでは、OOPの基礎となる技術を見てみましょう。

  1. イベント
  2. オブジェクトクラス

イベントはOOPの主要な基礎となる部分です。プログラム全体のロジックは、断続的に到来するイベントへの処理に基づいています。それらイベントに対する適切な対応は、オブジェクトクラス内に定義され、記述されます。つまり、クラスオブジェクトは、イベントの流れを捕まえ、処理することにより稼働します。

次に基礎となるものとして、オブジェクトクラスがあり、それは「3本の柱」で成り立ちます。

  1. カプセル化 - クラスの保護が「ブラックボックス」の理論に基づきます:オブジェクトはイベントに応答しますが、実際の実行処理は知られずに保たれます。
  2. 継承 - 既存のクラスから新しいクラスを、「親クラス」の属性やメソッドを保持しながら作成することです。
  3. 多相性 - 「孫」クラスにおける継承されたメソッドの実行内容を変化することができることです。

基礎的なコンセプトは、エキスパートアドバイザーコードで最も詳しく紹介されています。

イベント:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()                        // OnInit event processing
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)     // OnDeInit event processing
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()                       // OnTick event processing
  {
  }
//+------------------------------------------------------------------+
//| Expert Timer function                                            |
//+------------------------------------------------------------------+
void OnTimer()                      // OnTimer event processing
  {
  }
//+------------------------------------------------------------------+
//| Expert Chart event function                                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,     // OnChartEvent event processing
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
  }

オブジェクトクラス:

class CNew:public CObject
  {
private:
   int               X,Y;
   void              EditXY();
protected:
   bool              on_event;      //events processing flag
public:
   // Class constructor
   void              CNew();
   // OnChart event processing method
   virtual void      OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

カプセル化:

private:
   int               X,Y;
   void              EditXY();

継承:

class CNew: public CObject

多相性:

// OnChart event processing method
   virtual void      OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);

このメソッドの 仮想(virtual) 修飾子は、OnEventハンドラが再定義できることを意味しますが、この場合のメソッド名は親クラスと同じ名前で保持されます。


2. クラスの設計

OOPの重要な利点の一つに、拡張性があります - つまり、既存のシステムが変更せずにも新しいコンポーネントを扱うことができるということです。新しいコンポーネントをこのステージにて追加することができます。

MQL5のMsterWindowsクラスの視覚的デザインのプログラム作成により、設計の手順を考察してください。


2.1. ステージ1:プロジェクトの原案

設計のプロセスは、紙にペンで下書きを書くことから始まります。これは、プログラミングにおいて最も困難で楽しい瞬間の一つです。プログラムとユーザー間の対話だけではなく、データ処理の構造も考慮する必要があります。このプロセスは1日以上かかることもあります。基本的にはインターフェースから始めることが最も良いと思います。というのも、アルゴリスムの構築の際に、それが定義となることがあるからです。(ここでの例でもいくつかそのようになるケースがあります。)

作成したプログラウのダイアログの構築のため、Windowsアプリケーションウィンドウに類似したフォームを使用します。(図1の下書きをご覧ください)複数の行や、セルとグラッフィクオブジェクトのセルを持ちます。そして、概念設計のステージでは、プログラムの構造や、オブジェクトの分類などを紹介致します。

図1クラスのコンストラクター(下書き)

図1. クラスのコンストラクター(下書き)

かなり多くの数の行やセル(フィールド)を用いられた、ニ種類のグラフィックオブジェクトにより成り立っています。OBJ_EDITOBJ_BUTTON の二つです。従って、視覚的な外見や構造、プログラムに作成される基礎的なオブジェクトを決定すれば、設計の下書きは完成し、次のステージへ移ることができます。


2.2 ステージ2:ベースクラスの設計

今のところ3つのクラスがあり、今後(必要であれば)さらに追加していくことができます。

  • セルクラス CCell
  • セルのクラスであるCCellから成り立つ、行クラスCRow
  • 行クラスのCRowから成り立つ、ウィンドウクラスのCWin

直接プログラミングクラスに進むことができますが、重要なタスクである、クラスのオブジェクト間でのデータの取り交わしを行う必要があります。そのために、MQL5言語は、基本的な変数に加えて、新しいタイプ - ストラクチャーというものを持っています。もちろん、このステージにおいて、全ての接続部分を見ることや、計算を行うことはできません。そのため、プロジェクトを進めつつ、クラスやストラクチャーの記述を埋めていきたいと思います。さらに、OOPの原則は、この仕組みを阻害するというのではなく、むしろ逆で、技術やプログラミングを促進するものです。

WinCell ストラクチャー:

struct WinCell
  {
   color             TextColor;     // text color
   color             BGColor;       // background color
   color             BGEditColor;   // background color while editing
   ENUM_BASE_CORNER  Corner;         // anchor corner
   int               H;            // cell height
   int               Corn;         // displacement direction (1;-1)
  };

Stringや動的配列オブジェクトを持たないストラクチャーをシンプルストラクチャーと呼びます。異なるストラクチャー同士でも、そのようなストラクチャーの変数は、互いに自由にコピーされることができます。構築されたストラクチャーはこのような形です。効果の測定は後ほど行います。

ベースクラス CCell:

//+------------------------------------------------------------------+
//| CCell base class                                                 |
//+------------------------------------------------------------------+
class CCell
  {
private:
protected:
   bool              on_event;      // event processing flag
   ENUM_OBJECT       type;           // cell type
public:
   WinCell           Property;     // cell property
   string            name;          // cell name
   //+---------------------------------------------------------------+
   // Class constructor
   void              CCell();
   virtual     // Draw method
   void              Draw(string m_name,
                          int m_xdelta,
                          int m_ydelta,
                          int m_bsize);
   virtual     // Event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

ベースクラス CRow:

//+------------------------------------------------------------------+
//| CRow base class                                                  |
//+------------------------------------------------------------------+
class CRow
  {
protected:
   bool              on_event;      // event processing flag
public:
   string            name;          // row name
   WinCell           Property;     // row property
   //+---------------------------------------------------------------+
   // Class constructor
   void              CRow();
   virtual     // Draw method
   void              Draw(string m_name,
                          int m_xdelta,
                          int m_ydelta,
                          int m_bsize);
   virtual     // Event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

ベースクラス CWin:

//+------------------------------------------------------------------+
//| Base CWin class (WINDOW)                                         |
//+------------------------------------------------------------------+
class CWin
  {
private:
   void              SetXY(int m_corner); //Coordinates
protected:
   bool              on_event;   // event processing flag
public:
   string            name;       // window name
   int               w_corner;   // window corner
   int               w_xdelta;   // vertical delta
   int               w_ydelta;   // horizontal detla
   int               w_xpos;     // X coordinate
   int               w_ypos;     // Y coordinate
   int               w_bsize;    // Window width
   int               w_hsize;    // Window height
   int               w_h_corner; // hide mode corner
   WinCell           Property;   // Property
   //---
   CRowType1         STR1;       // CRowType1
   CRowType2         STR2;       // CRowType2
   CRowType3         STR3;       // CRowType3
   CRowType4         STR4;       // CRowType4
   CRowType5         STR5;       // CRowType5
   CRowType6         STR6;       // CRowType6
   //+---------------------------------------------------------------+
   // Class constructor
   void              CWin();
   // Set window properties
   void              SetWin(string m_name,
                            int m_xdelta,
                            int m_ydelta,
                            int m_bsize,
                            int m_corner);
   virtual     // Draw window method
   void              Draw(int &MMint[][3],
                          string &MMstr[][3],
                          int count);
   virtual     // OnEventTick handler
   void              OnEventTick();
   virtual     // OnChart event handler method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

説明と推奨:

  • 全てのベースクラスは、イベント処理用のメソッドを持っています。順に沿ってイベントを受け持ち、伝達する必要があるのです。イベントを受け取り、送信する仕組みがなければ、プログラム(もしくはモジュール)はインタラクティビティを失うこととなります。
  • ベースクラスの開発時には、最小数のメソッドで作成してみてください。そして、作成されたオブジェクトの機能性を向上させる「派生」クラスの中で様々な拡張を実行してみてください。
  • 別のクラスの内部データへの直接の呼び出しは控えてください。


2.3. ステージ3:ワーキングプロジェクト

ここでは、プログラムの作成をステップごとに始めていきます。サポート用フレームワークから始め、機能コンポーネントを増やし、内容を記述します。この際、作業の正誤をチェックし、デバッギングを行い、表示されるエラーを追っていきます。

ここでひとまず作業を中断し、ほとんど全てのプログラムで作動するフレームワークの作成技術について考察してみましょう。主に重要な箇所は - (エラーなくコンパイルし稼働するなど)ただちに作動しうるという点です。言語設計者は、この点に注意し、MQL5ウィザードにて生成されるフレームワークとしてのエキスパートアドバイザーテンプレートを使用することを推奨しています。

例として、以下のテンプレートをみてみましょう。

1) Program = Expert Advisor

//+------------------------------------------------------------------+
//|                                                MasterWindows.mq5 |
//|                                                 Copyright DC2008 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
#property link      "http://www.mql5.com"
#property version   "1.00"
//--- include files with classes
#include <ClassMasterWindows.mqh>
//--- Main module declaration
CMasterWindows    MasterWin;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Launch of the main module
   MasterWin.Run();
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Deinitialization of the main module
   MasterWin.Deinit();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- call OnTick event handler of main module
   MasterWin.OnEventTick();
  }
//+------------------------------------------------------------------+
//| Expert Event function                                            |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- call OnChartEvent handler of main module
   MasterWin.OnEvent(id,lparam,dparam,sparam);
  }

こちらがエキスパートアドバイザーの完成版のコードです。このプロジェクトにおいて、さらなる追加変更は必要ではありません。

2) メインモジュール = クラス

全ての主要な、また補助的なプロジェクトのモジュールは、ここからその開発を始めます。この手法は、複雑なマルチモジュールプロジェクトのプログラミングを容易にし、起こりうるエラーを検索します。しかし、その発見は容易ではありません。時折、わかりにくい「バグ」を見つだすよりも、新しいプロジェクトを作成した方が容易く、早いこともしばしばあります。

//+------------------------------------------------------------------+
//|                                           ClassMasterWindows.mqh |
//|                                                 Copyright DC2008 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
#property link      "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Main module: CMasterWindows class                                |
//+------------------------------------------------------------------+
class CMasterWindows
  {
protected:
   bool              on_event;   // event processing flag
public:
   // Class constructor
   void              CMasterWindows();
   // Method of launching the main module (core algorithm)
   void              Run();
   // Deinitialization method
   void              Deinit();
   // OnTick event processing method
   void              OnEventTick();
   // OnChartEvent event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

クラスの主要なメソッドの冒頭の記述が以下になります。

//+------------------------------------------------------------------+
//| CMasterWindows class constructor                                 |
//+------------------------------------------------------------------+
void CMasterWindows::CMasterWindows()
   {
//--- class members initialization
   on_event=false;   // disable events processing
   }
//+------------------------------------------------------------------+
//| Метод запуска главного модуля (основной алгоритм)                |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
   {
//--- Main functional of the class: runs additional modules
   ObjectsDeleteAll(0,0,-1);
   Comment("MasterWindows for MQL5     © DC2008");
//---
   on_event=true;   // enable events processing
   }
//+------------------------------------------------------------------+
//| Deinitialization method                                          |
//+------------------------------------------------------------------+
void CMasterWindows::Deinit()
   {
//--- 
   ObjectsDeleteAll(0,0,-1);
   Comment("");
   }
//+------------------------------------------------------------------+
//| OnTick() event processing method                                 |
//+------------------------------------------------------------------+
void CMasterWindows::OnEventTick()
   {
   if(on_event) // event processing is enabled
     {
     //---
     }
   }
//+------------------------------------------------------------------+
//| OnChartEvent() event processing method                           |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
     //---
     }
  }

3)基礎的な派生クラスのライブラリ

ライブラリは、派生クラスをいくつでも持つことができ、個別のファイルにグループ化するのに最適です。このように、エラーの検索と同様、必要な変更や追加をより簡単に行えます。

そして、やっとプログラムのフレームワークを持つことができます。テストし、正しく動作するか確認しましょう:(コンパイルと実行)もしテストが成功であれば、追加モジュールをプロジェクトに追加していきます。

派生クラスの接続を開始し、セルからスタートしましょう:

Nameクラス イメージ
CCellText クラス
CCellEdit クラス
CCellButton クラス
CCellButtonType クラス
CCellButtonType クラス

表 1. セルクラスのライブラリ

CCellButtonTypeの派生クラスの作成を詳しく見てみましょう。このクラスは様々なボタンを作成します。

//+------------------------------------------------------------------+
//| CCellButtonType class                                            |
//+------------------------------------------------------------------+
class CCellButtonType:public CCell
  {
public:
   ///Class constructor
   void              CCellButtonType();
   virtual     ///Draw method
   void              Draw(string m_name,
                          int m_xdelta,
                          int m_ydelta,
                          int m_type);
  };
//+------------------------------------------------------------------+
//| CCellButtonType class constructor                                |
//+------------------------------------------------------------------+
void CCellButtonType::CCellButtonType()
  {
   type=OBJ_BUTTON;
   on_event=false;   //disable events processing
  }
//+------------------------------------------------------------------+
//| CCellButtonType class Draw method                                |
//+------------------------------------------------------------------+
void CCellButtonType::Draw(string m_name,
                           int m_xdelta,
                           int m_ydelta,
                           int m_type)
  {
//--- creating an object with specified name
   if(m_type<=0) m_type=0;
   name=m_name+".Button"+(string)m_type;
   if(ObjectCreate(0,name,type,0,0,0,0,0)==false)
      Print("Function ",__FUNCTION__," error ",GetLastError());
//--- object properties initializartion
   ObjectSetInteger(0,name,OBJPROP_COLOR,Property.TextColor);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,Property.BGColor);
   ObjectSetInteger(0,name,OBJPROP_CORNER,Property.Corner);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xdelta);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ydelta);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,Property.H);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,Property.H);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,0);
   if(m_type==0) // Hide button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(MIN_WIN));
      ObjectSetString(0,name,OBJPROP_FONT,"Webdings");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,12);
     }
   if(m_type==1) // Close button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(CLOSE_WIN));
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 2");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8);
     }
   if(m_type==2) // Return button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(MAX_WIN));
      ObjectSetString(0,name,OBJPROP_FONT,"Webdings");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,12);
     }
   if(m_type==3) // Plus button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,"+");
      ObjectSetString(0,name,OBJPROP_FONT,"Arial");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,10);
     }
   if(m_type==4) // Minus button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,"-");
      ObjectSetString(0,name,OBJPROP_FONT,"Arial");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,13);
     }
   if(m_type==5) // PageUp button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(PAGE_UP));
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 3");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8);
     }
   if(m_type==6) // PageDown button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(PAGE_DOWN));
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 3");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8);
     }
   if(m_type>6) // empty button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,"");
      ObjectSetString(0,name,OBJPROP_FONT,"Arial");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,13);
     }
   on_event=true;   //enable events processing
  }
//+------------------------------------------------------------------+

必要な説明;

  • イベント処理の禁止令のクラスコンストラクターへの導入を行います。これは、作動する上でのオブジェクトを準備し、イベントの乱れを除去するために必要なことです。必要な動作の完成ののち、処理を進め、オブジェクトは完全に機能し始めます。
  • drawメソッドは、内部データを使用し、外部データを受け取ります。従って、コンプライアンスのためまず初めにデータはテストされ、例外の状況を避けるため処理される必要があります。しかし、この特定のケースにおいてこのテストを行いません。それはどうしてでしょうか?クラスオブジェクトは一人の兵士であり、必ずしも将軍の計画を知る必要はないことを想像してみてください。彼らの仕事は、簡潔に、また、迅速に、厳密に指揮官の命令を遂行し、与えられた命令を分析し、独自の判断を下してはなりません。従って、全ての外部データは、クラスを扱う前に全てコンパイルされる必要があります。

そして、セルの全ライブラリをテストする必要があります。このためには、以下のコードをメインモジュールを(一時的にテストのため)挿入し、エキスパートアドバイザーを稼働してくみましょう。

//--- include file with classes
#include <ClassUnit.mqh>
//+------------------------------------------------------------------+
//| Main module: CMasterWindows class                                |
//+------------------------------------------------------------------+
class CMasterWindows
  {
protected:
   bool              on_event;   // events processing flag
   WinCell           Property;   // cell property
   CCellText         Text;
   CCellEdit         Edit;
   CCellButton       Button;
   CCellButtonType   ButtonType;
public:
   // Class constructor
   void              CMasterWindows();
   // Main module run method (core algorithm)
   void              Run();
   // Deinitialization method
   void              Deinit();
   // OnTick event processing method
   void              OnEventTick();
   // OnChart event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };
//+------------------------------------------------------------------+
//| Main module run method (core algorithm)                          |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
  {
//--- core algorithm - it launches additional modules
   ObjectsDeleteAll(0,0,-1);
   Comment("MasterWindows for MQL5     © DC2008");
//--- Text field
   Text.Draw("Text",50,50,150,"Text field");
//--- Edit field
   Edit.Draw("Edit",205,50,150,"default value",true);
//--- LARGE BUTTON
   Button.Draw("Button",50,80,200,"LARGE BUTTON");
//--- Hide button
   ButtonType.Draw("type0",50,100,0);
//--- Close button
   ButtonType.Draw("type1",70,100,1);
//--- Return  button
   ButtonType.Draw("type2",90,100,2);
//--- Plus button
   ButtonType.Draw("type3",110,100,3);
//--- Minus button
   ButtonType.Draw("type4",130,100,4);
//--- None button
   ButtonType.Draw("type5",150,100,5);
//--- None button
   ButtonType.Draw("type6",170,100,6);
//--- None button
   ButtonType.Draw("type7",190,100,7);
//---
   on_event=true;   // enable events processing
  }

そして、結果として生じるクラスにイベントを移すことを忘れてはいけません。もしこれが行われなければ、プロジェクトのハンドリングは困難、または、不可能になります。

//+------------------------------------------------------------------+
//| CMasterWindows class OnChart event processing method             |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
      //--- process events for the cell class objects
      Text.OnEvent(id,lparam,dparam,sparam);
      Edit.OnEvent(id,lparam,dparam,sparam);
      Button.OnEvent(id,lparam,dparam,sparam);
      ButtonType.OnEvent(id,lparam,dparam,sparam);
     }
  }

結果として、セルクラスのライブラリのオブジェクトにおける使用可能なオブションを全て見ることができます。

図 2セルクラスのライブラリ

図 2. セルクラスのライブラリ

作動効率とイベントへのオブジェクトの反応をテストしてみましょう:

  • 「デフォルト」の代わりに、編集フィールドの異なる変数をみてみます。もし変数が変化している場合、テストは成功です。
  • ボタンを押し、またボタンが押されるまで、押された状態で維持されます。しかし、これは満足のいく反応ではありません。一度押した後、ボタンが元の状態に自動的に戻って来る必要があります。そして、これは、OOPの力、継承の可能性を紹介することができるところです。私たちのプログラムは、いくつかのボタンを使用し、個別にそれぞれに対して望んだ機能を追加する必要はありません。CCellベースクラスを変更するだけで十分であり、すべての派生クラスのオブジェクトは、適切に動き始めるのです!
//+------------------------------------------------------------------+
//| CCell class OnChart event processing method                      |
//+------------------------------------------------------------------+
void CCell::OnEvent(const int id,
                    const long &lparam,
                    const double &dparam,
                    const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
      //--- button click event
      if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".Button",0)>0)
        {
         if(ObjectGetInteger(0,sparam,OBJPROP_STATE)==1)
           {
            //--- if button stays pressed
            Sleep(TIME_SLEEP);
            ObjectSetInteger(0,sparam,OBJPROP_STATE,0);
            ChartRedraw();
           }
        }
     }
  }

そして、セルクラスのライブラリは、テストされ、プロジェクトに接続されます。

次のステップは、行ライブラリの追加です:

Nameクラス イメージ
CRowType1(0) クラス
CRowType1 (1) クラス
CRowType1 (2) クラス
CRowType1 (3) クラス
CRowType2 クラス
CRowType3 クラス
CRowType4 クラス
CRowType5 クラス
CRowType6 クラス

表 2. 行クラスのライブラリ

同様にテストを行います。すべてのテストの後、次のステージに進みます。


2.4ステージ4: プロジェクトの構築

この地点にて、すべての必要なモジュールは作成され、テストされました。それでは、プロジェクトの構築に進みます。まず、図1のウィンドウの形ようなのカスケードを作成し、すべての要素とイベントへのモジュールのプログラムされた応答、つまり、機能性を追加します。

そのために、プログラムの完成されているフレームとメインモジュールの準備品があります。それでは始めましょう。「子」クラスの一つ、Cwinベースクラスがあります。従って、すべてのパブリックメソッドや「親」クラスのフィールドは継承により、そのクラスに渡されます。それゆえ、いくつかのメソッドを再定義すれば、新しいCMasterWindowsクラスの準備完了です。

//--- include files with classes
#include <ClassWin.mqh>
#include <InitMasterWindows.mqh>
#include <ClassMasterWindowsEXE.mqh>
//+------------------------------------------------------------------+
//| CMasterWindows class                                             |
//+------------------------------------------------------------------+
class CMasterWindows:public CWin
  {
protected:
   CMasterWindowsEXE WinEXE;     // executable module
public:
   void              Run();      // Run method
   void              Deinit();   // Deinitialization method
   virtual                       // OnChart event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };
//+------------------------------------------------------------------+
//| CMasterWindows class deinitialization method                     |
//+------------------------------------------------------------------+
void CMasterWindows::Deinit()
  {
//---(delete all objects)
   ObjectsDeleteAll(0,0,-1);
   Comment("");
  }
//+------------------------------------------------------------------+
//| CMasterWindows class Run method                                  |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
  {
   ObjectsDeleteAll(0,0,-1);
   Comment("MasterWindows for MQL5     © DC2008");
//--- creating designer window and launch executable object
   SetWin("CWin1",1,30,250,CORNER_RIGHT_UPPER);
   Draw(Mint,Mstr,21);
   WinEXE.Init("CWinNew",30,18);
   WinEXE.Run();
  }
//+------------------------------------------------------------------+
//| CMasterWindows class event processing method                     |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
      //--- Close button click in the main window
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,"CWin1",0)>=0
         && StringFind(sparam,".Button1",0)>0)
        {
         ExpertRemove();
        }
      //--- OnChart event processing for all objects
      STR1.OnEvent(id,lparam,dparam,sparam);
      STR2.OnEvent(id,lparam,dparam,sparam);
      STR3.OnEvent(id,lparam,dparam,sparam);
      STR4.OnEvent(id,lparam,dparam,sparam);
      STR5.OnEvent(id,lparam,dparam,sparam);
      STR6.OnEvent(id,lparam,dparam,sparam);
      WinEXE.OnEvent(id,lparam,dparam,sparam);
     }
  }

アプリケーションウィンドウの作成のみを担っているので、メインモジュールはそれ自体かなり小さいです。次に、興味深い、イベントの発生への反応が見られる、実行可能WinEXEモジュールにコントロールを渡します。

以前に、WinCellストラクチャーをオブジェクト間のデータの受け渡しのために作成しました。今、この手法のすべての利点があきらかになります。ストラクチャーのすべてのメンバのコピーのプロセスは合理的であり、簡潔です

STR1.Property = Property;
   STR2.Property = Property;
   STR3.Property = Property;
   STR4.Property = Property;
   STR5.Property = Property;
   STR6.Property = Property;

このステージでは、クラスの設計の詳しい考察は終え、新規クラスの作成手順を早める、構築技術に移ります。


3. クラスのビジュアル設計

クラスはより早く構築されることができ、MQL5のMasterWindowsデザインにて、より簡単に視覚化することができます。

図 3. ビジュアル設計のプロセス

図 3. ビジュアル設計のプロセス

開発者に求められているのは、MasterWindowsフォームを用い、ウィンドウのフォームを描き、計画されたイベントの反応を決定することです。コード自体は自動で生成されます。そして終了です!プロジェクトの完成です。

エキスパートアドバイザーとともに、CMasterWindowsクラスの生成されたコードの例は図4にて示されています。(ファイルは、..\MQL5\Filesに作成されます。)

//****** Project (Expert Advisor): project1.mq5
//+------------------------------------------------------------------+
//|        Code has been generated by MasterWindows Copyright DC2008 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
//--- include files with classes
#include <ClassWin.mqh>
int Mint[][3]=
  {
     {1,0,0},
     {2,100,0},
     {1,100,0},
     {3,100,0},
     {4,100,0},
     {5,100,0},
     {6,100,50},
     {}
  };
string Mstr[][3]=
  {
     {"New window","",""},
     {"NEW1","new1",""},
     {"NEW2","new2",""},
     {"NEW3","new3",""},
     {"NEW4","new4",""},
     {"NEW5","new5",""},
     {"NEW6","new6",""},
     {}
  };
//+------------------------------------------------------------------+
//| CMasterWindows class (main unit)                                 |
//+------------------------------------------------------------------+
class CMasterWindows:public CWin
  {
private:
   long              Y_hide;          // Window shift vertical in hide mode
   long              Y_obj;           // Window shift vertical
   long              H_obj;           // Window shift horizontal
public:
   bool              on_hide;         // HIDE mode flag
   CArrayString      units;           // Main window lines
   void              CMasterWindows() {on_event=false; on_hide=false;}
   void              Run();           // Run method
   void              Hide();          // Hide method
   void              Deinit()         {ObjectsDeleteAll(0,0,-1); Comment("");}
   virtual void      OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };
//+------------------------------------------------------------------+
//| CMasterWindows class Run method                                  |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
  {
   ObjectsDeleteAll(0,0,-1);
   Comment("Code has been generated by MasterWindows for MQL5 © DC2008");
//--- creating main window and launch executable module
   SetWin("project1.Exp",50,100,250,CORNER_LEFT_UPPER);
   Draw(Mint,Mstr,7);
  }
//+------------------------------------------------------------------+
//| CMasterWindows class Hide method                                 |
//+------------------------------------------------------------------+
void CMasterWindows::Hide()
  {
   Y_obj=w_ydelta;
   H_obj=Property.H;
   Y_hide=ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,0)-Y_obj-H_obj;;
//---
   if(on_hide==false)
     {
      int n_str=units.Total();
      for(int i=0; i<n_str; i++)
        {
         long y_obj=ObjectGetInteger(0,units.At(i),OBJPROP_YDISTANCE);
         ObjectSetInteger(0,units.At(i),OBJPROP_YDISTANCE,(int)y_obj+(int)Y_hide);
         if(StringFind(units.At(i),".Button0",0)>0)
            ObjectSetString(0,units.At(i),OBJPROP_TEXT,CharToString(MAX_WIN));
        }
     }
   else
     {
      int n_str=units.Total();
      for(int i=0; i<n_str; i++)
        {
         long y_obj=ObjectGetInteger(0,units.At(i),OBJPROP_YDISTANCE);
         ObjectSetInteger(0,units.At(i),OBJPROP_YDISTANCE,(int)y_obj-(int)Y_hide);
         if(StringFind(units.At(i),".Button0",0)>0)
            ObjectSetString(0,units.At(i),OBJPROP_TEXT,CharToString(MIN_WIN));
        }
     }
//---
   ChartRedraw();
   on_hide=!on_hide;
  }
//+------------------------------------------------------------------+
//| CMasterWindows class OnChartEvent event processing method        |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event // event handling is enabled
      && StringFind(sparam,"project1.Exp",0)>=0)
     {
      //--- call of OnChartEvent handlers
      STR1.OnEvent(id,lparam,dparam,sparam);
      STR2.OnEvent(id,lparam,dparam,sparam);
      STR3.OnEvent(id,lparam,dparam,sparam);
      STR4.OnEvent(id,lparam,dparam,sparam);
      STR5.OnEvent(id,lparam,dparam,sparam);
      STR6.OnEvent(id,lparam,dparam,sparam);
      //--- creating graphic object
      if(id==CHARTEVENT_OBJECT_CREATE)
        {
         if(StringFind(sparam,"project1.Exp",0)>=0) units.Add(sparam);
        }
      //--- edit [NEW1] in Edit STR1
      if(id==CHARTEVENT_OBJECT_ENDEDIT
         && StringFind(sparam,".STR1",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW3] : Plus button STR3
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR3",0)>0
         && StringFind(sparam,".Button3",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW3] : Minus button STR3
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR3",0)>0
         && StringFind(sparam,".Button4",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Plus button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button3",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Minus button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button4",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Up button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button5",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Down button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button6",0)>0)
        {
        //--- event processing code
        }
      //--- [new5] button click STR5
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR5",0)>0
         && StringFind(sparam,".Button",0)>0)
        {
        //--- event processing code
        }
      //--- [NEW6] button click STR6
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR6",0)>0
         && StringFind(sparam,"(1)",0)>0)
        {
        //--- event processing code
        }
      //--- [new6] button click STR6
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR6",0)>0
         && StringFind(sparam,"(2)",0)>0)
        {
        //--- event processing code
        }
      //--- button click [] STR6
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR6",0)>0
         && StringFind(sparam,"(3)",0)>0)
        {
        //--- event processing code
        }
      //--- Close button click in the main window
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".Button1",0)>0)
        {
         ExpertRemove();
        }
      //--- Hide button click in the main window
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".Button0",0)>0)
        {
         Hide();
        }
     }
  }
//--- Main module declaration
CMasterWindows MasterWin;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- launch main module
   MasterWin.Run();
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- main module deinitialization
   MasterWin.Deinit();
  }
//+------------------------------------------------------------------+
//| Expert Event function                                            |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- call OnChartEvent event handler
   MasterWin.OnEvent(id,lparam,dparam,sparam);
  }

これを作動させると、以下の設計されたウィンドウを見ることができます。

図4アドバイザープロジェクト1ークラスのビジュアル設計結果

図4. エキスパートアドバイザープロジェクト1ークラスのビジュアル設計の結果


結論

  1. ステージごとにクラスは設計される必要があります。タスクをモジュールごとに分解し、個別のクラスがそれぞれのために作成されます。モジュールは、派生クラスやベースクラスのより小さなモジュールへ分解されます。
  2. 内蔵のメソッドでベースクラスを再定義してはいけません。これらの数は最小で留める必要があります。
  3. ビジュアル設計の環境を使用したクラスの設計は、とても簡単であり、「サル」向けでもあります。というのも、コードは自動生成されるからです。

付属物の位置:

  • masterwindows.mq5 - ...\MQL5\Experts\
  • remaining in the folder - ...\MQL5\Include\

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

添付されたファイル |
遺伝的アルゴリズム - とても簡単です! 遺伝的アルゴリズム - とても簡単です!
この記事では、執筆者は遺伝的アルゴリズムを使用した進化計算について紹介しています。例を用いながらアルゴリズムの機能について紹介し、実用的な推奨される用例を提示しています。
初心者のための複数インディケータバッファの作成 初心者のための複数インディケータバッファの作成
複雑なコードは一組の簡単なコードから構成されます。簡単なコードに慣れていれば、複雑なコードはそれほど複雑に見えません。本稿では、複数のインディケータバッファによって1件のインディケータを作成する方法について考察していきたいと思います。例として、アルーンインディケータを細かく分析し、2つの異なるバージョンのコードを提示します。
異なる国での異なるタイムゾーンに基づくトレーディング戦略例 異なる国での異なるタイムゾーンに基づくトレーディング戦略例
インターネット検索をしていると、多くの戦略を見つけるのはたやすいことです。そこから多様な提案を得ることができます。インサイダーの方法を採り入れ、異なる大陸の異なるタイムゾーンに基づく戦略作成の手順を見ていきます。
MetaTrader 5とMATLABの連携 MetaTrader 5とMATLABの連携
本稿はMetaTrader 5とMatLab数学的パッケージの連携について詳しく述べていきます。それは、データ変換のメカニズム、デスクトップMatLabとの連携のためのユニバーサルライブラリの開発手順をさします。またMatLab環境で生成されるDLLの使用についても述べていきます。本稿は C++ 言語とMQL5をご存じの経験者を対象としています。