- FileIsLineEnding関数の働き・役割
- FileIsLineEnding関数の引数について
- FileIsLineEnding関数の戻り値について
- FileIsLineEnding関数を使う際の注意点
- FileIsLineEnding関数を使ったサンプルコードについて
- コード解説1:プロパティ命令部分
- コード解説2:グローバル領域部分
- コード解説3:OnInit関数部分その1
- コード解説4:OnInit関数部分その2
- コード解説5:OnInit関数部分その3
- コード解説6:ReadData関数部分
- コード解説7:OnCalculate関数その1
- コード解説8:OnCalculate関数その2
- コード解説9:OnCalculate関数その3
- コード解説10:OnCalculate関数その4
- コード解説11:OnChartEvent関数
FileIsLineEnding関数の働き・役割
FileIsLineEnding関数は、テキストファイルの読み出し処理において、行の終わりを判定するために使用されます。この関数は、指定されたファイルハンドルを用いてファイル内の現在の読み取り位置が行の終わり(例えば、CR-LF)に達しているかどうかを確認します。もし行の終わりに達している場合は、trueを返します。これは、テキストやCSVファイルの処理時に重要な機能であり、行ごとにデータを読み取る際に役立ちます。
※CR-LFとは、コンピュータで使用される「キャリッジリターン(CR)」と「ラインフィード(LF)」という制御文字を指します。これらはテキストファイルの行の区切りを表すために使用されます。
- **CR(キャリッジリターン)**は、カーソルを行の先頭に移動させる制御文字です。
- **LF(ラインフィード)**は、カーソルを次の行に移動させる制御文字です。
Windowsのシステムでは、テキストファイルの改行は「CR+LF」の組み合わせで表されますが、LinuxやMac OSでは通常「LF」のみが使われます。
FileIsLineEnding関数の引数について
bool FileIsLineEnding(
int file_handle // ファイルハンドル
);
FileIsLineEnding関数は、1つの引数を取ります。
file_handle
FileOpen関数から戻されたファイルハンドルを指定します。このファイルハンドルを使って、ファイルの現在の読み取り位置が行の終わりに達しているかを確認します。
FileIsLineEnding関数の戻り値について
FileIsLineEnding関数は、テキストファイルやCSVファイルの読み取り処理において、現在の読み取り位置が行の終わりに達しているかを確認し、その結果を戻り値として返します。
戻り値は以下の通りです。
- true: ファイルの現在の読み取り位置が行の終わり(CR-LF)に達している場合。
- false: 行の終わりに達していない場合、またはファイルが閉じられている場合。
この戻り値を利用することで、行単位でのデータ処理が可能になります。
FileIsLineEnding関数を使う際の注意点
FileIsLineEnding関数を使用する際には、以下の点に留意する必要があります。
ファイルハンドルが有効であることを確認してから使用する必要があります。無効なファイルハンドルを渡すと、正しく判定が行えず、予期しない動作を引き起こす可能性があります。
FileIsLineEnding関数は、テキストファイルやCSVファイルなどの行の終わりが明示的にCR-LFで区切られているファイルに対して効果を発揮します。バイナリデータや行の終わりが異なる形式のファイルには対応していません。
ファイルを操作している際、ファイルが適切に開かれていない場合は、行の終わりの判定ができません。そのため、FileOpen関数などでファイルが正常に開かれているかを事前に確認することが必要です。
FileIsLineEnding関数を使ったサンプルコードについて
//+------------------------------------------------------------------+
//| カスタム指標をプロットする設定 |
//+------------------------------------------------------------------+
#property indicator_chart_window // チャート上に直接プロットする指標
#property indicator_buffers 5 // 指標に使用するバッファの数
#property indicator_plots 1 // プロットするラインの数
//---- ラベル1をプロットする設定
#property indicator_label1 "Overbought & Oversold" // ラベル名を設定
#property indicator_type1 DRAW_COLOR_BARS // カラーバーで表示
#property indicator_color1 clrRed, clrBlue // カラーバーの色(赤と青)
#property indicator_style1 STYLE_SOLID // ラインのスタイルはソリッド(実線)
#property indicator_width1 2 // ラインの幅を2ピクセルに設定
//--- データ読み込みのパラメータ
input string InpFileName="RSI.csv"; // ファイル名を指定(デフォルトはRSI.csv)
input string InpDirectoryName="Data"; // ディレクトリ名を指定(デフォルトはData)
//--- 指標に使用するバッファ
double open_buff[]; // 開始価格用バッファ
double high_buff[]; // 高値価格用バッファ
double low_buff[]; // 安値価格用バッファ
double close_buff[]; // 終値価格用バッファ
double color_buff[]; // カラーインデックス用バッファ
//--- 買われ過ぎを示す変数
int ovb_ind=0; // 買われ過ぎのインデックス
int ovb_size=0; // 買われ過ぎのサイズ
datetime ovb_time[]; // 買われ過ぎの時間を格納する配列
//--- 売られ過ぎを示す変数
int ovs_ind=0; // 売られ過ぎのインデックス
int ovs_size=0; // 売られ過ぎのサイズ
datetime ovs_time[]; // 売られ過ぎの時間を格納する配列
//+------------------------------------------------------------------+
//| カスタム指標を初期化する関数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- デフォルトの配列サイズ
int ovb_def_size=100; // 買われ過ぎ配列の初期サイズ
int ovs_def_size=100; // 売られ過ぎ配列の初期サイズ
//--- 配列のサイズを指定したデフォルトサイズに変更
ArrayResize(ovb_time,ovb_def_size); // 買われ過ぎ時間配列のリサイズ
ArrayResize(ovs_time,ovs_def_size); // 売られ過ぎ時間配列のリサイズ
//--- ファイルを開く
ResetLastError(); // エラーコードをリセット
int file_handle=FileOpen(InpDirectoryName+"//"+InpFileName,FILE_READ|FILE_CSV|FILE_ANSI); // ファイルをCSVモードで開く
if(file_handle!=INVALID_HANDLE) // ファイルが正常に開けた場合
{
//--- ファイルが開けたことをログに出力
PrintFormat("%s file is available for reading",InpFileName);
PrintFormat("File path: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
double value; // ファイルから読み取る値用の変数
//--- ファイルからデータを読み取る
while(!FileIsEnding(file_handle)) // ファイルの終端に達するまで読み込む
{
//--- ファイルから数値を読み込む
value=FileReadNumber(file_handle);
//--- 読み取った値に応じて処理を行う
if(value>=70) // 値が70以上なら買われ過ぎと判定
ReadData(file_handle,ovb_time,ovb_size,ovb_def_size); // 買われ過ぎのデータを読み取る
else // 70未満なら売られ過ぎと判定
ReadData(file_handle,ovs_time,ovs_size,ovs_def_size); // 売られ過ぎのデータを読み取る
}
//--- ファイルを閉じる
FileClose(file_handle); // ファイルハンドルを閉じる
PrintFormat("Data is written, %s file is closed",InpFileName); // ログに書き込み完了を表示
}
else // ファイルが開けなかった場合
{
//--- エラーメッセージを表示
PrintFormat("Failed to open %s file, Error code = %d",InpFileName,GetLastError());
return(INIT_FAILED); // 初期化失敗を返す
}
//--- バッファをインジケータに割り当てる
SetIndexBuffer(0,open_buff,INDICATOR_DATA); // 開始価格バッファをインジケータにセット
SetIndexBuffer(1,high_buff,INDICATOR_DATA); // 高値価格バッファをインジケータにセット
SetIndexBuffer(2,low_buff,INDICATOR_DATA); // 安値価格バッファをインジケータにセット
SetIndexBuffer(3,close_buff,INDICATOR_DATA); // 終値価格バッファをインジケータにセット
SetIndexBuffer(4,color_buff,INDICATOR_COLOR_INDEX); // カラーインデックスバッファをインジケータにセット
//--- チャートに表示されない値を設定
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); // 空の値を設定して表示を調整
return(INIT_SUCCEEDED); // 初期化成功を返す
}
//+------------------------------------------------------------------+
//| ファイルの文字列データを読み込む関数 |
//+------------------------------------------------------------------+
void ReadData(const int file_handle,datetime &arr[],int &size,int &def_size)
{
bool flag=false; // 1回目の読み取りをスキップするためのフラグ
//--- 行の終わりかファイルの終わりまでデータを読み込む
while(!FileIsLineEnding(file_handle) && !FileIsEnding(file_handle)) // ファイルの終端または行の終端まで読み込む
{
//--- 数値データを読み飛ばして次の位置に移動
if(flag)
FileReadNumber(file_handle); // 次の値を読み飛ばす
//--- 現在の日時を配列に格納
arr[size]=FileReadDatetime(file_handle); // 読み取った日時を配列に保存
size++; // サイズを増加
//--- 必要に応じて配列のサイズを拡張
if(size==def_size) // サイズがデフォルトサイズに達した場合
{
def_size+=100; // デフォルトサイズを100増加
ArrayResize(arr,def_size); // 配列サイズをリサイズ
}
flag=true; // 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(time,false); // time配列を時系列ではなく設定
ArraySetAsSeries(open,false); // open配列を時系列ではなく設定
ArraySetAsSeries(high,false); // high配列を時系列ではなく設定
ArraySetAsSeries(low,false); // low配列を時系列ではなく設定
ArraySetAsSeries(close,false); // close配列を時系列ではなく設定
//--- 処理されていないバーのループ
for(int i=prev_calculated;i<rates_total;i++) // 前回の計算からまだ処理していないバーを処理
{
//--- バッファの初期化
open_buff[i]=0; // 開始価格バッファを初期化
high_buff[i]=0; // 高値価格バッファを初期化
low_buff[i]=0; // 安値価格バッファを初期化
close_buff[i]=0; // 終値価格バッファを初期化
color_buff[i]=
0; // カラーバッファを初期化
//--- 買われ過ぎデータがまだ残っているか確認
if(ovb_ind<ovb_size) // 買われ過ぎデータが残っている場合
for(int j=ovb_ind;j<ovb_size;j++) // 買われ過ぎデータをチェック
{
//--- 日付が一致する場合、バーが買われ過ぎ領域にある
if(time[i]==ovb_time[j]) // バーの日時と買われ過ぎの日時が一致する場合
{
open_buff[i]=open[i]; // 開始価格をセット
high_buff[i]=high[i]; // 高値価格をセット
low_buff[i]=low[i]; // 安値価格をセット
close_buff[i]=close[i];// 終値価格をセット
color_buff[i]=0; // 赤(0)をセット
ovb_ind=j+1; // インデックスを更新
break; // ループを抜ける
}
}
//--- 売られ過ぎデータがまだ残っているか確認
if(ovs_ind<ovs_size) // 売られ過ぎデータが残っている場合
for(int j=ovs_ind;j<ovs_size;j++) // 売られ過ぎデータをチェック
{
//--- 日付が一致する場合、バーが売られ過ぎ領域にある
if(time[i]==ovs_time[j]) // バーの日時と売られ過ぎの日時が一致する場合
{
open_buff[i]=open[i]; // 開始価格をセット
high_buff[i]=high[i]; // 高値価格をセット
low_buff[i]=low[i]; // 安値価格をセット
close_buff[i]=close[i];// 終値価格をセット
color_buff[i]=1; // 青(1)をセット
ovs_ind=j+1; // インデックスを更新
break; // ループを抜ける
}
}
}
return(rates_total); // 次回の計算に備えて現在のバー数を返す
}
//+------------------------------------------------------------------+
//| チャートイベントハンドラ |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam
)
{
//--- チャートのスケールに応じてラインの幅を調整する
if(ChartGetInteger(0,CHART_SCALE)>3) // チャートのスケールが3以上の場合
PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2); // ライン幅を2に設定
else // スケールが3未満の場合
PlotIndexSetInteger(0,PLOT_LINE_WIDTH,1); // ライン幅を1に設定
}
コード解説1:プロパティ命令部分
//+------------------------------------------------------------------+
//| カスタム指標をプロットする設定 |
//+------------------------------------------------------------------+
#property indicator_chart_window // チャート上に直接プロットする指標
#property indicator_buffers 5 // 指標に使用するバッファの数
#property indicator_plots 1 // プロットするラインの数
//---- ラベル1をプロットする設定
#property indicator_label1 "Overbought & Oversold" // ラベル名を設定
#property indicator_type1 DRAW_COLOR_BARS // カラーバーで表示
#property indicator_color1 clrRed, clrBlue // カラーバーの色(赤と青)
#property indicator_style1 STYLE_SOLID // ラインのスタイルはソリッド(実線)
#property indicator_width1 2 // ラインの幅を2ピクセルに設定
このセクションでは、カスタム指標をチャートにプロットするための設定を行っています。各#property命令によって、指標の表示形式や使用するリソースが定義されています。以下、各命令の詳細を解説します。
#property indicator_chart_window
この命令は、カスタム指標がチャートのメインウィンドウにプロットされることを指定しています。チャート上に直接表示するインジケータを作成する場合に使用されます。
#property indicator_buffers 5
この命令は、指標に使用するバッファの数を指定しています。ここでは、5つのバッファが使用されます。バッファは、計算結果を一時的に保持するための領域です。各バッファには、例えば「開始価格」「高値」「安値」「終値」などのデータが保存されます。
#property indicator_plots 1
この命令は、プロットするラインの数を指定します。ここでは1本のラインが描画されます。
#property indicator_label1 “Overbought & Oversold”
この命令は、プロットするラインにラベル(名前)を設定します。ここでは「Overbought & Oversold(買われ過ぎ & 売られ過ぎ)」というラベルが付与され、チャートに表示される際にそのラインが何を表しているかを示します。
#property indicator_type1 DRAW_COLOR_BARS
この命令は、プロットされるラインの表示形式を指定します。D
RAW_COLOR_BARSは、カラーバー形式でラインを表示することを意味しています。バーの色は、条件に応じて変わります。
#property indicator_color1 clrRed, clrBlue
この命令は、プロットされるカラーバーの色を指定します。ここでは、赤(clrRed)と青(clrBlue)の2色が使用されます。これらの色は、買われ過ぎや売られ過ぎの状況に応じて動的に変わります。
#property indicator_style1 STYLE_SOLID
この命令は、プロットされるラインのスタイルを指定します。STYLE_SOLIDは、実線で表示されることを意味しています。他に、点線なども指定可能ですが、ここでは実線が使用されています。
#property indicator_width1 2
この命令は、ラインの幅を指定します。ここでは2ピクセル(デジタル画像を構成する最小の単位)の幅でラインが描画されるよう設定されています。
コード解説2:グローバル領域部分
//--- データ読み込みのパラメータ
input string InpFileName="RSI.csv"; // ファイル名を指定(デフォルトはRSI.csv)
input string InpDirectoryName="Data"; // ディレクトリ名を指定(デフォルトはData)
//--- 指標に使用するバッファ
double open_buff[]; // 開始価格用バッファ
double high_buff[]; // 高値価格用バッファ
double low_buff[]; // 安値価格用バッファ
double close_buff[]; // 終値価格用バッファ
double color_buff[]; // カラーインデックス用バッファ
//--- 買われ過ぎを示す変数
int ovb_ind=0; // 買われ過ぎのインデックス
int ovb_size=0; // 買われ過ぎのサイズ
datetime ovb_time[]; // 買われ過ぎの時間を格納する配列
//--- 売られ過ぎを示す変数
int ovs_ind=0; // 売られ過ぎのインデックス
int ovs_size=0; // 売られ過ぎのサイズ
datetime ovs_time[]; // 売られ過ぎの時間を格納する配列
このセクションでは、カスタム指標に使用されるグローバル変数が定義されています。これらの変数は、指標全体で利用され、主にデータの保存や処理に使用されます。以下、各変数の役割について説明します。
input string InpFileName=”RSI.csv”
この命令は、外部入力用の変数としてファイル名を指定しています。デフォルト値は「RSI.csv」で、カスタム指標が参照するファイルの名前です。ユーザーはこの変数を通じて、ファイル名を変更できます。
input string InpDirectoryName=”Data”
この命令も外部入力用の変数で、ファイルが保存されているディレクトリ名を指定しています。デフォルト値は「Data」です。ユーザーはこのディレクトリ名を変更して、別の場所からファイルを読み込むことが可能です。
バッファに使用する変数
バッファは、指標のデータを一時的に保存するために使用されます。各バッファには異なるデータが格納され、描画や計算に使用されます。
- double open_buff[]
開始価格(オープンプライス)を保存するバッファです。この配列は、チャート上での各バーの開始価格を保持します。 - double high_buff[]
高値を保存するバッファです。各バーの最高価格がこの配列に格納されます。 - double low_buff[]
安値を保存するバッファです。各バーの最低価格がこの配列に格納されます。 - double close_buff[]
終値(クローズプライス)を保存するバッファです。各バーの終了時の価格がこの配列に格納されます。 - double color_buff[]
カラーインデックスを保存するバッファです。バーの色(赤や青など)を指定するために使われ、買われ過ぎや売られ過ぎの状態を視覚的に示します。
買われ過ぎを示す変数
買われ過ぎ状態を管理するための変数です。
- int ovb_ind=0
買われ過ぎ状態のデータを処理する際のインデックスです。このインデックスを用いて、現在処理しているデータの位置を管理します。 - int ovb_size=0
買われ過ぎ状態のデータの総数を表します。この変数は、現在いくつのデータが存在しているかを示します。 - datetime ovb_time[]
買われ過ぎ状態が発生した時間を保存する配列です。各データがいつ発生したのかを記録し、後にその情報を参照します。
売られ過ぎを示す変数
売られ過ぎ状態を管理するための変数です。
- int ovs_ind=0
売られ過ぎ状態のデータを処理する際のインデックスです。現在の処理位置を管理します。 - int ovs_size=0
売られ過ぎ状態のデータの総数を表します。この変数は、売られ過ぎデータがいくつあるかを示します。 - datetime ovs_time[]
売られ過ぎ状態が発生した時間を保存する配列です。売られ過ぎのタイミングを記録し、後で分析や処理に利用されます。
これらの変数は、カスタム指標全体で使用され、買われ過ぎや売られ過ぎの状態を管理し、チャートに反映するために使われます。
コード解説3:OnInit関数部分その1
//+------------------------------------------------------------------+
//| カスタム指標を初期化する関数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- デフォルトの配列サイズ
int ovb_def_size=100; // 買われ過ぎ配列の初期サイズ
int ovs_def_size=100; // 売られ過ぎ配列の初期サイズ
//--- 配列のサイズを指定したデフォルトサイズに変更
ArrayResize(ovb_time,ovb_def_size); // 買われ過ぎ時間配列のリサイズ
ArrayResize(ovs_time,ovs_def_size); // 売られ過ぎ時間配列のリサイズ
//--- ファイルを開く
ResetLastError(); // エラーコードをリセット
int file_handle=FileOpen(InpDirectoryName+"//"+InpFileName,FILE_READ|FILE_CSV|FILE_ANSI); // ファイルをCSVモードで開く
OnInit関数は、カスタム指標が初めて実行される際に呼び出される初期化関数です。この関数では、配列の初期設定やファイルの読み込みなど、指標が正しく動作するための準備が行われます。以下に、各部分の詳細を解説します。
デフォルトの配列サイズ設定
まず、買われ過ぎ状態と売られ過ぎ状態を保存する配列の初期サイズを設定しています。ovb_def_sizeは買われ過ぎのデータを保存する配列の初期サイズ、ovs_def_sizeは売られ過ぎのデータ用のサイズです。それぞれ100個のデータを保存できるよう初期値が設定されています。この値は後にデータ量に応じて拡張されることがあります。
配列のサイズを指定したデフォルトサイズに変更
次に、ArrayResize関数を使って、デフォルトサイズに合わせて配列のサイズを変更しています。ここでリサイズされる配列は、買われ過ぎや売られ過ぎの時間を保存するためのもので、指定した数のデータを保持できるようにメモリが確保されます。これにより、データが増加しても適切に保存・処理ができるようになります。
ファイルを開く
その後、ファイルの読み込み準備が行われています。最初にResetLastError関数を使って、前回のエラー情報をクリアし、新たなエラー発生時に正確なエラーメッセージを取得できるようにしています。
次にFileOpen関数を使用して、指定されたディレクトリにあるファイルを開きます。ここでは、InpDirectoryNameで指定されたフォルダ内のInpFileNameというCSVファイルを、読み取り専用モードで開いています。ファイルが正しく開かれた場合、ファイルハンドルが返され、後の処理で使用されます。
コード解説4:OnInit関数部分その2
if(file_handle!=INVALID_HANDLE) // ファイルが正常に開けた場合
{
//--- ファイルが開けたことをログに出力
PrintFormat("%s file is available for reading",InpFileName);
PrintFormat("File path: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
double value; // ファイルから読み取る値用の変数
//--- ファイルからデータを読み取る
while(!FileIsEnding(file_handle)) // ファイルの終端に達するまで読み込む
{
//--- ファイルから数値を読み込む
value=FileReadNumber(file_handle);
//--- 読み取った値に応じて処理を行う
if(value>=70) // 値が70以上なら買われ過ぎと判定
ReadData(file_handle,ovb_time,ovb_size,ovb_def_size); // 買われ過ぎのデータを読み取る
else // 70未満なら売られ過ぎと判定
ReadData(file_handle,ovs_time,ovs_size,ovs_def_size); // 売られ過ぎのデータを読み取る
}
//--- ファイルを閉じる
FileClose(file_handle); // ファイルハンドルを閉じる
PrintFormat("Data is written, %s file is closed",InpFileName); // ログに書き込み完了を表示
}
このセクションでは、開いたファイルを正常に読み取り、データを処理するためのコードが記述されています。ファイルの中身を一行ずつ読み込み、その値に応じて買われ過ぎか売られ過ぎかを判断し、それぞれのデータを適切な配列に格納します。
ファイルの正常なオープンを確認
ファイルが正常に開かれたかどうかを確認しています。FileOpen関数で取得したファイルハンドルが無効でない場合に、データ読み取り処理が行われます。無効な場合(INVALID_HANDLE)のときは、エラーメッセージを表示します。
ログへのファイル読み込み準備の出力
ファイルが正常に開かれたことを確認した後、そのファイル名とファイルパスをエキスパートログに出力します。これにより、ユーザーが正しいファイルを読み込んでいるかを確認できます。
ファイルからデータの読み取りと処理
ファイルの終端に達するまでデータを読み取るためのループを実行しています。FileIsEnding関数を使い、ファイルの終わりまで繰り返し処理を行います。
値の読み取りと条件分岐
この部分では、ファイルから数値を一つ読み取り、その値を変数に格納します。読み取った数値に応じて、そのデータが買われ過ぎか売られ過ぎかを判定します。
買われ過ぎと売られ過ぎの判定
数値が70以上の場合は買われ過ぎと判定され、対応する配列にデータが格納されます。70未満の場合は売られ過ぎと判断され、別の配列にデータが保存されます。
ファイルのクローズ
ファイルの読み込みが完了した後、ファイルハンドルを閉じ、ログにファイルが正常に閉じられたことを表示します。この処理によって、ファイルが適切に処理され、リソースが解放されます。
コード解説5:OnInit関数部分その3
else // ファイルが開けなかった場合
{
//--- エラーメッセージを表示
PrintFormat("Failed to open %s file, Error code = %d",InpFileName,GetLastError());
return(INIT_FAILED); // 初期化失敗を返す
}
//--- バッファをインジケータに割り当てる
SetIndexBuffer(0,open_buff,INDICATOR_DATA); // 開始価格バッファをインジケータにセット
SetIndexBuffer(1,high_buff,INDICATOR_DATA); // 高値価格バッファをインジケータにセット
SetIndexBuffer(2,low_buff,INDICATOR_DATA); // 安値価格バッファをインジケータにセット
SetIndexBuffer(3,close_buff,INDICATOR_DATA); // 終値価格バッファをインジケータにセット
SetIndexBuffer(4,color_buff,INDICATOR_COLOR_INDEX); // カラーインデックスバッファをインジケータにセット
//--- チャートに表示されない値を設定
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); // 空の値を設定して表示を調整
return(INIT_SUCCEEDED); // 初期化成功を返す
}
このセクションでは、ファイルが開けなかった場合のエラーハンドリングと、インジケータに使用するバッファの設定が行われています。また、最後に初期化処理が成功したかどうかを返す処理が含まれています。
ファイルが開けなかった場合の処理
ファイルが正常に開けなかった場合に実行される処理です。PrintFormat関数を使ってエラーメッセージをエキスパートログに出力します。このメッセージには、開けなかったファイル名とエラーコードが含まれます。エラーが発生した場合には、初期化が失敗したことを示すINIT_FAILEDが返され、プログラムが終了します。
バッファをインジケータに割り当てる
SetIndexBuffer関数を使って、定義されたバッファをインジケータに割り当てています。バッファは、カスタムインジケータの計算結果を保持し、それをチャート上に描画するためのデータを保存する役割を果たします。
- open_buff: 開始価格(オープンプライス)を保存するバッファです。
- high_buff: 高値を保存するバッファです。
- low_buff: 安値を保存するバッファです。
- close_buff: 終値(クローズプライス)を保存するバッファです。
- color_buff: バーのカラーインデックスを保存するバッファです。このバッファにより、チャート上のバーの色を動的に変えることができます。
チャートに表示されない値を設定
PlotIndexSetDouble関数を使用して、空の値を設定します。これにより、インジケータに描画される値の表示を制御します。ここではPLOT_EMPTY_VALUEを設定することで、必要に応じて特定の値を非表示にしています。
初期化の成功を返す
初期化が正常に完了した場合、INIT_SUCCEEDEDが返されます。この戻り値は、指標の初期化が正しく行われたことを示し、その後の処理が継続されるようになります。
コード解説6:ReadData関数部分
//+------------------------------------------------------------------+
//| ファイルの文字列データを読み込む関数 |
//+------------------------------------------------------------------+
void ReadData(const int file_handle,datetime &arr[],int &size,int &def_size)
{
bool flag=false; // 1回目の読み取りをスキップするためのフラグ
//--- 行の終わりかファイルの終わりまでデータを読み込む
while(!FileIsLineEnding(file_handle) && !FileIsEnding(file_handle)) // ファイルの終端または行の終端まで読み込む
{
//--- 数値データを読み飛ばして次の位置に移動
if(flag)
FileReadNumber(file_handle); // 次の値を読み飛ばす
//--- 現在の日時を配列に格納
arr[size]=FileReadDatetime(file_handle); // 読み取った日時を配列に保存
size++; // サイズを増加
//--- 必要に応じて配列のサイズを拡張
if(size==def_size) // サイズがデフォルトサイズに達した場合
{
def_size+=100; // デフォルトサイズを100増加
ArrayResize(arr,def_size); // 配列サイズをリサイズ
}
flag=true; // 1回目のループを終了し、次から通常処理を行う
}
}
このセクションでは、カスタム指標がファイルからデータを読み取るためのオリジナル関数であるReadData関数が記述されています。この関数は、指定されたファイルからデータを読み取り、指定された配列にそのデータを格納する役割を果たします。配列が満杯になると、そのサイズを動的に拡張する処理も行っています。
関数の概要
ReadData関数は、ファイルハンドルと日時データを保存する配列を引数として受け取り、ファイルから読み取ったデータをこの配列に保存します。行の終端やファイルの終端に達するまでデータを読み込みます。
フラグの初期化
最初に、フラグを初期化しています。このフラグは、最初のデータ読み取りをスキップするために使われます。最初のループでは、読み飛ばすべき数値データがないため、フラグをfalseに設定しておきます。
行の終端またはファイルの終端までデータを読み込む
ファイルの終端または行の終端に達するまで、データを読み取る処理を繰り返します。FileIsLineEnding関数とFileIsEnding関数を使って、どちらかの終端に到達した時点でループを終了します。
数値データをスキップ
フラグがtrueに設定されている場合、ファイルから次の数値を読み飛ばして、位置を進めます。これは、複数のデータ項目がファイルに並んでいる場合に、それらをスキップするために行います。
日時データを配列に格納
現在のファイルから読み取った日時データを配列に格納します。日時データが格納されるたびに、配列のサイズを1つ増やしていきます。
配列のサイズを動的に拡張
配列がデフォルトのサイズに達した場合、さらに大きなサイズに拡張します。ここでは、デフォルトのサイズを100増やし、ArrayResize関数を使ってメモリを再確保しています。これにより、大量のデータを効率的に処理できます。
フラグの更新
最初のループが終了した後、フラグをtrueに設定し、次のループからは通常のデータ処理が行われます。
コード解説7: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(time,false); // time配列を時系列ではなく設定
ArraySetAsSeries(open,false); // open配列を時系列ではなく設定
ArraySetAsSeries(high,false); // high配列を時系列ではなく設定
ArraySetAsSeries(low,false); // low配列を時系列ではなく設定
ArraySetAsSeries(close,false); // close配列を時系列ではなく設定
OnCalculate関数は、カスタム指標の計算を行うためのメイン関数です。チャート上に表示されるデータを計算し、各種バッファに格納します。この部分では、データを時系列として扱うかどうかの設定が行われています。
配列を時系列に設定
ここでは、複数の配列が「時系列に設定されているかどうか」を指定しています。ArraySetAsSeries関数を使って、各配列が時系列順(最新のデータが配列の最後に来る)で並べられるか、逆時系列(最新のデータが配列の最初に来る)で並べられるかを設定しています。
具体的には、falseを指定することで、配列が時系列ではない(つまり、最新のデータが配列の最初に来ない)ように設定されています。これにより、データの処理や計算が配列の順序に依存しない形で行われます。
各配列の役割
- time配列
各バー(チャート上のローソク足)の日時データを格納します。 - open配列
各バーの開始価格(オープン価格)を格納します。 - high配列
各バーの最高価格(高値)を格納します。 - low配列
各バーの最低価格(安値)を格納します。 - close配列
各バーの終了価格(クローズ価格)を格納します。
これらの配列は、指標の計算に使用され、チャート上に描画される際の基本データとなります。
コード解説8:OnCalculate関数その2
//--- 処理されていないバーのループ
for(int i=prev_calculated;i<rates_total;i++) // 前回の計算からまだ処理していないバーを処理
{
//--- バッファの初期化
open_buff[i]=0; // 開始価格バッファを初期化
high_buff[i]=0; // 高値価格バッファを初期化
low_buff[i]=0; // 安値価格バッファを初期化
close_buff[i]=0; // 終値価格バッファを初期化
color_buff[i]=0; // カラーバッファを初期化
このセクションでは、まだ処理されていないバー(ローソク足)に対して、カスタム指標の計算を行うループの開始部分が記述されています。前回の計算から新たに追加されたバーに対してのみ処理が行われ、各バッファの初期化が行われます。
処理されていないバーのループ
前回の計算時点から新たに追加されたバーを処理しています。prev_calculatedは前回までに処理されたバーの数を示し、rates_totalは現在のバーの総数を示しています。ループは、前回計算されていないバーのみを対象にします。これにより、無駄な再計算を防ぎ、効率的な処理が行われます。
バッファの初期化
各バッファを0で初期化しています。これは、現在処理しているバーのデータをクリアし、新しいデータを格納する準備をするためです。
- open_buff: 開始価格(オープン価格)のバッファを初期化します。
- high_buff: 高値のバッファを初期化します。
- low_buff: 安値のバッファを初期化します。
- close_buff: 終値(クローズ価格)のバッファを初期化します。
- color_buff: カラーバッファを初期化します。これにより、バーの色が設定される準備が整います。
これらの初期化は、各バーに対して新しいデータを割り当てるために必要なステップです。
コード解説9:OnCalculate関数その3
//--- 買われ過ぎデータがまだ残っているか確認
if(ovb_ind<ovb_size) // 買われ過ぎデータが残っている場合
for(int j=ovb_ind;j<ovb_size;j++) // 買われ過ぎデータをチェック
{
//--- 日付が一致する場合、バーが買われ過ぎ領域にある
if(time[i]==ovb_time[j]) // バーの日時と買われ過ぎの日時が一致する場合
{
open_buff[i]=open[i]; // 開始価格をセット
high_buff[i]=high[i]; // 高値価格をセット
low_buff[i]=low[i]; // 安値価格をセット
close_buff[i]=close[i];// 終値価格をセット
color_buff[i]=0; // 赤(0)をセット
ovb_ind=j+1; // インデックスを更新
break; // ループを抜ける
}
}
このセクションでは、買われ過ぎのデータが残っているかを確認し、該当するバーに対してデータを設定する処理が行われています。各バーの日時データと買われ過ぎデータの日時が一致する場合、そのバーに買われ過ぎのデータを反映します。
買われ過ぎデータの確認
まず、買われ過ぎのデータが残っているかどうかを確認します。ovb_indは現在の買われ過ぎデータのインデックスを示し、ovb_sizeは買われ過ぎデータの総数を示しています。インデックスが総数より小さい場合、まだ処理されていない買われ過ぎデータが残っていることを意味します。
買われ過ぎデータのチェック
買われ過ぎデータを順次チェックするためのループです。このループは、ovb_indからovb_sizeまで繰り返され、買われ過ぎデータを探索します。
日時の一致を確認
各バーの日時(time配列の値)と買われ過ぎデータの日時(ovb_time配列の値)が一致するかを確認します。一致した場合、そのバーが買われ過ぎ領域にあると判定されます。
バーのデータを設定
日時が一致した場合、そのバーに対して各価格データを設定します。
- open_buff: 開始価格をセットします。
- high_buff: 高値をセットします。
- low_buff: 安値をセットします。
- close_buff: 終値をセットします。
- color_buff: 赤(0)をセットし、バーが買われ過ぎ領域であることを示します。
インデックスの更新
処理が終わった後、次の買われ過ぎデータを処理するためにインデックスを更新します。これにより、次回のループでは新たなデータが対象となります。
ループの終了
日時が一致して処理が完了したら、ループを抜けて次のバーの処理に進みます。
コード解説10:OnCalculate関数その4
//--- 売られ過ぎデータがまだ残っているか確認
if(ovs_ind<ovs_size) // 売られ過ぎデータが残っている場合
for(int j=ovs_ind;j<ovs_size;j++) // 売られ過ぎデータをチェック
{
//--- 日付が一致する場合、バーが売られ過ぎ領域にある
if(time[i]==ovs_time[j]) // バーの日時と売られ過ぎの日時が一致する場合
{
open_buff[i]=open[i]; // 開始価格をセット
high_buff[i]=high[i]; // 高値価格をセット
low_buff[i]=low[i]; // 安値価格をセット
close_buff[i]=close[i];// 終値価格をセット
color_buff[i]=1; // 青(1)をセット
ovs_ind=j+1; // インデックスを更新
break; // ループを抜ける
}
}
}
return(rates_total); // 次回の計算に備えて現在のバー数を返す
}
このセクションでは、売られ過ぎのデータが残っているかを確認し、該当するバーに対してデータを設定する処理が行われています。買われ過ぎデータを処理したのと同様に、各バーの日時データと売られ過ぎデータの日時が一致する場合、そのバーに売られ過ぎのデータを反映します。
売られ過ぎデータの確認
売られ過ぎのデータが残っているかどうかを確認します。ovs_indは現在の売られ過ぎデータのインデックスを示し、ovs_sizeは売られ過ぎデータの総数を示しています。インデックスが総数より小さい場合、まだ処理されていない売られ過ぎデータが残っていることを意味します。
売られ過ぎデータのチェック
売られ過ぎデータを順次チェックするためのループです。このループは、ovs_indからovs_sizeまで繰り返され、売られ過ぎデータを探索します。
日時の一致を確認
各バーの日時(time配列の値)と売られ過ぎデータの日時(ovs_time配列の値)が一致するかを確認します。一致した場合、そのバーが売られ過ぎ領域にあると判定されます。
バーのデータを設定
日時が一致した場合、そのバーに対して各価格データを設定します。
- open_buff: 開始価格をセットします。
- high_buff: 高値をセットします。
- low_buff: 安値をセットします。
- close_buff: 終値をセットします。
- color_buff: 青(1)をセットし、バーが売られ過ぎ領域であることを示します。
インデックスの更新
処理が終わった後、次の売られ過ぎデータを処理するためにインデックスを更新します。これにより、次回のループでは新たなデータが対象となります。
ループの終了
日時が一致して処理が完了したら、ループを抜けて次のバーの処理に進みます。
関数の終了
処理が全て完了すると、rates_total(現在のバーの総数)を返し、次回のOnCalculate関数呼び出し時に前回までに処理されたバーの情報が正しく引き継がれます。
コード解説11:OnChartEvent関数
OnChartEvent関数は、チャート上で発生するイベントを処理するために使用されるイベントハンドラーです。この関数は、ユーザーがチャートを操作したり、イベントが発生した際に呼び出され、そのイベントに応じた処理を行います。ここでは、チャートのスケールに応じてラインの幅を調整する処理が行われています。
OnChartEvent関数の引数
- id
イベントの識別子です。どのイベントが発生したかを特定するために使用されます。 - lparam
イベントのパラメータとして使用されるlong型の変数です。 - dparam
イベントのパラメータとして使用されるdouble型の変数です。 - sparam
イベントのパラメータとして使用されるstring型の変数です。
チャートのスケールに応じた処理
チャートのスケールが変更された場合に、ラインの幅を調整します。
- ChartGetInteger(0,CHART_SCALE)
この関数は、現在のチャートスケールの値を取得します。0は現在のチャートIDを意味し、CHART_SCALEはスケールに関する情報を取得するための識別子です。 - if(ChartGetInteger(0,CHART_SCALE)>3)
チャートスケールが3以上の場合、ラインの幅を2に設定します。スケールが大きい場合、バーの表示が小さくなるため、ライン幅を太くすることで視認性を高めます。 - else
チャートスケールが3未満の場合、ラインの幅を1に設定します。スケールが小さい(バーが大きく表示される)場合、ラインを細く設定することで、過剰に目立たないように調整します。
このように、チャートのスケールに応じて自動的にラインの幅が調整されることで、ユーザーが異なるズームレベルでも視覚的にわかりやすい表示が提供されます。