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

54
6 533

オブジェクト指向プログラミング(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\
次の記事 >>
Vitaliy Kostrubko:
セルゲイ、こんにちは! ...可能性に慣れるために、あなたのコンパイルされたファイル(投稿#4から)をダウンロードしました.でも、チャート上に表示されません。
Vitaliy Kostrubko:
...この投稿からダウンロードしたコンパイル時にエラーが出ます:
lynxntech:
間違ったところから始めているようです、 MQL5プログラミングの基本から始めて、クラスを作り、パネルを作り、取引機能を組み込んでみるべきです。 このパネルで取引する必要があるのなら、既製のものを購入したほうがいいし、選択肢はある。 ここでパネルを作ったとして、それで何をするのですか? あなたが説明したことをすべてできる人は、あなたの開発は必要ないと言うでしょう・・・。と言って、ゼロから自分のものを使うだろう。 そして、パネルではなくプログラミングしか知らない人は、この記事のスケッチのもとで、パネルのために半年かけてこれらのトレード願望を作り上げるだろう。 加える この記事は、教室に通う前に手続き的なスキルを向上させたい人にとって役に立つかもしれない。