Expert Advisor、スクリプト、インディケータの同期

Сергей Ковалев | 16 2月, 2016

はじめに

MQL4 で書かれ、MetaTrader 4 クライアントターミナルで実行されるプログラムは以下のように3種類あります。
- Expert Advisor
- スクリプト
- インディケータ

おのおの、特定範囲の問題に対処します。これらプログラムについて簡潔に説明します。

1. MQL4 ユーザープログラムの簡単な説明

1.1. Expert Advisor
Expert Advisor (EA) は収益性あるトレード戦略を実現するために使用される主要なプログラムです。以下に EA の顕著な特徴をリストアップしています。
1. トレードを支援するために埋め込まれた関数を使用する機能
2. 外部設定をマニュアルで変更する機能
3. 特殊関数 start() の起動調整を行うルールの可用性ティック単位で起動します。新規ティックが出現するとき、この関数に対して有効な環境全体のパラメータが更新されます。たとえば、売り買い などのような変数は新しい値を取ります。コードの実行が完了する、すなわち戻りオペレータに達すると、関数 start() は処理を終了し、新規ティクが現れるまでスリープとなります。

1.2. スクリプト
スクリプトは Expert Advisor にひじょうに類似していますが、特徴はやや異なります。以下に スクリプトの顕著な特徴をリストアップしています。
1. スクリプトもトレード関数を使用することが可能です。
2. スクリプトでは外部設定のパラメータは変更できません。
3. スクリプトの主な特徴は規則です。それに従ってスクリプトの特殊関数 start() が一度だけ起動し、チャートにアタッチされた直後に初期化されます。

Expert Advisor およびスクリプトはシンボルのメインウィンドウにアタッチされ、特別なサブウィンドウは持ちません。

1.3. インディケータ
Expert Advisor やスクリプトとは異なり、インディケータは別の目的を持ちます。
1. インディケータの主な機能は、示される考えに従って1つまたは別の原則を表示する連続曲線を描くことです。
2. インディケータではトレード関数は使用できません。
3. インディケータはティックに従って起動されます。
4. 示されるパラメータに従い、インディケータはメインのシンボルウィンドウまたはそれのサブウィンドウで目的を果たします。

以上、カスタムプログラムの主な特徴、すなわち今後の 考えに必要なもののみリストアップしました。

上述から判るように、すべてのプログラムの特性を備えているカスタムプログラムはありません。Expert Advisor とスクリプトは描画ができず、インディケータはトレードしない、などです。

われわれのトレーディングシステムがトレード中にカスタムプログラムのすべての特性を利用する必要があるなら、唯一の解決法はExpert Advisor、スクリプト、インディケータを同時に使用することです。

2. 問題説明

全カスタムプログラムの同時使用の必要性を提供する基準を考察します。

2.1. 適時性
ユーザーによる制御はどれも即時実行される必要があります。Expert Advisor に基づくプログラムはかならずしもこの目的にかなっているわけではありません。Expert Advisor の主なデメリットは外部処理に対し て感受性がないことです。この制限の理由はかなりシンプルです。Expert Advisor の基本コードがティックに従って起動することです。ユーザーが EA にオーダーをクローズするように命令し、EA が次のティックを待っている場合はどうなるのでしょうか?この質問に対する答えは Expert Advisor がどのように書かれているかによります。命令は実行されるがいくらか遅延が発生する、という場合もあります。

プログラムは Expert Advisor の主要なコードがティック間で中断なく連続的に実行するように作られている可能性があります。これには特殊な関数

start()

内にループを作る必要があります。そこにプログラムの主要コードがすべて入れられるのです。ループの開始時に環境情報が強制的に更新されると、複合体前部が正常に動作します。ループ化された Expert Advisor のデメリットはセットアップパネルを開くことができないことです。EA をループ化してみます。そうすると、それを設定することはできません。

スクリプトの使用でもしかりです。これは無限ループがスクリプト内で作成されることを意味しています。ただ、パラメータはスクリプト内に設定されることはありません。

トレーディングシステムのカスタマイズと連続処理モードにおけるユーザーコマンドすべての実行の適時性は、 Expert Advisor の設定とスクリプトの即時実行を同時に行うことで実現できます。

2.2. アウェアネス
トレードに関する情報を入手する必要がある場合があります。たとえば、ある特定の瞬間(重要なニュースが公表される2分前など)に、ディーリングセンターが通常未決注文を出すのに最小許容距離 10 ポイントを 20 ポイントに変更したことをトレーダーは誰しも知りたいと思います。その上、概してトレーダーはトレードサーバーが注文の実行を拒否する理由を知りたがるものです。こういった情報やその他の有用な情報はインディケータウィンドウにテキスト形式で表示されます。また、継続的に古いメッセージ行はトレーディングシステムからの新規メッセージのために空のスペースに繰り上げられます。この場合、Expert Advisor またはスクリプトは表示インディケータとコンバインする必要があります。

2.3. 制御
強化されたインターフェースを持つトレーディングシステムを使用するなら、コントロール(グラフィカルオブジェクト)はインディケータウィンドウに配置する方がよいと言えます。ろうそくトレンドがコントロール項目に重複せず、そのため制御を妨げないことを確認します。

2.4. システム要件
この場合、最終プロダクトに対する主な要件は同期動作です。プログラムの 3 タイプすべてを基にしたシステムを開発するには、コンポーネントのすべてによって遂行するタスクを解離することが必要です。われわれのシステムのプログラムそれぞれの特別な機能に従い、以下の特性を定義します。

スクリプト-解析的、トレード関数を持つ基本コードを提供します。

Expert Advisor-セットアップパネルを提供します。

インディケータ -制御および情報表示を行うサブウィンドウを提供します。

3. ソフトウェアソリューション

最小の条件範囲内で3種類のコンポーネントを基にしたアプリケーションのストラクチャをここでは考察することを示します。実用でアプリケーションを使用しようと決めるなら、解析的トレーディング処理に関連するためご自身で詳しく説明する必要があります。ただしストラクチャ作成には以下で提供している資料できわめて十分です。

3.1. Expert Advisor
Expert Advisor が何で構成されて おり、それがどのように動作するか詳しく考察しましょう。


// Expert.mq4
//====================================================== include =======
#include <stdlib.mqh>
#include <stderror.mqh> 
#include <WinUser32.mqh> 
//======================================================================
#include <Peremen_exp.mq4>  // Description of the EA variables.
#include <Metsenat_exp.mq4> // Predefinition of the EA variables. 
#include <Del_GV_exp.mq4>   
// Deletion of all GlobalVariables created by the Expert Advisor.
#include <Component_exp.mq4> // Checking for availability of components.
#include <Component_uni.mq4> 
// Message in the indicator that components are not available.
//======================================================================
//
// 
//======================================================================
int init()  
  {
    Fishka=1;          // We are in init()  
    Metsenat_exp();   // Predefinition of the EA variables.
    Component_exp();  // Check for availability of components
    return;
 } 
//=====================================================================
int start() 
  { 
    Fishka=2;         // We are in start()  
    Component_exp();  // Check for availability of components
    return;                                                                 
 }
//=====================================================================
int deinit() 
  {   
    Fishka=3;         // We are in deinit()  
    Component_exp();  // check for availability of components
    Del_GV_exp();     // Deletion of the Expert Advisor's GlobalVariable.
    return;
 }
//======================================================================


特殊関数 init() では2つの関数が動作しています。それは Metsenat_exp() と Component_exp() です。

Metsenat_exp()

- いくつかの変数を事前定義する関数です。

// Metsenat_exp.mq4
//=================================================================
int Metsenat_exp()
 {
//============================================ Predefinitions =====
   Symb     = "_"+Symbol();
   GV       = "MyGrafic_GV_";
//============================================= GlobalVariable ====
   GV_Ind_Yes = GV+"Ind_Yes"   +Symb;      
// 0/1 confirms that the indicator is loaded
   GV_Scr_Yes = GV+"Scr_Yes"   +Symb;      
// 0/1 confirms that the script is loaded
//-------------------------------------------- Public Exposure ----
   GV_Exp_Yes = GV+"Exp_Yes"   +Symb;     
   GlobalVariableSet(GV_Exp_Yes, 1 ); 
   GV_Extern  = GV+"Extern"    +Symb;     
   GlobalVariableSet(GV_Extern,  1 ); 
//  AAA is used as an example:
   GV_AAA     = GV+"AAA"       +Symb;     
GlobalVariableSet(GV_AAA,   AAA ); 
//==================================================================
   return;
 }
//====================== End of Module =============================

アプリケーション全体のメンテナンスタスクの一つは全コンポーネントの可用性を追跡することです。これが全コンポーネント(スクリプト、Expert Advisor、インディケータ)がお互いに追跡しあう必要があり、コンポーネントが利用可能でなければ動作を停止し、そのことをユーザーに報告する理由です。このためにプログラムはそれぞれグローバル変数を出すことによって開始時に可用性について報告をするのです。例では Expert Advisor の関数 Metsenat_exp() 内で以下の行においてこれが行われます。

   GV_Exp_Yes = GV+"Exp_Yes"   +Symb;     
   GlobalVariableSet(GV_Exp_Yes, 1 );

関数Metsenat_exp() は EA の関数 init() によって制御されます。すなわち、それはロード、または変数の値を変更する際一度だけ使われます。スクリプトは変更された設定について「知る」必要があり、これがエキスパートがグローバル変数 GV_Extern の値を変更することによってそれをスクリプトに報告する理由です。

   GV_Extern  = GV+"Extern"    +Symb;     
   GlobalVariableSet(GV_Extern,  1 );

Component_exp()

- 制御を完了するための関数です。さらなるシナリオは Component_exp() が使用される Expert Advisor の特殊関数に依存します。

// Component_exp.mq4 
//===============================================================================================
int Component_exp()
 {
//===============================================================================================
   while( Fishka < 3 &&     // We are in init() or in start() and..
      (GlobalVariableGet(GV_Ind_Yes)!=1 || 
       GlobalVariableGet(GV_Scr_Yes)!=1)) 
    {                            // ..while a program is not available.
      Complect=0;                // Since one is inavailable, it is a deficiency
      GlobalVariableSet(GV_Exp_Yes, 1); 
// Inform that the EA is available
//-----------------------------------------------------------------------------------------------
      if(GlobalVariableGet(GV_Ind_Yes)==1 && 
         GlobalVariableGet(GV_Scr_Yes)!=1)
        {//If there is an indicator but there is no scrip available, then..
         Graf_Text = "Script is not installed.";  
// Message text
         Component_uni();                             
// Write the message text in the indicator window.
        }
//-----------------------------------------------------------------------------------------------
      Sleep(300);
    }
//===============================================================================================
     if(Complect==0)
    {
      ObjectDelete("Necomplect_1"); 
// Deletion of unnecessary messages informing about inavailability of components  
      ObjectDelete("Necomplect_2");       
      ObjectsRedraw();              // For quick deletion 
      Complect=1;        // If we have left the loop, it means that all components are available
    }
//===============================================================================================
   if(Fishka == 3 && GlobalVariableGet(GV_Ind_Yes)==1)
// We are in deinit(), and there is space to write the indicator into
    { 
//-----------------------------------------------------------------------------------------------
      if(GlobalVariableGet(GV_Scr_Yes)!=1)  // If there is no script available,
       {
         Graf_Text = "Components Expert and Script are not installed";
// Message (since we are unloading)
         Component_uni();     // Write the message text in the indicator window
       }
//-----------------------------------------------------------------------------------------------
    }
//===============================================================================================
   return;
 }
//===================== End of the module =======================================================

スクリプトとインディケータの可用性は対応するグローバル変数 -GV_Scr_Yes および GV_Ind_Yes の値の読み取りに基づいてトレースされます。どのコンポーネントも利用可能でなければ、コントロールは完了する、すなわち、インディケータとスクリプトがインストールされるまで、無限ループに入ります。アプリケーションはユーザーに対して関数

Component_uni()

によって現状を報告します。これはすべてのコンポーネントにインクルードされているユニバーサル関数です。

// Component_uni.mq4
//================================================================
int Component_uni()
 {
//================================================================
//----------------------------------------------------------------
   Win_ind = WindowFind("Indicator");                 
// What is our indicator's window number?
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   ObjectCreate ( "Necomplect_1", OBJ_LABEL, Win_ind, 0, 0  );
// Create an object in the indicator window
   ObjectSet    ( "Necomplect_1", OBJPROP_CORNER,        3  );
// coordinates related to the bottom-right corner
   ObjectSet    ( "Necomplect_1", OBJPROP_XDISTANCE,   450  );
// coordinates on X..
   ObjectSet    ( "Necomplect_1", OBJPROP_YDISTANCE,    16  );
// coordinates on Y..
   ObjectSetText("Necomplect_1", Graf_Text,10,"Courier New",Tomato);
// text, font, and color
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   Graf_Text = "Application does not work.";
 // Message text
   ObjectCreate ( "Necomplect_2", OBJ_LABEL, Win_ind, 0, 0);
// Create an object in the indicator window
   ObjectSet    ( "Necomplect_2", OBJPROP_CORNER,        3);
// coordinates related to the bottom-right corner
   ObjectSet    ( "Necomplect_2", OBJPROP_XDISTANCE,   450);
// coordinates on Х..
   ObjectSet    ( "Necomplect_2", OBJPROP_YDISTANCE,     2);
// coordinates on Y..
   ObjectSetText("Necomplect_2", Graf_Text,10,"Courier New",Tomato);
// text, font, color
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   ObjectsRedraw();                                // Redrawing.
   return;
//================================================================
 }
//===================== End of module ============================

アプリケーションが完了するとすぐに、EA のコントロールはループから不完了についての不要なメッセージが削除される連続コードに渡されます。

EA がロードされていなければ、特殊関数 deinit() はComponent_exp() も呼び出しますが、それは現時点でロードされていないことを報告するという別の目的のためです。

Expert Advisor のdeinit() 関数において

Del_GV_exp()

も呼び出されます。

これは EA によって開かれたグローバル変数をすべて削除するのに使用されます。不文律によると、ロードされていないプログラムはどれも『空間をクリアする』必要があります。すなわち、以前に作成されたグローバル変数やグラフィカルオブジェクトを削除するのです。

// Del_GV_exp.mq4
//=================================================================
int Del_GV_exp()
 {
//=================================================================
   GlobalVariableDel(GV_Exp_Yes      ); 
   GlobalVariableDel(GV_Extern       ); 
   GlobalVariableDel(GV_AAA          ); 
//=================================================================
   return;
 }
//====================== End of module ============================


よって Expert Advisor は動作を開始し、全段階において他の2つのコンポーネントの可用性を追跡します。init() で一度、deinit() で一度、そして start() でティックごとにこれを行います。この EA コンストラクションによりプログラムがわれわれのタスクを遂行するのに使用を可能にします。セットアップパネルを使用可能とするのです。変数を記述しているファイルにはたとえば、ААА 変数とそれが対応するグローバル変数 GV_AAA が入っており、その値はスクリプトから読み出されます。

これがすべてどのように動作するか詳細に入るにはスクリプトのストラクチャを考察します。

3.2. スクリプト
スクリプトコード:

// Script.mq4
//==================================================== include ====
#include <stdlib.mqh> 
#include <stderror.mqh>
#include <WinUser32.mqh>
//=================================================================
#include <Peremen_scr.mq4>       
// File describing variables of the script. 
#include <Metsenat_scr.mq4>      
// Predefining of variables of the script.   
#include <Mess_graf_scr.mq4>     
// List of graphical messages.
#include <Novator_scr.mq4>       
// Environment scanning, obtaining new values for some variables
#include <Del_GV_scr.mq4>        
// Deletion of all GlobalVariables created by the script.
#include <Component_scr.mq4>     
// Checking for components availability.
#include <Component_uni.mq4>     
// Message in the indicator about inavailability of components.
#include <Del_Obj_scr.mq4>       
// Deletion of all objects created by the program complex.
#include <Work_scr.mq4>          
// The main working function of the script. 
//=================================================================
//
// 
//=================================================================
int init()  
 {
   Fishka = 1;                                // We are in init()  
   Metsenat_scr();       // Predefining of variables of the script.
   return;
 }
//================================================================
int start()  
 {
   Fishka = 2;                               // We are in start()  
   while(true)
    {
      Component_scr();  // Checking for availability of components
      Work_scr();       // The main working function of the script.
    }
   return;
 }
//=================================================================
int deinit() 
 {
   Fishka = 3;                                // We are in deinit()  
   Component_scr();      // Checking for availability of components
   Del_Obj_scr();          // Deletion of graphical objects created
   Del_GV_scr();        // Deletion of GlobalVariable of the script.
   return;
 }
//==================================================================

コードの基本は特殊関数 start() における無限ループの可用性です。スクリプトコードでは、似た名前の関数やコンテンツが使用されています。その特殊な機能に着目します。ループすべての冒頭では関数

Component_scr()

が呼ばれます。

// Component_scr.mq4   
//====================================================================
int Component_scr()
 {
//====================================================================
   Iter=0;                               // Zeroize iteration counter
   while (Fishka <3 &&              // We are in init() or in start() 
      (GlobalVariableGet(GV_Ind_Yes)!=1 || 
       GlobalVariableGet(GV_Exp_Yes)!=1)) 
    {                                 // Until a program is available
      GlobalVariableSet(GV_Scr_Yes, 1);               
// Declare about the script availability
//--------------------------------------------------------------------
      Iter++;                                    // Iteration counter
      if(Iter==1)                         // Skip the first iteration
       {
         Sleep(500);
         continue;
       }
//--------------------------------------------------------------------
      if(Iter==2)             // Take measures on the second iteration
       {
         Complect=0; // Program is not available, it is incompleteness
         for (i=0;i<=31;i++)ObjectDelete(Name_Graf_Text[i]);
// Deletion of all strings
// Here, a function can be inserted that will zeroize trade queue.
       }
//--------------------------------------------------------------------
      if(GlobalVariableGet(GV_Ind_Yes)==1 && 
          GlobalVariableGet(GV_Exp_Yes)!=1)
       {                       // If there is an indicator, but no EA
         Graf_Text = "Expert has not been installed."; 
// Message text 
         Component_uni();                             
// Write the text message in the indicator window.
       }
//-----------------------------------------------------------------
      Sleep(300);
    }
//-----------------------------------------------------------------
   if(Complect==0)                // Process it once at completing.
    {
      ObjectDelete("Necomplect_1"); 
// Deletion of unnecessary messages..
      ObjectDelete("Necomplect_2"); 
// ..about incompleteness of components        
      Mess_graf_scr(1);
// Inform the user about completeness
      if( IsExpertEnabled()) 
// The button is enabled
       {
         Mess_graf_scr(3000);
         Knopka_Old = 1;
       }
      if(!IsExpertEnabled()) 
// The button is disabled
       {
         Mess_graf_scr(4000);
         Knopka_Old = 0;
       }
      Complect=1; 
// The minimal installation completeness reached
      Redraw = 1; 
// For quick deletion 
    }
//====================================================================
   if(Fishka == 3 && GlobalVariableGet(GV_Ind_Yes)==1)      
// We are in deinit()  
    {
      for(i=0;i<=31;i++)ObjectDelete(Name_Graf_Text[i]);    
// Deletion of all strings
//--------------------------------------------------------------------
      if(GlobalVariableGet(GV_Exp_Yes)!=1)                 
// There is indicator, but no Expert Advisor
         Graf_Text="Components Expert and Script are not installed.";
// Message (as we're unloading)
      if(GlobalVariableGet(GV_Exp_Yes)==1)
// If there are both indicator and EA, then..
         Graf_Text="The Script has not been installed."; 
// Message (as we're unloading)
      Component_uni();   // Write the message in the indicator window.
//--------------------------------------------------------------------
      ObjectsRedraw();                    // For quick deletion 
    }
//====================================================================
   return;
 }
//====================== End of module ===============================

スクリプト上の第一の要望は

処理の

連続性です。extern 変数を更新する間、Expert Advisor は完全にインストールされます。EA のセットアップパネルで OK を押すと、アンロードされ、deinit() に制御を委ねます。それから連続して init() および start() を経てすぐに再びロードします。結果、短い時間ではありますが Expert Advisor はその可用性を確認するグローバル変数を deinit() から削除します。

EA がロードされていない、とスクリプトが思わないように、関数Component_scr() には最初の反復で決定を無効にする小さなブロックがあります。

      Iter++;                         // Iteration counter
      if(Iter==1)              // Skip the first iteration
        {
          Sleep(500);
          continue;
        }


Expert Advisor のロードを完了するにはほとんどの場合、500秒で十分です。Expert Advisor の init() でもっとリソースを消費するコードを使用すれば、時間は長くかかります。EA が2番目の反復で検出されていなければ、EA が使用不可であるという判断がされ、スクリプトは処理を停止します。

      Complect = 0;    // A program is not available, incompleteness


前段落で『スクリプトは処理を停止します』という表現を使いました。われわれの例では、この現象を扱うコードは含まれていませんが、それは本稿の対象ではないためにほかなりません。コード内の対応する関数を呼ぶ箇所にはコメントが付けられています。

// Here, a function zeroizing trade counter can be inserted.

実際に動作しているプログラムの関数

Work_scr()

内では、われわれの例で使用されている関数以外に、イベントの特定のオーダーを処理するためにその他の関数が取られています。たとえば、みなさんのプログラムが複数のオーダーを変更するために調整される場合、それは確実に配列を持ち、現行ティックでそのようなトレードが数多く発生すれば、その配列内でトレードを実行するキューが格納されます。

そういったキューが生じるときに不完了となる(たとえば Expert Advisor またはスクリプトがうっかりロードされていない、など)、上述のトレードキューの配列と、おそらく状況によって他の変数をいくつかゼロ設定することで達成されるトレードを無効にする必要があります。

スクリプトの無限ループもまた関数 Work_scr() を持ちます。これはすべての主要コードが入れられるスクリプトのメイン関数です。

// Work_scr.mq4
//=================================================================
int Work_scr()  
 {
   Novator_scr();
//-----------------------------------------------------------------
   // Basic code of the entire application.
//------------------------------------------------ For example ----
   if(New_Tick==1)                             // At every new tick
    {                                                                    
      Alert ("The current value of ААА = ", AAA);
    }                                                                    
//-----------------------------------------------------------------
   if(Redraw==1)
    {
      ObjectsRedraw();                    // To display immediately
      Redraw=0;                         // Unflag objects redrawing
    }
//-----------------------------------------------------------------
   Mess_graf_scr(0);
   Sleep(1);                           // Just in case, from reload
   return;
 }
//====================== End of module ============================


Work_scr() は基本コードで使用されている環境変数を更新する関数 Novator_scr() を持ちます。

// Novator_scr.mq4  
//===================================================================
int Novator_scr()  
 {
//===================================================================
//---------------------------------------- Updating of settings -----
   if(GlobalVariableGet(GV_Extern)==1) 
// There is an update in the EA
    {
      Metsenat_scr();         // Updating of the script variables.
      Mess_graf_scr(5000);    // Message about a new setting.
      Redraw=1;               // Redrawing at the end of the loop.
    }                                                                    
//--------------------------------- EA button state -----------------
   Knopka = 0;                                         // Preset
   if( IsExpertEnabled()) Knopka = 1; 
// Check for the real state of the button
 
   if(Knopka==1 && Knopka_Old==0) 
// If the state has changed for ON
    {
      Knopka_Old = 1;                // This will be the old one
      Mess_graf_scr(3);              // Inform the user about changes
    }
   if(Knopka==0 && Knopka_Old==1) 
// If the state has changed for OFF
    {
      Knopka_Old = 0;                 // This will be the old one
      Mess_graf_scr(4);              // Inform the user about changes
    }
//-------------------------------------------------- New tick --------
   New_Tick=0;                              // First of all, zeroize
   if (RefreshRates()==true) New_Tick=1; 
// It is easy to catch a new tick if you know how to do it
//--------------------------------------------------------------------
//====================================================================
   return;
 }
//=====================; End of module ===============================


この関数の必要性をもっと詳しく考察します。本稿の冒頭で、EA がロードされるたび、またその変数が更新されるときも同様に、その下位関数 Metsenat_exp() は変数 GV_Extern の値を 1 に設定する、とお話しました。スクリプトについては、それは設定が更新されることを意味します。このため、関数 Novator_scr() は以下のブロックを持ちます。

//---------------------------------------- Updating settings ----
   if (GlobalVariableGet(GV_Extern)==1) 
// An update has taken place in the EA
    {
      Metsenat_scr();              // Updating script settings.
      Mess_graf_scr(5000);         // New setting message.
      Redraw=1;                    // Redrawing at the end of the loop.
    }

上の変数の値はここで解析され、更新が必要な場合には、関数

Metsenat_scr()

が呼ばれます。この関数が更新を行う(グローバル変数の新しい値を読む)のです。

// Metsenat_scr.mq4
//===================================================================
int Metsenat_scr()
  {
//========================================================== int ====
//======================================================= double ====
//======================================================= string ====
      MyGrafic    = "MyGrafic_";
    Mess_Graf   = "Mess_Graf_";
    Symb        = "_"+Symbol();
    GV          = "MyGrafic_GV_";
//=============================================== GlobalVariable ====
     GV_Ind_Yes  = GV+"Ind_Yes" +Symb;       
// 0/1 confirms that the indicator has been loaded
     GV_Exp_Yes  = GV+"Exp_Yes" +Symb;       
// 0/1 confirms that the EA has been loaded
//-------------------------------------------------- Publishing -----
     GV_Scr_Yes  = GV+"Scr_Yes" +Symb;     
    GlobalVariableSet(GV_Scr_Yes,          1 ); 
    GV_Extern   = GV+"Extern"  +Symb;     
    GlobalVariableSet(GV_Extern,           0 ); 
//--------------------------------------------------- Reading -------
                                             //  AAA is used as an example:
     GV_AAA      = GV+"AAA"     +Symb;     
   AAA  = GlobalVariableGet(GV_AAA); 
//===================================================================
     return;
 }
//======================== End of module ============================


次に関数Metsenat_scr() はグローバル変数 GV_Extern の値を0 に設定します。続く履歴内では、この変数はユーザーが EA のセットアップウィンドウを開くまで 0 のまま残ります。

変更された設定によって EA はアンロードとロードの全段階を通過するのですが、スクリプトはユーザーが設定を変更している間またはその後動作を停止することに注意が必要です。そのため、とスクリプトを組み合わせて使用することでアプリケーション処理の連続性に役立ち、ユーザーは設定を変更すること、すなわち過程を制御することができるのです。

関数

Novator_scr()

の続くブロックでは、 EA のボタンがトレードを有効にするよう制御されます。そして新規ティックが検出されます。みなさんのトレーディングシステムがこれら、また同様のパラメータを使用するとすると、それは関数

Novator_scr()

です。これはそういった計算を行うものです。



たとえば、

新規バー

が出現したかどうか検出する、重要なイベント

時間

が来たか確認する、

トレード条件

が変更になった(サイズ拡張、ストップオーダーを出す最小距離など)かどうか検出し、また基本の解析的関数が処理を開始する前に必要なその他の計算を伴うこの関数を完了します。



プログラムの基本内容を作成する関数は関数 Work_scr() には表示されていません。記事 Considering Orders in a Large Programでオーダーを考慮する関数 Terminal() を取り上げます。みなさんがトレーディングシステムで同じ考慮原則を取り入れるなら、関数 Terminal() は関数 Work_scr() 内で関数 Novator_scr() の直後にインクルードする必要があります。

スクリプトはそれ自身にもう一つの補助関数を持ちます。それはMess_graf_scr() で、インディケータウィンドウにメッセージを表示します。

// Mess_graf_scr.mq4
//====================================================================
int Mess_graf_scr(int Mess_Number)
 {
//====================================================================
   if(Mess_Number== 0)        // This happens in every loop Work
    {
      if(Time_Mess>0 && GetTickCount()-Time_Mess>15000) 
// Color print has outdated within the last 
       {                       // ..15 sec, let's color lines gray
         ObjectSet(Name_Graf_Text[1],OBJPROP_COLOR,Gray);
// Last 2 lines
         ObjectSet(Name_Graf_Text[2],OBJPROP_COLOR,Gray);
// The last 2 lines
         Time_Mess=0;         // Additional flag not to color in vain
         Redraw=1;            // Then redraw
       }
      return;                 // It was a little step into 
    }
//--------------------------------------------------------------------
   Time_Mess=GetTickCount(); // Remember the message publishing time
   Por_Nom_Mess_Graf++;      // Count lines. This is just a name part.
   Stroka_2=0;            // Presume that message in one line
   if(Mess_Number>1000)      
// If a huge number occurs, the number will be brought to life, 
// understand that the previous line is from the same message, i.e.,it 
// should not be colored gray 
    {
      Mess_Number=Mess_Number/1000; 
      Stroka_2=1; 
    } 
//====================================================================
   switch(Mess_Number)
    {
//--------------------------------------------------------------------
      case 1:
         Graf_Text = "All necessary components installed.";
         Color_GT = LawnGreen; 
         break;
//--------------------------------------------------------------------
      case 2:
         Graf_Text = " ";
         break;
//--------------------------------------------------------------------
      case 3:
         Graf_Text = "Expert Advisors enabled.";
         Color_GT = LawnGreen; 
         break;
//--------------------------------------------------------------------
      case 4:
         Graf_Text = "Expert Advisors disabled.";
         Color_GT = Tomato; 
         break;
//--------------------------------------------------------------------
      case 5:
         Graf_Text = "Expert Advisor settings have been updated.";
         Color_GT = White; 
         break;
//---------------------------------------------------- default -------
      default:
         Graf_Text = "Line default "+ DoubleToStr( Mess_Number, 0);
         Color_GT = Tomato;
         break;
    }
//====================================================================
   ObjectDelete(Name_Graf_Text[30]); 
// the 30th object is preempted, delete it
   int Kol_strok=Por_Nom_Mess_Graf;
   if(Kol_strok>30) Kol_strok=30;
//-----------------------------------------------------------------
   for(int lok=Kol_strok;lok>=2;lok--)
// Go through graphical text names
    {
      Name_Graf_Text[lok]=Name_Graf_Text[lok-1];        
// Reassign them (normalize)
      ObjectSet(Name_Graf_Text[lok],OBJPROP_YDISTANCE,2+14*(lok-1));
//Change Y value (normalize)
      if(lok==3 || lok==4 || (lok==2 && Stroka_2==0))
         ObjectSet(Name_Graf_Text[lok],OBJPROP_COLOR,Gray);
//Color old lines gray.. 
    }
//-------------------------------------------------------------------
   Graf_Text_Number=DoubleToStr( Por_Nom_Mess_Graf, 0); 
//The unique part of the name unite with the message number
   Name_Graf_Text[1] = MyGrafic + Mess_Graf + Graf_Text_Number;
// Form the message name.
   Win_ind= WindowFind("Indicator");                    
//What is the window number of our indicator?
 
   ObjectCreate ( Name_Graf_Text[1],OBJ_LABEL, Win_ind,0,0);
// Create an object in the indicator window
   ObjectSet    ( Name_Graf_Text[1],OBJPROP_CORNER, 3   );  
// ..with coord, from the bottom-right corner..
   ObjectSet    ( Name_Graf_Text[1],OBJPROP_XDISTANCE,450); 
// ..with coordinates on X..
   ObjectSet    ( Name_Graf_Text[1],OBJPROP_YDISTANCE, 2);  
// ..with coordinates on Y..
   ObjectSetText(Name_Graf_Text[1],Graf_Text,10,"Courier New",
                 Color_GT);
//text font color
   Redraw=1;                                  // Then redraw
//=================================================================
   return;
 }
//====================== End of module ============================

この関数については詳細をすべて考察する必要はありません。ただ特殊な機能を説明するに留めます。


1. メッセージはすべてグラフィカルな手段によって表示されます。
2. 関数に渡される正式なパラメータはメッセージ番号に対応しています。
3. 渡されるパラメータの値が1と999の間であれば、インディケータウィンドウ内で先行するテキスト行には色がついていません。この値が1000を超える場合、メッセージが表示され、その値は1000で割られた渡される値に等しくなっています。この後者の場合、先行行には色がついています。
4. 前メッセージから15秒後、すべての行は色付ではなくなります。
5. この関数は行を変色する機能を保ち、ときどきアクティブ化されます。そのため、関数 Work_scr() の最後に呼び出しがあります。

   Mess_graf_scr(0);


記事 Graphic Expert Advisor: AutoGraf で、実際に動作しているプログラム複合体は、250以上の多様なメッセージを持つ同様の関数が使用される場所に入っています。みなさんのトレーディングですべてのまたはいくつかのメッセージを使用するのにこの例を参照することができます。

3.3. インディケータ

われわれの表示を完了するために、コードはかなりシンプルながら、インディケータについても考察します。

// Indicator.mq4
//===================================================; include ==========
#include <stdlib.mqh>
#include <stderror.mqh>
#include <WinUser32.mqh>
//=======================================================================
#include <Peremen_ind.mq4>       
// Description of the indicator variables.
#include <Metsenat_ind.mq4>      
// Predefining the indicator variables. 
#include <Del_GV_ind.mq4>        
// Deletion of all GlobalVariables created by the indicator.
#include <Component_ind.mq4>     
// Check components for availability.
#include <Component_uni.mq4>     
// Message in the indicator about inavailability of components.
//=======================================================================
//
// 
//=======================================================================
#property indicator_separate_window
//=======================================================================
//
//
//=======================================================================
int init()  
 {
   Metsenat_ind();
   return;
 }
//=======================================================================
int start() 
 {
   if(Component_ind()==0) return; // Check for availability of components
   //...
   return;                                                           
 }
//=======================================================================
int deinit() 
 {
   Del_GV_ind();             // Deletion of the indicator GlobalVariable.
   return;
 }
//=======================================================================


ここではインディケータの重要な機能をただひとつだけ強調します。インディケータは個別のウィンドウに表示される、ということです。

#property indicator_separate_window

関数 Metsenat_ind() および Del_GV_ind() のコンテンツは、前に考察した Expert Advisor とスクリプトで使用されている関数と類似するものです。

関数 Component_ind() の内容もシンプルです。

// Component_ind.mq4
//===================================================================
int Component_ind()
 {
//===================================================================
   if(GlobalVariableGet(GV_Exp_Yes)==1 && 
      GlobalVariableGet(GV_Scr_Yes)==1)
//If all components are available
    {                        // State about the indicator available
      if(GlobalVariableGet(GV_Ind_Yes)!=1)
          GlobalVariableSet(GV_Ind_Yes,1);
      return(1);
    }
//--------------------------------------------------------------------
   if(GlobalVariableGet(GV_Scr_Yes)!=1 && 
      GlobalVariableGet(GV_Exp_Yes)!=1)
    {                           // If there is neither script nor EA  
      Graf_Text = "Components Expert and Script are not installed.";            
// Message text
      Component_uni();        // Write the info message in ind. window
    }
//=====================================================================
   return(0);
 }
//=====================; End of module ================================

コードから判るように、関数

Component_ind() は、別の2つのコンポーネント- スクリプトと Expert Advisor の両方、がロードされている場合にのみメッセージを提供します。プログラムのどちらか一方が利用不可であれば、処理はなにも行われません。これは、シンボルウィンドウでそのプログラムが利用可能であれば、これらプログラムはプログラム複合体の構成を追跡し、ユーザーに結果を知らせることを前提としています。

必要に応じ、インディケータの主要特性である描画も行われます。プログラム複合体に関しては、この特性は不要ですが、実際のトレーディングでは使用可能です。たとえばサブウィンドウをゾーンに分割するなどです。

4. 実用

アプリケーションのコンポーネントをシンボルウィンドウにアタッチする順番は重要ではありません。ただし、アタッチされるとすぐにコメントを読むことが可能になるため、インディケータを最初にアタッチすることが推奨されるでしょう。

よって、アプリケーションがどのように動作するかを示すのに以下を行う必要があります。

1. シンボルウィンドウにインディケータをアタッチします。次のメッセージが即時インディケータウィンドウに表示されます。:

コンポーネントであるエキスパートとスクリプトはインストールされません。
アプリケーションは動作しません。


2. シンボルウィンドウに Expert Advisor をアタッチします。関数 Component_exp() がスタートし、次のメッセージがインディケータウィンドウに表示されます。:

スクリプトがインストールされていません。
アプリケーションは動作しません。


3. シンボルウィンドウにスクリプトをアタッチします。このイベントはスクリプトの関数 Component_scr() で処理され、インディケータウィンドウに表示されます。


必要なコンポーネントがすべてインストールされています。
Expert Advisors が有効です。


Expert Advisor が無効であれば、メッセージは次のようなものとなります。:

必要なコンポーネントがすべてインストールされています。
Expert Advisor は無効です。


4. EA ボタンを複数回押し、このイベントシーケンスが即アプリケーションによって処理され、メッセージ行に表示されることを確認します。:

Expert Advisor は無効です。
Expert Advisor は有効です。

Expert Advisor は無効です。
Expert Advisor は有効です。
Expert Advisor は無効です。


プログラム複合体で使用されるループした基本コードを持つスクリプトによって、ユーザーの制御に対応するプログラムは複数ティックないでは作成されず、即時作成されることに留意ください。

一例として、関数 Alert() を使用し EA 設定からの変数のティックに関す表示を関数 Work_scr() に入れました。



この機能について考察します。関数 Work_scr() はスクリプトの一部です。スクリプトの基本ループは複数ティック内で関数 Alert() によりメッセージが表示される間にティック間で何百回と返す時間を持ちます。

5. EA のセットアップツールバーを開き、値 AAA を 3 と置き換えます。スクリプトはこのイベントを追跡し、インディケータウィンドウに次のようなメッセージを表示します。:

Expert Advisor は有効です。
Expert Advisor は無効です。
Expert Advisor は有効です。

Expert Advisor は無効です。
EA 設定は更新されました。


関数 Alert() のウィンドウは変数 AAA のティックに関する新しい値を表示します。





6. これで、あらゆるシーケンスにおいてすべてのコンポーネントをロードまたはアンロードし、EA ボタンを使い、調整可能な変数値を変更し、プログラム複合体のクオリティーに関するご自身の意見を出すことが可能です。

おわりに

これまで説明してきた技術を用いて到達した主な事柄は、環境においてイベントが生じる生じないにかかわらず、スクリプトは動作を停止しない、ということです。スクリプトが停止するのは、それ以外のコンポーネントの一つまたは両方(インディケータ、Expert Advisor)が有効でない場合です。

説明したプログラム複合体を作成する原理は、多少変更を加えていますが、記事Graphic Expert Advisor: AutoGraf で説明されている実際の作業のアプリケーションAutoGraf で使用されるものです。

SK. Dnepropetrovsk. 2006