プリプロセッサ

プリプロセッサ

プリプロセッサは、プログラムがコンパイルされる直前のプログラムソースコードの準備を目的とした MQL5 コンパイラの特別なサブシステムです。

プリプロセッサはソースコードの読みやすさを向上します。コードは、MQL5 プログラムのソースコードを含む特殊ファイルを含めることにより、構造化することが出来ます。定数への呼び名の割り当ては、コードの読みやすさの向上に貢献します。

またプリプロセッサは MQL5 プログラムの特定パラメータを決定することも出来ます。

  • 定数の宣言
  • プログラムプロパティの設定
  • プログラムテキスト内の Include ファイル
  • 関数のインポート
  • 条件付きコンパイル

プリプロセッサディレクティブはコンパイルする前にソースコードを前処理するためにコンパイラによって使用されます。ディレクティブは常に#で始まります。したがって、コンパイラは変数名、関数名などでのこのシンボルの使用を禁止します。

各ディレクティブはエントリごとに指定されます。1つのエントリで複数のディレクティブを使用することはできません。ディレクティブエントリが大きすぎる場合は、 ‘\’ 記号を使用して複数の行に分割します。この場合、次の行はディレクティブエントリの続きと見なされます。

//+——————————————————————+
//|  foreach擬似演算子                                                 |
//+——————————————————————+
#define ForEach(index, array) for (int index = 0,                    \
max_##index=ArraySize((array));                                   \
index<max_##index; index++)
//+——————————————————————+
//| スクリプトプログラム開始関数                                              |
//+——————————————————————+
void OnStart()
{
string array[]={“12”,“23”,“34”,“45”};
//— ForEachを使用して配列をバイパスする
ForEach(i,array)
{
PrintFormat(“%d: array[%d]=%s”,i,i,array[i]);
}
}
//+——————————————————————+
/* 結果の出力
0: array[0]=12
1: array[1]=23
2: array[2]=34
3: array[3]=45
*/

これら3つの #defineディレクティブは、コンパイラには1つの長い行のように見えます。上記の例は ##も適用します。これは、2つのマクロトークンを1つにマージする#defineマクロで使用されるマージ演算子です。トークンマージ演算子は、マクロ定義の最初または最後として使用することはできません。

マクロ代入( #define )

プリプロセッサディレクティブはコンパイルする前にソースコードを前処理するためにコンパイラによって使用されます。ディレクティブは常に#で始まります。したがって、コンパイラは変数名、関数名などでのこのシンボルの使用を禁止します。

各ディレクティブはエントリごとに指定されます。1つのエントリで複数のディレクティブを使用することはできません。ディレクティブエントリが大きすぎる場合は、 ‘\’ 記号を使用して複数の行に分割します。この場合、次の行はディレクティブエントリの続きと見なされます。

#define ディレクティブは、定数にニーモニック名を割り当てるために使用することが出来ます。#define には 2 つの形式があります。

#define 識別子式                           // パラメータなしの形式
#define 識別子 (パラメータ1,… パラメータ8) 式   // パラメトリック形式

#define ディレクティブは後に続くソーステキストで識別子があった場合その全てにを代入します。代入は識別子が独立したトークンである場合にのみ行わます。代入は識別子がコメントの一部、文字列の一部、または他の長い識別子の一部である場合には行われません。

定数識別子は、変数名と同じ規則によって扱われます。値は任意の型のものとすることが出来ます。

#define ABC               100
#define PI                3.14
#define COMPANY_NAME     “MetaQuotes Software Corp.”

void ShowCopyright()
{
Print(“Copyright  2001-2009, “,COMPANY_NAME);
Print(“https://www.metaquotes.net”);
}

はキーワード、定数、定数及び非定数式などのいくつかのトークンで構成されます。は行の終わりで終了し、次の行に続くことは出来ません。

例:

#define TWO        2
#define THREE      3
#define INCOMPLETE TWO+THREE
#define COMPLETE  (TWO+THREE)
void OnStart()
{
Print(“2 + 3*2 = “,INCOMPLETE*2);
Print(“(2 + 3)*2 = “,COMPLETE*2);
}
// 結果
// 2 + 3*2 = 8
// (2 + 3)*2 = 10

 

パラメトリック形式の #define

パラメトリック形式の場合、後続する識別子の全てが実際のパラメータを考慮して代入されます。例えば、

// 2 つのパラメータ a と b を使用する例
#define A 2+3
#define B 5-1
#define MUL(a, b) ((a)*(b))

double c=MUL(A,B);
Print(“c=”,c);
/*
double c=MUL(A,B); の式は
double c=((2+3)*(5-1)); と同じです。
*/
// 結果
// c=20

見つけにくい非明白なエラーを防ぐために、式の中でパラメータを使用する際にはパラメータを括弧で囲むようにしてください。ブラケットを使用せずにコードを書き換えると、結果が異なります。

// 2 つのパラメータ a と b を使用する例
#define A 2+3
#define B 5-1
#define MUL(a, b) a*b

double c=MUL(A,B);
Print(“c=”,c);
/*
double c=MUL(A,B); の式は
double c=2+3*5-1; と同じです。
*/
// 結果
// c=16

パラメトリック形式では、最大で 8 つのパラメータが使用可能です。

// パラメトリック形式の正しい使い方
#define LOG(text) Print(__FILE__,“(“,__LINE__,“) :”,text)         // パラメータは「text」の 1 つ

// パラメトリック形式の不正な使い方        
#define WRONG_DEF(p1, p2, p3, p4, p5, p6, p7, p8, p9)   p1+p2+p3+p4 // パラメータが p1 から p9 の 8 つ以上

#undef ディレクティブ

#undef は、前に定義されたマクロ代入の宣言を解除します。

例:

#define MACRO

void func1()
{
#ifdef MACRO
Print(“MACRO is defined in “,__FUNCTION__);
#else
Print(“MACRO is not defined in “,__FUNCTION__);
#endif
}

#undef MACRO

void func2()
{
#ifdef MACRO
Print(“MACRO is defined in “,__FUNCTION__);
#else
Print(“MACRO is not defined in “,__FUNCTION__);
#endif
}

void OnStart()
{
func1();
func2();
}

/* 結果:
MACRO is defined in func1
MACRO is not defined in func2
*/

プログラムのプロパティ (#property)

全ての MQL5 プログラムは、明示的に起動せずにプログラムの中で適切なサービスを提供してクライアント端末を補助する #property という付加的な特定のパラメータを指定することが出来ます。これは、まず第一に、指標の外部設定に関連します。インクルードファイルに記載されているプロパティは完全に無視されます。プロパティは、メイン mq5 ファイルで指定する必要があります。

#property 識別子の値

コンパイラは、実行モジュールの設定に宣言された値を書き込みます。

定数

Type

説明

icon

string

EX5 プログラムのアイコンとして使用される画像ファイルへのパス。パス指定のルールはリソースの場合と同じです。このプロパティは、MQL5 のソースコードのメインモジュールで指定される必要があります。アイコンファイルは ICO 形式である必要があります。

link

string

会社のウェブサイトへのリンク。

copyright

string

会社名。

version

string

プログラムのバージョン(最大 31 文字)

説明

string

MQL5 プログラムの簡単な説明文。複数の説明が存在でき、各々がテキストの1行を記述します。合計した説明の長さは、改行を含んで 511 文字を超えることは出来ません。

stacksize

int

MQL5 プログラムスタックサイズ。関数の再帰呼び出しを実行する際には充分なサイズのスタックが必要です。

スクリプトまたはチャート上のエキスパートアドバイザーを起動する際には、8 MB 以上のスタックが割り当てられます。指標の場合には、スタックサイズは常に 1 MB に固定されています。

プログラムはがストラテジーテスターで起動される場合には、常に 16 MB のスタックが割り当てられます。

library

 

ライブラリ。start 関数は割り当てられません。export 修飾子のついた関数は 他の MQL5 プログラムにインポート出来ます。

indicator_applied_price

int

「適用価格」フィールドの初期値を指定します。値は ENUM_APPLIED_PRICE から選べます。プロパティが指定されていない場合、初期値は PRICE_CLOSE です。

indicator_chart_window

 

チャートウィンドウで指標を表示します。

indicator_separate_window

 

別ウィンドウで指標を表示します。

indicator_height

int

ピクセル単位での指標サブウィンドウの固定された高さ(INDICATOR_HEIGHT プロパティ)。

indicator_buffers

int

指標計算に使用されるバッファ数。

indicator_plots

int

指標の グラフィックシリーズの数。

indicator_minimum

double

個別の指標ウィンドウのスケーリングの下限。

indicator_maximum

double

個別の指標ウィンドウのスケーリングの上限。

indicator_labelN

string

データウィンドウに表示された N 番目のグラフィックシリーズ のラベルの設定。複数の指標バッファ(DRAW_CANDLES、DRAW_FILLINGなど)を必要とするグラフィックシリーズでは、ラベル名はセパレータ「 ; 」を使用して定義されています。

indicator_colorN

color

線 N の表示色。N はグラフィックシリーズの番号で 1 から始まります。

indicator_widthN

int

グラフィックシリーズの線の太さ。N はグラフィックシリーズの番号で 1 から始まります。

indicator_styleN

int

ENUM_LINE_STYLE を使用して指定されたグラフィックシリーズの線のスタイル。N はグラフィックシリーズの番号で 1 から始まります。

indicator_typeN

int

ENUM_DRAW_TYPE を使用して指定されたグラフィカルプロットの種類。. N はグラフィックシリーズの番号で 1 から始まります。</t4>

indicator_levelN

double

個別の指標ウィンドウにおける N の水平レベル。

indicator_levelcolor

color

指標の水平レベルの色。

indicator_levelwidth

int

指標の水平レベルの太さ。

indicator_levelstyle

int

指標の水平レベルのスタイル。

script_show_confirm

 

スクリプト実行の前に、確認メッセージウィンドウを表示します。

script_show_inputs

 

スクリプト実行の前にプロパティウィンドウを表示して確認メッセージウィンドウを無効化します。

tester_indicator

string

「indicator_name.ex5」の形式でのカスタム指標の名称。 対応するパラメータが定数文字列を介して設定されている場合、テストが必要な指標はiCustom() の呼び出しから自動的に定義されています。他の全ての場合(IndicatorCreate() 関数の使用や指標名を設定するパラメータでの非定数文字列の使用)、このプロパティが必要とされています。

tester_file

string

テスタのファイル名。二重引用符内で拡張子の表示も含みます(文字列定数)。指定されたファイルはテスタに渡されます。テストされるべき入力ファイルがある場合、指定が必ず必要です。

tester_library

string

二重引用符内で拡張子を含むライブラリ名。ライブラリは拡張子として「dll」または「ex5」を持つことが出来ます。テストを必要とするライブラリは自動的に定義されます。 しかし、ライブラリのいずれかがカスタム 指標で使用されている場合、このプロパティが必要です。

tester_set

string

入力パラメータの値とステップを含むセットファイルの名前。このファイルは、テスト及び最適化の前にテスタに渡されます。ファイル名は、拡張子を含み二重引用符で定数文字列として指定されます。

EA名とバージョン番号をセットファイル名に”<expert_name>_<number>.set”として指定すると、パラメータバージョンのダウンロードメニューに<number>バージョン番号の下に自動的に追加されます。たとえば、”MACD Sample_4.set”という名前は、これがバージョン番号が4の”MACD Sample.mq5″ EAのセットファイルであることを意味します。

フォーマットを調べるには、ストラテジーテスターでテスト/最適化設定を手動で保存し、この方法で作成したセットファイルを開くことをお勧めします。

tester_no_cache

string

ストラテジーテスターは最適化を実行する際にすべての実行されたテストパスを最適化キャッシュに保存します。ここではテスト結果は入力パラメータセットごとに保存されます。これにより、無駄な時間を再計算にかけることなく、再最適化中に同じパラメータに対する既製の結果を使用することができます。

しかし、一部のタスク (例: 数学計算) では、既成の結果が最適化キャッシュにあるかどうかにかかわらず、計算を実行する必要があります。この場合、ファイルにはtester_no_cacheプロパティが含まれるべきです。テスト結果はキャッシュに保存されるため、実行されたテストパスのすべてのデータはストラテジーテスターで確認できます。

tester_everytick_calculate

string

ストラテジーテスターでは、指標はそのデータがアクセスされるとき、すなわち指標バッファの値が要求されたときにのみ計算されます。各ティックで指標値を取得する必要がない場合、これによってテストと最適化の速度が大幅に上がります。

 

tester_everytick_calculateプロパティを指定することによって、全てのディックでの指標の計算を強要できます。

 

ストラテジーテスターの指標は、以下の場合にはすべてのティックで強制的に計算されます。

  • 可視化モードでのテスト
  • 指標にEventChartCustom、OnChartEvent、OnTimer関数がある
  • 指標はビルド番号1916以前のコンパイラで作成された

 

この関数はストラテジーテスターにのみ適用され、端末での指標は常に受信したティックごとに計算されます。

説明とバージョン番号に関するサンプルタスク

#property version     “3.70”     // エキスパートアドバイザーの現在のバージョン
#property description “ZigZag universal with Pesavento Patterns”
#property description “At the moment in the indicator several ZigZags with different algorithms are included”
#property description “It is possible to embed a large number of other indicators showing the highs and”
#property description “lows and automatically build from these highs and lows various graphical tools”

各指標バッファ用に別々のラベルを指定する例(”C open; C high; C low; C close”)

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   1
#property indicator_type1   DRAW_CANDLES
#property indicator_width1  3
#property indicator_label1 “C open;C high;C low;C close”

ファイルの読み込み (#include)

#include コマンドラインはプログラムのどこにでも配置することが出来ますが、通常は全てがソースコードの先頭に配置されます。呼び出し形式は下記の通りです。

#include <ファイル名>
#include “ファイル名”

例:

#include <WinUser32.mqh>
#include “mylib.mqh”

プリプロセッサは、#include <ファイル名> をWinUser32.mqh の内容に入れ替えます。山カッコは WinUser32.mqh ファイルが標準ディレクトリ(通常 terminal_installation_directory\MQL5\Include)から取得されることを示します。現在のディレクトリは検索に含まれません。

ファイル名は引用符で囲まれている場合、検索は(メインソースファイルが含まれている)現在のディレクトリで行われます。標準ディレクトリは検索に含まれません。

関数のインポート (#import)

関数はコンパイル済みの MQL5 モジュール( *.ex5 ファイル )及びオペレーティングシステムモジュール( *.dll ファイル )からインポートされます。モジュール名は #import ディレクティブで指定されます。コンパイラがインポートされた関数の呼び出しを正しく形成し、適切な伝達パラメータを整理するには、関数 の完全な記述が必要とされています。関数の記述は #import “モジュール名” ディレクティブの直後に続きます。新しいコマンド#import(パラメータなし)がインポートされた関数の記述ブロックを完了します。

#import “file_name”
func1 define;
func2 define;

funcN define;
#import

インポートされた関数は任意の名称を持つことが出来ます。異なるモジュールからの同名の関数も同時にインポートされることが出来ます。インポートされた関数は、組み込み関数の名称と同じ名称を持つことが出来ます。スコープ解決演算がどちらの関数が呼び出されるかを定義します。

#import キーワードの後に指定されたファイルの検索順序は、インポートした関数の呼び出しで説明されています。

インポートされた関数はコンパイルされたモジュールの外側にあるので、コンパイラは渡されたパラメータの妥当性を検証することは出来ません。そのため、ランタイムエラーを回避するためには、インポートされた関数に渡されたパラメータの組成と順序を正確に記述する必要があります。(EX5とDLLモジュールから)インポートされた関数に渡されたパラメータは、初期値を持つことが出来ます。

以下は、インポートされた関数のパラメータとして使用することは出来ません。

  • ポインタ( * )
  • 動的配列を含むオブジェクトへのリンク及び/またはポインタ

クラス、文字列、または文字列及び/または任意の型の動的配列を含んでいる複合オブジェクトは、DLLからインポートされた関数にパラメータとして渡すことはできません。

例:

#import “stdlib.ex5”
string ErrorDescription(int error_code);
int    RGB(int red_value,int green_value,int blue_value);
bool   CompareDoubles(double number1,double number2);
string DoubleToStrMorePrecision(double number,int precision);
string IntegerToHexString(int integer_number);
#import “ExpertSample.dll”
int    GetIntValue(int);
double GetDoubleValue(double);
string GetStringValue(string);
double GetArrayItemValue(double &arr[],int,int);
bool   SetArrayItemValue(double &arr[],int,int,double);
double GetRatesItemValue(double &rates[][6],int,int,int);
#import

MQL5 プログラムの実行時に関数をインポートするには、事前結合が使用されます。これは、ライブラリはそれを利用する EX5 プログラムの読み込み時に読み込みされることを意味します。

Drive:\Directory\FileName.Ext のように読み込まれるモジュールの完全修飾名を使用することは推薦されていません。MQL5 ライブラリはterminal_dir\MQL5\Libraries フォルダから読み込まれます。

インポートされた関数の呼び出しバージョンが32ビット版と64ビット版Windowsで異なる場合は、両方ともインポートし、_IsX64変数を使って正しい関数バージョンを明確的に呼び出す必要があります。

例:

#import “user32.dll”
//— 32ビットシステム
int    MessageBoxW(uint hWnd,string lpText,string lpCaption,uint uType);
//— 64ビットシステム
int    MessageBoxW(ulong hWnd,string lpText,string lpCaption,uint uType);
#import
//+——————————————————————+
//|  MessageBox_32_64_bit は MessageBoxW() の適切なバージョンを使用する  |
//+——————————————————————+
int MessageBox_32_64_bit()
{
int res=-1;
//— 64 ビット Windows 使用の場合
if(_IsX64)
{
ulong hwnd=0;
res=MessageBoxW(hwnd,“64-bit MessageBoxW call example”,“MessageBoxW 64 bit”,MB_OK|MB_ICONINFORMATION);
}
else // 32 ビット Windows 使用の場合
{
uint hwnd=0;
res=MessageBoxW(hwnd,“32-bit MessageBoxW call example”,“MessageBoxW 32 bit”,MB_OK|MB_ICONINFORMATION);
}
return (res);
}
//+——————————————————————+
//| スクリプトプログラム開始関数                        |
//+——————————————————————+
void OnStart()
{
//—
int ans=MessageBox_32_64_bit();
PrintFormat(“MessageBox_32_64_bit returned %d”,ans);
}

条件付きコンパイル( #ifdef、#ifndef、#else、#endif )

プリプロセッサディレクティブはコンパイルする前にソースコードを前処理するためにコンパイラによって使用されます。ディレクティブは常に#で始まります。したがって、コンパイラは変数名、関数名などでのこのシンボルの使用を禁止します。

各ディレクティブはエントリごとに指定されます。1つのエントリで複数のディレクティブを使用することはできません。ディレクティブエントリが大きすぎる場合は、 ‘\’ 記号を使用して複数の行に分割します。この場合、次の行はディレクティブエントリの続きと見なされます。

プリプロセッサの条件付きコンパイルディレクティブは、特定の条件の成立に応じて、プログラムの一部をコンパイルまたはスキップすることを可能にします。

条件は、次のいずれかの形式を取ることが出来ます。

#ifdef 識別子
//ここにあるコードは、識別子がすでに #define ディレクティブのプリプロセッサに定義されている場合にコンパイルされます。
#endif

#ifndef 識別子
// ここにあるコードは、識別子がすでに #define ディレクティブのプリプロセッサに定義されていない場合にコンパイルされます。
#endif

条件付きコンパイルディレクティブは複数の行で続けられ、任意の #else を含んで #endif で終わります。検証条件が true の場合、#else と #endif の間の行は無視されます。検証条件が満たされていない場合は、チェックと #else ディレクティブ( #else が存在しない場合は #endif ディレクティブ)の間の行は全て無視されます。

例:

#ifndef TestMode
#define TestMode
#endif
//+——————————————————————+
//| スクリプトプログラムを開始する関数                                          |
//+——————————————————————+
void OnStart()
{
  #ifdef TestMode
Print(“Test mode”);
  #else
Print(“Normal mode”);
  #endif
}

標準マクロは、プログラムの種類とコンパイルモードに応じて以下のように定義されています。

__MQL5__  マクロは *.mq5 ファイル、__MQL4__ は *.mq4 ファイルをコンパイルする時に定義されます。
_DEBUG マクロはデバグモードでコンパイルする時に定義されます。
_RELEASE マクロはリリースモードでコンパイルする時に定義されます。

例:

//+——————————————————————+
//| スクリプトプログラムを開始する関数                                          |
//+——————————————————————+
void OnStart()
{
  #ifdef __MQL5__
#ifdef _DEBUG
Print(“Hello from MQL5 compiler [DEBUG]”);
#else
#ifdef _RELEASE
Print(“Hello from MQL5 compiler [RELEASE]”);
#endif
#endif
  #else
#ifdef __MQL4__
#ifdef _DEBUG
Print(“Hello from MQL4 compiler [DEBUG]”);
#else
#ifdef _RELEASE
Print(“Hello from MQL4 compiler [RELEASE]”);
#endif
#endif
#endif
  #endif
}

Originally posted 2019-07-27 10:27:10.

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">