- ArrayCopy関数の働き・役割
- ArrayCopy関数の引数について
- ArrayCopy関数の戻り値について
- ArrayCopy関数を使う際の注意点
- ArrayCopy関数を使ったサンプルコードについて
- サンプルコード解説1:プロパティ命令部分
- 1. #property indicator_chart_window
- 2. #property indicator_buffers 5
- 3. #property indicator_plots 1
- 4. #property indicator_label1 "Extremums"
- 5. #property indicator_type1 DRAW_COLOR_CANDLES
- 6. #property indicator_color1 clrLightSteelBlue,clrRed,clrBlue
- 7. #property indicator_style1 STYLE_SOLID
- 8. #property indicator_width1 1
- サンプルコード解説2:その他のグローバル領域部分
- サンプルコード解説3:FillCandles関数(オリジナル関数)部分
- サンプルコード解説4:OnInit関数部分
- OnInit関数の概要
- 各部分の解説
- 1. SetIndexBuffer(0, ExtOpen)
- 2. SetIndexBuffer(1, ExtHigh)
- 3. SetIndexBuffer(2, ExtLow)
- 4. SetIndexBuffer(3, ExtClose)
- 5. SetIndexBuffer(4, ExtColor, INDICATOR_COLOR_INDEX)
- 6. PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, INDICATOR_EMPTY_VALUE)
- 7. PlotIndexSetString(0, PLOT_LABEL, “Open;High;Low;Close”)
- 8. return(INIT_SUCCEEDED)
- サンプルコード解説5:OnCalculate関数部分その1
- サンプルコード解説6:OnCalculate関数部分その2
- サンプルコード解説7:OnCalculate関数部分その3
- サンプルコード解説8:OnCalculate関数部分その4
- サンプルコード解説9:OnCalculate関数部分その5
- サンプルコード解説10:IsMax関数(オリジナル関数)部分
- サンプルコード解説11:IsMin関数(オリジナル関数)部分
ArrayCopy関数の働き・役割
ArrayCopy関数は、1つの配列を別の配列にコピーするために使用されます。この関数では、コピー元配列から複製先の配列に要素を転送し、必要に応じてコピーする開始位置や要素数を指定できます。配列のタイプに応じて、同じデータ型同士でのコピーが可能であり、時系列配列を含む動的配列の場合、複製先のサイズも自動で調整されます。
ArrayCopy関数の引数について
int ArrayCopy(
void& dst_array[], // 複製先の配列
const void& src_array[], // ソース配列
int dst_start=0, // 複製先の配列の開始インデックス
int src_start=0, // ソース配列の開始インデックス
int count=WHOLE_ARRAY // 要素の数
);
ArrayCopy関数は、以下の5つの引数を使用します。
- dst_array[]
コピー先の配列です。コピー元の配列のデータがこの配列に書き込まれます。 - src_array[]
コピー元の配列です。この配列からデータが読み取られ、コピー先の配列に書き込まれます。 - dst_start = 0
コピー先の配列のどの位置からデータを書き込むかを指定します。デフォルトは0(最初の要素)です。 - src_start = 0
コピー元の配列のどの位置からデータをコピーするかを指定します。デフォルトは0(最初の要素)です。 - count = WHOLE_ARRAY
コピーする要素数を指定します。デフォルトでは、配列全体がコピーされます。
ArrayCopy関数の戻り値について
ArrayCopy関数の戻り値は、コピーに成功した要素の数です。具体的には、指定した要素数(count)が複製先にコピーされ、その実際にコピーされた要素の数が戻り値として返されます。指定した要素数よりもコピー元の配列の残り要素が少ない場合は、コピー可能な要素数が返されます。
例えば、コピー元の配列に残り要素が3つしかない場合、指定した要素数が5であっても、戻り値は3となります。
ArrayCopy関数を使う際の注意点
ArrayCopy関数を使用する際には、いくつかの重要なポイントを理解しておく必要があります。複製元と複製先の配列が異なる型の場合、MQL5は可能な限り自動的に型変換を試みますが、文字列配列や構造体の配列は同じ型の配列にしかコピーできません。クラスや初期化が必要なオブジェクトを含む配列はコピーできないため、注意が必要です。
また、動的な時系列配列に対しては、複製先の配列が自動的にサイズ調整されますが、配列のサイズが減少することはありません。これは、時系列データを処理する場合に特に重要です。コピーする要素数(count)が負の値であったり、コピー元配列の要素数を超える場合には、残りのすべての要素がコピーされるため、コピーの範囲に注意が必要です。
さらに、countを指定しない場合、デフォルトで配列全体がコピーされます。必要な要素数を指定することで、不要なデータが複製されることを防ぐことができます。
コピー操作が左から右へ行われることにも注意が必要です。配列がシリーズ配列の場合、データの順序に影響を与えることがあるため、適切なインデックス設定を行うことが大切です。
ArrayCopy関数を使ったサンプルコードについて
//--- 指標の設定: このカスタム指標をチャートウィンドウに表示する
#property indicator_chart_window
//--- 5つのバッファを使用する設定
#property indicator_buffers 5
//--- 1つのプロット(描画対象)を設定
#property indicator_plots 1
//--- プロットの設定: プロット名、種類、色、スタイル、幅の設定
#property indicator_label1 "Extremums" // プロットラベル
#property indicator_type1 DRAW_COLOR_CANDLES // 色付きのローソク足を描画
#property indicator_color1 clrLightSteelBlue,clrRed,clrBlue // 色の指定(複数の状態に対応)
#property indicator_style1 STYLE_SOLID // 線のスタイル
#property indicator_width1 1 // 線の幅
//--- 定義済み定数: 空の値を表す
#define INDICATOR_EMPTY_VALUE 0.0
//--- 入力パラメータ: 指標に使用する区間の半分の長さを指定
input int InpNum=4; // 極値を探すための区間長さの半分
//--- 指標バッファ: 各ローソク足の開値、高値、安値、終値、色を格納する配列
double ExtOpen[]; // 開値を格納するバッファ
double ExtHigh[]; // 高値を格納するバッファ
double ExtLow[]; // 安値を格納するバッファ
double ExtClose[]; // 終値を格納するバッファ
double ExtColor[]; // 各ローソク足の色を格納するバッファ
//--- グローバル変数
int ExtStart=0; // 非極値の最初のローソク足のインデックス
int ExtCount=0; // 区間内の非極値の数
//+------------------------------------------------------------------+
//| 非極値のローソク足に値を入れる関数 |
//| ソース配列から複製先の配列にデータをコピーする |
//+------------------------------------------------------------------+
void FillCandles(const double &open[],const double &high[],
const double &low[],const double &close[])
{
//--- ソースのローソク足データを各バッファにコピーする
ArrayCopy(ExtOpen,open,ExtStart,ExtStart,ExtCount); // 開値をコピー
ArrayCopy(ExtHigh,high,ExtStart,ExtStart,ExtCount); // 高値をコピー
ArrayCopy(ExtLow,low,ExtStart,ExtStart,ExtCount); // 安値をコピー
ArrayCopy(ExtClose,close,ExtStart,ExtStart,ExtCount); // 終値をコピー
}
//+------------------------------------------------------------------+
//| カスタム指標の初期化関数 |
//| 指標をチャートに表示するための準備を行う |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指標バッファを各プロットにマッピングする
SetIndexBuffer(0,ExtOpen); // 開値バッファをマッピング
SetIndexBuffer(1,ExtHigh); // 高値バッファをマッピング
SetIndexBuffer(2,ExtLow); // 安値バッファをマッピング
SetIndexBuffer(3,ExtClose); // 終値バッファをマッピング
SetIndexBuffer(4,ExtColor,INDICATOR_COLOR_INDEX); // 色バッファをマッピング
//--- 指定した値(INDICATOR_EMPTY_VALUE)が空の値として扱われる設定
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,INDICATOR_EMPTY_VALUE);
//--- データウィンドウに表示されるラベルを設定
PlotIndexSetString(0,PLOT_LABEL,"Open;High;Low;Close");
//--- 初期化が成功したことを示す戻り値
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| カスタム指標の計算関数 |
//| 毎ティック実行され、指標を計算するメインロジック |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, // 利用可能なバーの総数
const int prev_calculated, // 前回計算されたバー数
const datetime &time[], // 日時データ
const double &open[], // 開値データ
const double &high[], // 高値データ
const double &low[], // 安値データ
const double &close[], // 終値データ
const long &tick_volume[], // ティックボリューム
const long &volume[], // ボリュームデータ
const int &spread[]) // スプレッドデータ
{
//--- 時系列配列を通常のインデックスに設定する
ArraySetAsSeries(open,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(close,false);
//--- 計算開始位置を決定する
int start=prev_calculated;
//--- 最初の指定したバー数は計算を行わない
if(start==0)
{
start+=InpNum*2;
ExtStart=0;
ExtCount=0;
}
//--- 計算が終わったバーが1つしかない場合、極値チェックを行う
if(rates_total-start==1)
start--;
//--- 極値のチェックを行うバーのインデックス
int ext;
//--- 指標の計算ループ
for(int i=start;i<rates_total-1;i++)
{
//--- i番目のバーに値をリセットする(初期化)
ExtOpen[i]=0;
ExtHigh[i]=0;
ExtLow[i]=0;
ExtClose[i]=0;
//--- 極値をチェックするインデックスを計算
ext=i-InpNum;
//--- 極大をチェック
if(IsMax(high,ext))
{
//--- 極大値であるローソク足を強調表示する
ExtOpen[ext]=open[ext];
ExtHigh[ext]=high[ext];
ExtLow[ext]=low[ext];
ExtClose[ext]=close[ext];
ExtColor[ext]=1; // 極大を表す色を設定
//--- 極値までのローソク足を中間色で強調表示
FillCandles(open,high,low,close);
//--- 極値の開始位置と非極値の数をリセット
ExtStart=ext+1;
ExtCount=0;
//--- 次の反復に進む
continue;
}
//--- 極小をチェック
if(IsMin(low,ext))
{
//--- 極小値であるローソク足を強調表示する
ExtOpen[ext]=open[ext];
ExtHigh[ext]=high[ext];
ExtLow[ext]=low[ext];
ExtClose[ext]=close[ext];
ExtColor[ext]=2; // 極小を表す色を設定
//--- 極値までのローソク足を中間色で強調表示
FillCandles(open,high,low,close);
//--- 極値の開始位置と非極値の数をリセット
ExtStart=ext+1;
ExtCount=0;
//--- 次の反復に進む
continue;
}
//--- 非極値の数を増やす
ExtCount++;
}
//--- 次回呼び出し時に使用するために、計算済みのバー数を返す
return(rates_total);
}
//+------------------------------------------------------------------+
//| 現在の配列要素が極大かどうかを確認する関数 |
//+------------------------------------------------------------------+
bool IsMax(const double &price[],const int ind)
{
//--- 区間の開始位置を計算
int i=ind-InpNum;
//--- 区間の終了位置を計算
int finish=ind+InpNum+1;
//--- 区間の前半をチェックし、極大値かを確認
for(;i<ind;i++)
{
if(price[ind]<=price[i])
return(false); // 現在の値が過去の値以下なら極大ではない
}
//--- 区間の後半をチェックし、極大値かを確認
for(i=ind+1;i<finish;i++)
{
if(price[ind]<=price[i])
return(false); // 現在の値が未来の値以下なら極大ではない
}
//--- 極大値を発見
return(true);
}
//+------------------------------------------------------------------+
//| 現在の配列要素が極小かどうかを確認する関数 |
//+------------------------------------------------------------------+
bool IsMin(const double &price[],const int ind)
{
//--- 区間の開始位置を計算
int i=ind-InpNum;
//--- 区間の終了位置を計算
int finish=ind+InpNum+1;
//--- 区間の前半をチェックし、極小値かを確認
for(;i<ind;i++)
{
if(price[ind]>=price[i])
return(false); // 現在の値が過去の値以上なら極小ではない
}
//--- 区間の後半をチェックし、極小値かを確認
for(i=ind+1;i<finish;i++)
{
if(price[ind]>=price[i])
return(false); // 現在の値が未来の値以上なら極小ではない
}
//--- 極小値を発見
return(true);
}
サンプルコード解説1:プロパティ命令部分
//--- 指標の設定: このカスタム指標をチャートウィンドウに表示する
#property indicator_chart_window
//--- 5つのバッファを使用する設定
#property indicator_buffers 5
//--- 1つのプロット(描画対象)を設定
#property indicator_plots 1
//--- プロットの設定: プロット名、種類、色、スタイル、幅の設定
#property indicator_label1 "Extremums" // プロットラベル
#property indicator_type1 DRAW_COLOR_CANDLES // 色付きのローソク足を描画
#property indicator_color1 clrLightSteelBlue,clrRed,clrBlue // 色の指定(複数の状態に対応)
#property indicator_style1 STYLE_SOLID // 線のスタイル
#property indicator_width1 1 // 線の幅
このセクションでは、カスタム指標のプロパティ設定部分について解説します。プロパティ設定は、指標の基本的な動作や外観を定義するために使用されます。
1. #property indicator_chart_window
このプロパティは、カスタム指標をチャートウィンドウに表示するための設定です。MQL5では、カスタム指標をチャートウィンドウやサブウィンドウに表示することができますが、この命令により、チャートウィンドウに表示されることが指定されています。
2. #property indicator_buffers 5
このプロパティ命令は、指標が使用するバッファの数を設定しています。ここでは、5つのバッファが使用されることを指定しています。バッファは、指標が描画するためのデータを保存するための配列で、ローソク足の情報や色などを格納します。
3. #property indicator_plots 1
このプロパティ命令は、プロットの数を設定します。プロットとは、実際にチャート上に描画されるグラフィック要素を指します。この例では、1つのプロット(描画対象)が設定されており、それに基づいてローソク足が描かれます。
4. #property indicator_label1 "Extremums"
このプロパティ命令は、プロットにラベル(名前)を付けています。ここでは、”Extremums”(極値)というラベルが設定されています。このラベルは、チャートのデータウィンドウに表示され、指標が何を表しているかを示す役割を果たします。
5. #property indicator_type1 DRAW_COLOR_CANDLES
このプロパティ命令はプロットの種類を指定します。DRAW_COLOR_CANDLESは、色付きのローソク足を描画するタイプを意味しています。ローソク足の形状や色を使って、視覚的に指標の結果を表現します。
6. #property indicator_color1 clrLightSteelBlue,clrRed,clrBlue
このプロパティ命令は、プロットに使用される色を設定します。clrLightSteelBlue、clrRed、clrBlueの3色が指定されています。これにより、ローソク足が異なる状態に応じて異なる色で描画されるようになります。たとえば、上昇トレンドと下降トレンドで色を変えることができます。
7. #property indicator_style1 STYLE_SOLID
このプロパティ命令は、プロットのスタイルを設定します。STYLE_SOLIDは、実線のスタイルを意味しています。これにより、ローソク足の線が実線として描画されることが指定されています。
8. #property indicator_width1 1
このプロパティ命令は、プロットの線の幅を設定します。ここでは、1ピクセル(デジタル画像を構成する最小の単位)の幅で描画されるように指定されています。線の太さを調整することで、チャート上での見やすさをコントロールできます。
これらのプロパティ設定により、カスタム指標の外観と動作が詳細に定義されています。指標がどのウィンドウに表示されるか、使用するバッファの数、描画するローソク足の色やスタイルまで、すべてが明確に指定されています。
サンプルコード解説2:その他のグローバル領域部分
//--- 定義済み定数: 空の値を表す
#define INDICATOR_EMPTY_VALUE 0.0
//--- 入力パラメータ: 指標に使用する区間の半分の長さを指定
input int InpNum=4; // 極値を探すための区間長さの半分
//--- 指標バッファ: 各ローソク足の開値、高値、安値、終値、色を格納する配列
double ExtOpen[]; // 開値を格納するバッファ
double ExtHigh[]; // 高値を格納するバッファ
double ExtLow[]; // 安値を格納するバッファ
double ExtClose[]; // 終値を格納するバッファ
double ExtColor[]; // 各ローソク足の色を格納するバッファ
//--- グローバル変数
int ExtStart=0; // 非極値の最初のローソク足のインデックス
int ExtCount=0; // 区間内の非極値の数
このセクションでは、指標における定義済み定数、入力パラメータ、指標バッファ、グローバル変数について解説します。これらは、指標全体で使用される重要なデータの保存や初期設定を行うために使用されています。
1. #define INDICATOR_EMPTY_VALUE 0.0
この定義は、指標の中で「空の値」として使用される定数を設定しています。ここでは0.0が指定されており、指標計算でデータが存在しない箇所や無効な値を示すために使用されます。たとえば、ローソク足が存在しない部分などにこの値が使われ、描画しないように設定できます。
2. input int InpNum=4
これは入力パラメータで、指標に外部から値を設定できるようにしています。この場合、InpNumは極値(最大値や最小値)を探すために使用する区間の半分の長さを表しています。デフォルトでは4が設定されており、ユーザーがこの値を変更することで、指標が極値を判定する際の区間を調整できます。
3. double ExtOpen[], ExtHigh[], ExtLow[], ExtClose[], ExtColor[]
これらは指標バッファと呼ばれる配列で、各ローソク足のデータを格納するために使用されます。
- ExtOpen[]は、各ローソク足の始値を保存します。
- ExtHigh[]は、高値を保存します。
- ExtLow[]は、安値を保存します。
- ExtClose[]は、終値を保存します。
- ExtColor[]は、各ローソク足の色(グラフィカルな強調表示に使用)を保存します。
これらのバッファは、各ローソク足のデータをグラフィカルに描画するために必要な情報を保持しており、後続の処理で使用されます。
4. int ExtStart=0
ExtStartは、非極値(最大値や最小値ではないローソク足)の最初のインデックスを記録するために使用されるグローバル変数です。極値のチェックを行う際に、この変数は次の計算における開始位置として機能します。初期値は0に設定されていますが、指標の計算中に更新されます。
5. int ExtCount=0
ExtCountは、現在の区間内で非極値のローソク足の数を記録するために使用されます。この変数は、極値を判定するための補助的な役割を果たし、極値ではないローソク足の数をカウントして管理します。
これらの定義済み定数や変数は、指標全体で重要な役割を果たします。入力パラメータはユーザーが自由に設定できるため、指標の挙動をカスタマイズ可能にします。指標バッファは、各ローソク足のデータや描画情報を保持し、グローバル変数は計算の進行や結果に基づいたデータを管理するために使われています。
サンプルコード解説3:FillCandles関数(オリジナル関数)部分
//| 非極値のローソク足に値を入れる関数 |
//| ソース配列から複製先の配列にデータをコピーする |
//+------------------------------------------------------------------+
void FillCandles(const double &open[],const double &high[],
const double &low[],const double &close[])
{
//--- ソースのローソク足データを各バッファにコピーする
ArrayCopy(ExtOpen,open,ExtStart,ExtStart,ExtCount); // 開値をコピー
ArrayCopy(ExtHigh,high,ExtStart,ExtStart,ExtCount); // 高値をコピー
ArrayCopy(ExtLow,low,ExtStart,ExtStart,ExtCount); // 安値をコピー
ArrayCopy(ExtClose,close,ExtStart,ExtStart,ExtCount); // 終値をコピー
}
このセクションでは、FillCandles関数について解説します。この関数は、ローソク足データを別の配列にコピーする役割を持ち、ArrayCopy関数を利用して処理を行っています。さらに、引数として渡される配列がどのような役割を果たしているかについても解説します。
FillCandles関数の概要
FillCandles関数は、渡された4つの配列(始値、 高値、 安値、 終値)を元に、ExtOpen、ExtHigh、ExtLow、ExtCloseという各バッファにデータをコピーします。このコピー処理には、ArrayCopy関数を用いています。この関数は、非極値のローソク足に対して始値、高値、安値、終値のデータを記録していく際に使用されます。
各引数の役割
open[]
open[]は、ローソク足の始値データを格納している配列です。関数の中では、この始値データをExtOpenというバッファにコピーしています。このバッファは後にチャートに表示される始値のデータとなります。
high[]
high[]は、ローソク足の高値データを格納している配列です。関数内でこの配列のデータはExtHighバッファにコピーされ、チャートに表示される高値データとなります。
low[]
low[]は、ローソク足の安値データを格納している配列です。このデータはExtLowバッファにコピーされ、同様にチャート上で安値として使用されます。
close[]
close[]は、ローソク足の終値データを持つ配列です。この終値データも、ArrayCopy関数によってExtCloseバッファにコピーされ、チャートに終値として描画されます。
関数の動作
関数内部では、まずArrayCopy関数を使用して、指定された範囲のデータをコピー元配列から複製先バッファにコピーします。具体的には、ExtOpen、ExtHigh、ExtLow、ExtCloseという4つのバッファにそれぞれの値がコピーされます。
- ExtOpenにはopen[]配列のデータがコピーされます。これは始値に相当します。
- ExtHighにはhigh[]配列のデータがコピーされます。これは高値に相当します。
- ExtLowにはlow[]配列のデータがコピーされます。これは安値に相当します。
- ExtCloseにはclose[]配列のデータがコピーされます。これは終値に相当します。
また、ExtStartはコピーの開始位置を示し、ExtCountはコピーする要素の数を示しています。これにより、指定された範囲のローソク足データが正しく複製されます。
このFillCandles関数は、ローソク足の始値、高値、安値、終値を正確に別のバッファにコピーし、チャートに描画するための準備を行う重要な役割を果たしています。各引数は、それぞれローソク足の値に対応し、複製先のバッファに正確にデータを転送しています。
サンプルコード解説4:OnInit関数部分
//+------------------------------------------------------------------+
//| カスタム指標の初期化関数 |
//| 指標をチャートに表示するための準備を行う |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指標バッファを各プロットにマッピングする
SetIndexBuffer(0,ExtOpen); // 開値バッファをマッピング
SetIndexBuffer(1,ExtHigh); // 高値バッファをマッピング
SetIndexBuffer(2,ExtLow); // 安値バッファをマッピング
SetIndexBuffer(3,ExtClose); // 終値バッファをマッピング
SetIndexBuffer(4,ExtColor,INDICATOR_COLOR_INDEX); // 色バッファをマッピング
//--- 指定した値(INDICATOR_EMPTY_VALUE)が空の値として扱われる設定
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,INDICATOR_EMPTY_VALUE);
//--- データウィンドウに表示されるラベルを設定
PlotIndexSetString(0,PLOT_LABEL,"Open;High;Low;Close");
//--- 初期化が成功したことを示す戻り値
return(INIT_SUCCEEDED);
}
このセクションでは、カスタム指標の初期化を行うOnInit関数について解説します。この関数は、指標をチャート上に表示する準備を行い、指標のバッファを設定したり、描画のためのラベルや設定を整える重要な役割を担っています。
OnInit関数の概要
OnInit関数は、指標が初めて動作するときに一度だけ実行され、主に以下の処理を行います。
- 指標バッファのマッピング
- 指標の描画に使用されるラベルやスタイルの設定
- 必要な初期設定を行い、正常に初期化が完了したかどうかを示す値を返します。
各部分の解説
1. SetIndexBuffer(0, ExtOpen)
最初に、SetIndexBuffer関数を使用して、始値(Open)のデータを保存するExtOpenバッファをプロットにマッピングします。0番目のプロットに、このバッファが対応づけられ、チャート上に表示される準備が整います。
2. SetIndexBuffer(1, ExtHigh)
次に、高値(High)のデータを保存するExtHighバッファを1番目のプロットにマッピングします。この設定により、チャート上に高値のデータが描画されるようになります。
3. SetIndexBuffer(2, ExtLow)
同様に、安値(Low)のデータを保存するExtLowバッファを2番目のプロットにマッピングします。これによって、安値データがチャートに表示されます。
4. SetIndexBuffer(3, ExtClose)
終値(Close)のデータを保存するExtCloseバッファを3番目のプロットにマッピングします。終値のデータもこれによりチャート上に描画される準備が整います。
5. SetIndexBuffer(4, ExtColor, INDICATOR_COLOR_INDEX)
4番目のプロットには、ExtColorというバッファをマッピングします。このバッファはローソク足の色を管理しており、指標の色設定やグラフィカルな表現に使用されます。INDICATOR_COLOR_INDEXを指定することで、このバッファは色のインデックスを指示します。
6. PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, INDICATOR_EMPTY_VALUE)
PlotIndexSetDouble関数を使って、0番目のプロットで表示されるデータの空の値(データが存在しない場合に表示される値)を設定します。INDICATOR_EMPTY_VALUEとして設定された値が空の値として扱われ、データが存在しない部分が描画されないようになります。
7. PlotIndexSetString(0, PLOT_LABEL, “Open;High;Low;Close”)
この部分では、PlotIndexSetString関数を使用して、データウィンドウやチャート上で表示されるラベルを設定します。ここでは、「Open;High;Low;Close」というラベルが設定され、データウィンドウにはそれぞれの始値、高値、安値、終値が表示されるようになります。
8. return(INIT_SUCCEEDED)
最後に、OnInit関数は初期化が成功したことを示すINIT_SUCCEEDEDを返します。これにより、プログラム全体に初期化が正しく行われたことを通知します。
OnInit関数は、指標が正常に動作するための基本的な設定を行う重要な関数です。指標のバッファをプロットにマッピングし、データの表示に必要なラベルやスタイルを設定することで、指標がチャート上に正しく表示される準備が整います。
サンプルコード解説5:OnCalculate関数部分その1
//+------------------------------------------------------------------+
//| カスタム指標の計算関数 |
//| 毎ティック実行され、指標を計算するメインロジック |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, // 利用可能なバーの総数
const int prev_calculated, // 前回計算されたバー数
const datetime &time[], // 日時データ
const double &open[], // 開値データ
const double &high[], // 高値データ
const double &low[], // 安値データ
const double &close[], // 終値データ
const long &tick_volume[], // ティックボリューム
const long &volume[], // ボリュームデータ
const int &spread[]) // スプレッドデータ
{
//--- 時系列配列を通常のインデックスに設定する
ArraySetAsSeries(open,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(close,false);
//--- 計算開始位置を決定する
int start=prev_calculated;
//--- 最初の指定したバー数は計算を行わない
if(start==0)
{
start+=InpNum*2;
ExtStart=0;
ExtCount=0;
}
このセクションでは、カスタム指標の計算処理を行うOnCalculate関数について解説します。この関数は、毎ティック実行され、指標の計算を行うメインロジックを担当します。ここでは、OnCalculate関数の最初の部分について詳しく見ていきます。
OnCalculate関数の概要
OnCalculate関数は、チャート上のデータ(ローソク足の始値、高値、安値、終値など)を基に、カスタム指標を計算します。この関数は毎回ティックデータが更新されるたびに呼び出され、最新のデータを使って指標の更新を行います。引数として、各種データが渡され、計算結果が指標バッファに保存されます。
引数の解説
rates_total
チャート上で利用可能なバー(ローソク足)の総数を表します。これは、指標を計算する際に、どの範囲まで計算するかを決定するために使用されます。
prev_calculated
前回計算されたバー数を表します。この値を基に、すでに計算済みのバーを再計算せず、新しいデータだけを計算することで効率的に処理を行います。
time[]
ローソク足の日時データを格納する配列です。各バーの時刻情報が保存されており、このデータを使って時間軸に沿った分析や指標計算が行われます。
open[], high[], low[], close[]
それぞれ、始値、高値、安値、終値のデータを格納する配列です。これらのデータは、指標計算の基となるローソク足の値を示しています。OnCalculate関数内で、これらの配列を基に様々な計算が行われ、指標バッファに結果が反映されます。
tick_volume[], volume[], spread[]
それぞれ、ティックボリューム、ボリューム、スプレッドを示すデータです。これらのデータは、取引量や市場の流動性、売買のスプレッド(価格差)を反映しており、指標の計算に必要な場合に使用されます。
関数内部の解説
ArraySetAsSeries(open, false), ArraySetAsSeries(high, false), ArraySetAsSeries(low, false), ArraySetAsSeries(close, false)
ArraySetAsSeries関数を使い、配列のインデックスが通常の左から右の順序に設定されるようにします。MQL5では、時系列の配列はデフォルトで右から左にデータが格納されますが、通常のインデックスを使用して処理を行いたい場合、これらの命令で配列の順序を設定します。
int start = prev_calculated;
この部分では、計算の開始位置を決定しています。前回計算されたバーの数を基に、再度計算を行わず、新しいバーのみを計算するようにします。これにより、無駄な再計算を防ぎ、効率的な処理が可能になります。
if(start == 0)
最初の計算時には、startが0となります。初回の計算時には、指標計算に必要な特定のバー数が揃うまで計算を行わないため、初期設定として開始位置を調整します。
start += InpNum * 2
InpNumは極値(最大値や最小値)を探す際の区間の半分の長さを指定する入力パラメータです。この行では、最初に計算を行うバーの位置を決定しています。InpNumに基づいて、最初のバーの位置を調整し、適切な位置から計算を開始します。
ExtStart = 0, ExtCount = 0
初期化時に、ExtStartとExtCountが0にリセットされます。これらの変数は、非極値のローソク足の開始位置や、その数を追跡するために使用されます。これにより、次回の計算に備えて状態がリセットされます。
OnCalculate関数は、カスタム指標の計算において最も重要な関数です。この関数の最初の部分では、計算に必要なデータを準備し、効率的に処理を行うための初期設定が行われています。
サンプルコード解説6:OnCalculate関数部分その2
//--- 計算が終わったバーが1つしかない場合、極値チェックを行う
if(rates_total-start==1)
start--;
//--- 極値のチェックを行うバーのインデックス
int ext;
//--- 指標の計算ループ
for(int i=start;i<rates_total-1;i++)
{
//--- i番目のバーに値をリセットする(初期化)
ExtOpen[i]=0;
ExtHigh[i]=0;
ExtLow[i]=0;
ExtClose[i]=0;
//--- 極値をチェックするインデックスを計算
ext=i-InpNum;
このセクションでは、OnCalculate関数の後半部分について解説します。ここでは、実際に指標の計算が行われ、ローソク足データを基に極値(最大値や最小値)がチェックされる部分を中心に見ていきます。
計算ロジックの流れ
1. if(rates_total - start == 1)
この条件は、計算が終わったバーが1つしかない場合に、極値のチェックを行うためのものです。新しいバーが1つ追加された時点で、この条件が満たされます。その場合、startの値を1つ前に戻すことで、そのバーも再度チェック対象とします。これにより、極値が正確に反映されるように調整されています。
2. 極値のチェックを行うバーのインデックス
次に、極値(最大値や最小値)を計算するためのインデックスext
が定義されます。このインデックスは、現在のバーの位置(i)から、InpNum(区間の半分の長さ)を引いた値として設定されます。これにより、極値をチェックする範囲を定義し、その範囲内で最も高い値や低い値を確認することが可能になります。
3. 計算ループの開始
forループが始まり、バーごとの計算が実行されます。i
はstart
からrates_total - 1
までの範囲でループし、すべてのバーを対象に処理が行われます。
4. 各バーのデータリセット
ループ内では、まず各バーの始値(ExtOpen)、高値(ExtHigh)、安値(ExtLow)、終値(ExtClose)が0にリセットされます。これにより、極値が確認されていないバーに対して初期化処理が行われます。リセットすることで、次のステップで新しい値が正確に計算され、反映される準備が整います。
5. 極値チェックの準備
ext変数に、極値をチェックするためのインデックスが計算されます。このインデックスは、現在のバーからInpNum(区間の半分の長さ)を引いた値です。この範囲を基に、極値を探すためのチェックが行われます。
極値チェックのための準備
OnCalculate関数のこの部分では、バーごとのデータを処理し、始値や高値、安値、終値を初期化した上で、極値を計算するための準備が行われています。ここでの処理は、次の段階で極値が正しく判定されるための基礎となり、指標の正確な描画に貢献します。
サンプルコード解説7:OnCalculate関数部分その3
//--- 極大をチェック
if(IsMax(high,ext))
{
//--- 極大値であるローソク足を強調表示する
ExtOpen[ext]=open[ext];
ExtHigh[ext]=high[ext];
ExtLow[ext]=low[ext];
ExtClose[ext]=close[ext];
ExtColor[ext]=1; // 極大を表す色を設定
//--- 極値までのローソク足を中間色で強調表示
FillCandles(open,high,low,close);
//--- 極値の開始位置と非極値の数をリセット
ExtStart=ext+1;
ExtCount=0;
//--- 次の反復に進む
continue;
}
このセクションでは、OnCalculate関数の極値チェックに関する部分について解説します。ここでは、極大値(高値)を検出し、それに応じてローソク足のデータを処理する部分を中心に見ていきます。
極大値チェックの流れ
1. 極大をチェック
この条件文では、極大値(最大値)を検出するために、IsMax関数を使用しています。IsMax関数は、指定された範囲内で現在のバーが他のバーよりも高い値を持っているかどうかを確認します。もし現在のバーが極大値である場合、次の処理が実行されます。
2. 極大値であるローソク足を強調表示する
極大値が確認された場合、その極大値を表すローソク足の始値、高値、安値、終値を、それぞれ対応するバッファ(ExtOpen、ExtHigh、ExtLow、ExtClose)に保存します。これにより、チャート上でそのローソク足が表示されるようになります。
また、ExtColorバッファに1を設定することで、極大を示す色が設定されます。この色設定は、後にチャート上で極大を視覚的に強調表示するために使用されます。
3. 極値までのローソク足を中間色で強調表示
FillCandles関数を呼び出すことで、極大値から次の極値までの間にあるローソク足が強調表示されます。FillCandles関数は、始値、高値、安値、終値のデータを中間的な色で表示するために使用されます。これにより、極大値の位置が視覚的に明確になります。
4. 極値の開始位置と非極値の数をリセット
ExtStartに新しい極値のインデックスを設定し、次の処理の開始位置を更新します。また、ExtCountを0にリセットして、次の区間で非極値のカウントを再スタートさせます。
5. 次のループに進む
continue文により、次のループに進むため、ここで処理を終了します。これにより、極大値が確認された場合、再度同じバーを処理せず、次のバーに移動します。
OnCalculate関数のこの部分では、ローソク足の極大値を検出し、それに基づいてチャート上で強調表示を行います。この処理により、トレーダーは市場の極大値に基づいたトレンドの変化を視覚的に確認することができ、重要なトレンド転換点を把握する助けとなります。
サンプルコード解説8:OnCalculate関数部分その4
//--- 極小をチェック
if(IsMin(low,ext))
{
//--- 極小値であるローソク足を強調表示する
ExtOpen[ext]=open[ext];
ExtHigh[ext]=high[ext];
ExtLow[ext]=low[ext];
ExtClose[ext]=close[ext];
ExtColor[ext]=2; // 極小を表す色を設定
//--- 極値までのローソク足を中間色で強調表示
FillCandles(open,high,low,close);
//--- 極値の開始位置と非極値の数をリセット
ExtStart=ext+1;
ExtCount=0;
//--- 次の反復に進む
continue;
}
このセクションでは、OnCalculate関数の極小値(最小値)チェックに関する部分について解説します。この処理では、ローソク足データの中で極小値(最も低い値)を検出し、それに応じてローソク足を強調表示します。
極小値チェックの流れ
1. 極小をチェック
この条件文では、極小値(最小値)を検出するために、IsMin関数が使用されています。IsMin関数は、指定された範囲内で現在のバーが他のバーよりも低い値を持っているかどうかを確認します。もし現在のバーが極小値である場合、次の処理が実行されます。
2. 極小値であるローソク足を強調表示する
極小値が確認された場合、そのローソク足の始値、高値、安値、終値が、それぞれ対応するバッファ(ExtOpen、ExtHigh、ExtLow、ExtClose)に保存されます。これにより、チャート上でそのローソク足が表示されます。
さらに、ExtColorバッファに2を設定することで、極小を示す色が設定されます。これにより、チャート上で極小値が視覚的に強調表示され、重要なトレンド転換点として目立つようにします。
3. 極値までのローソク足を中間色で強調表示
FillCandles関数を呼び出すことで、極小値から次の極値までの間にあるローソク足が中間色で強調表示されます。始値、高値、安値、終値のデータが中間的な色で表示され、極小値が視覚的に区別されるようになります。
4. 極値の開始位置と非極値の数をリセット
ExtStartに新しい極小値のインデックスを設定し、次の処理の開始位置を更新します。また、ExtCountを0にリセットして、次の区間で非極値のカウントを再スタートさせます。これにより、新たな極値の検出と、その間のローソク足の数を管理できます。
5. 次の反復に進む
continue文を使用して、現在のループを終了し、次のループに進みます。極小値が検出された場合、すぐに次のバーの処理に移り、再度同じバーを処理しないようにしています。
OnCalculate関数のこの部分では、ローソク足の極小値を検出し、それに基づいてチャート上で強調表示を行います。この処理により、トレーダーは市場の極小値に基づいたトレンドの変化を視覚的に確認することができ、重要なトレンド転換点を把握するのに役立ちます。
サンプルコード解説9:OnCalculate関数部分その5
//--- 非極値の数を増やす
ExtCount++;
}
//--- 次回呼び出し時に使用するために、計算済みのバー数を返す
return(rates_total);
}
このセクションでは、OnCalculate関数の最終部分について解説します。ここでは、非極値のカウントを更新し、次回の呼び出し時に計算済みのバー数を返す処理が行われます。
非極値の数を増やす
ExtCount++
この行では、非極値の数をカウントするためにExtCountを1つ増やしています。ここまでの処理で極値(極大または極小)と判定されなかったローソク足は、非極値として扱われます。したがって、非極値のカウントが増加します。このカウントは、後続の処理で非極値の範囲を強調表示する際に使用されます。
次回呼び出し時に使用するために、計算済みのバー数を返す
return(rates_total)
最後に、return文を使用して、現在までに計算されたバーの総数(rates_total)を返します。この戻り値は、次回OnCalculate関数が呼び出された際に、再度全てのバーを計算する必要がないようにするためのものです。これにより、すでに計算されたバーをスキップし、効率的な計算処理が可能になります。
具体的には、次回呼び出された際に、prev_calculatedという引数にこのrates_totalの値が渡されるため、前回計算済みのバー以降から新しいバーのみを処理することができます。
OnCalculate関数のこの最後の部分では、極値と判定されなかった非極値のカウントを増やし、次回の処理に向けて計算済みのバー数を返すことで、効率的な指標計算が実現されています。これにより、無駄な再計算を防ぎ、指標のパフォーマンスを向上させることができます。
サンプルコード解説10:IsMax関数(オリジナル関数)部分
//+------------------------------------------------------------------+
//| 現在の配列要素が極大かどうかを確認する関数 |
//+------------------------------------------------------------------+
bool IsMax(const double &price[],const int ind)
{
//--- 区間の開始位置を計算
int i=ind-InpNum;
//--- 区間の終了位置を計算
int finish=ind+InpNum+1;
//--- 区間の前半をチェックし、極大値かを確認
for(;i<ind;i++)
{
if(price[ind]<=price[i])
return(false); // 現在の値が過去の値以下なら極大ではない
}
//--- 区間の後半をチェックし、極大値かを確認
for(i=ind+1;i<finish;i++)
{
if(price[ind]<=price[i])
return(false); // 現在の値が未来の値以下なら極大ではない
}
//--- 極大値を発見
return(true);
}
このセクションでは、IsMax関数について解説します。この関数は、ローソク足の価格データから、指定されたバーが極大値(他の価格よりも高い値)であるかを確認するために使用されます。関数の引数についても詳しく解説します。
IsMax関数の概要
IsMax関数は、与えられた範囲内の価格データを確認し、指定されたバーが極大値(最大値)かどうかを判断します。具体的には、指定されたインデックスのバーが、過去および未来のバーと比較して最も高い値を持っているかを確認します。
引数の説明
price[]
この引数は、価格データを格納する配列です。通常、始値、高値、安値、終値などの価格情報がこの配列に保存されています。この関数では、主に高値をチェックするために使用されます。
ind
indは、現在のバーのインデックスを表します。関数内で、このインデックスを基に極大値かどうかの判定を行います。現在のバーを基準に、過去のバーや未来のバーと比較するために使われます。
関数内の処理
1. 区間の開始位置と終了位置を計算
最初に、指定されたバーから比較対象となる過去のバーの開始位置を計算します。インデックスindから、InpNum(区間の半分の長さ)を引くことで、比較範囲の前半部分を決定します。同様に、終了位置としてindにInpNumを加えた値を計算し、区間の後半部分の比較範囲を設定します。
2. 区間の前半をチェック
forループを使って、区間の前半にあるバーを確認します。もし現在のバーの価格が、過去のバーの価格よりも小さいか等しい場合、そのバーは極大値ではないため、falseを返します。
3. 区間の後半をチェック
次に、区間の後半(未来のバー)をチェックします。forループを使って、未来のバーと比較し、もし現在のバーの価格が、未来のバーの価格よりも小さいか等しい場合、falseを返します。
4. 極大値の確認
区間の前半および後半の両方で、現在のバーが他のバーよりも高い場合、現在のバーは極大値であると判断され、trueが返されます。この結果により、OnCalculate関数内でローソク足が極大値として処理され、チャート上で強調表示されます。
IsMax関数は、指定された範囲内で現在のバーが極大値かどうかを判断するために使用されます。引数として渡される価格データとバーのインデックスを基に、過去および未来のバーと比較を行い、最大値であるかどうかを確認します。この処理により、トレーダーは市場のトレンド転換点を視覚的に把握することができます。
サンプルコード解説11:IsMin関数(オリジナル関数)部分
//+------------------------------------------------------------------+
//| 現在の配列要素が極小かどうかを確認する関数 |
//+------------------------------------------------------------------+
bool IsMin(const double &price[],const int ind)
{
//--- 区間の開始位置を計算
int i=ind-InpNum;
//--- 区間の終了位置を計算
int finish=ind+InpNum+1;
//--- 区間の前半をチェックし、極小値かを確認
for(;i<ind;i++)
{
if(price[ind]>=price[i])
return(false); // 現在の値が過去の値以上なら極小ではない
}
//--- 区間の後半をチェックし、極小値かを確認
for(i=ind+1;i<finish;i++)
{
if(price[ind]>=price[i])
return(false); // 現在の値が未来の値以上なら極小ではない
}
//--- 極小値を発見
return(true);
}
このセクションでは、IsMin関数について解説します。この関数は、ローソク足の価格データから指定されたバーが極小値(他の価格よりも低い値)であるかどうかを確認するために使用されます。関数の引数についても詳しく解説します。
IsMin関数の概要
IsMin関数は、指定された範囲内の価格データを確認し、指定されたバーが極小値(最小値)かどうかを判断します。具体的には、指定されたインデックスのバーが過去および未来のバーと比較して最も低い値を持っているかを確認します。
引数の説明
price[]
この引数は、価格データを格納する配列です。通常、始値、高値、安値、終値などの価格情報がこの配列に保存されています。この関数では、主に安値をチェックするために使用されます。
ind
indは、現在のバーのインデックスを表します。関数内で、このインデックスを基に極小値かどうかの判定を行います。現在のバーを基準に、過去および未来のバーと比較するために使われます。
関数内の処理
1. 区間の開始位置と終了位置を計算
最初に、指定されたバーから比較対象となる過去のバーの開始位置を計算します。インデックスindから、InpNum(区間の半分の長さ)を引くことで、比較範囲の前半部分を決定します。同様に、終了位置としてindにInpNumを加えた値を計算し、区間の後半部分の比較範囲を設定します。
2. 区間の前半をチェック
forループを使って、区間の前半にあるバーを確認します。もし現在のバーの価格が、過去のバーの価格よりも高いか等しい場合、そのバーは極小値ではないため、falseを返します。
3. 区間の後半をチェック
次に、区間の後半(未来のバー)をチェックします。forループを使って、未来のバーと比較し、もし現在のバーの価格が、未来のバーの価格よりも高いか等しい場合、falseを返します。
4. 極小値の確認
区間の前半および後半の両方で、現在のバーが他のバーよりも低い場合、現在のバーは極小値であると判断され、trueが返されます。この結果により、OnCalculate関数内でローソク足が極小値として処理され、チャート上で強調表示されます。
IsMin関数は、指定された範囲内で現在のバーが極小値かどうかを判断するために使用されます。引数として渡される価格データとバーのインデックスを基に、過去および未来のバーと比較を行い、最小値であるかどうかを確認します。この処理により、トレーダーは市場のトレンド転換点を視覚的に把握することができます。