MQLのCSV読込の仕様について
MT4やMT5にてCSVを読込ませてなんやかんやさせたい、MQLでCSVを読込ませてみよう。って感じでCSVを読込ませる処理をいれようにもどうすりゃいいのかイマイチ解らん・・・( ^ω^)
って感じになったので、仕様について勉強になった内容を記載しておきます。
Pythonなどはヘッダーを読込んで項目ごとに処理できるんですが、どうもMQLはそこまで器用にはできておらず、原始的な仕様になってますね。
上記URL先でよくよく確認すると実際には書いてあったりするんですが、自分で動かしてみないとピンとこない部分もあり、自分なり解説入れておきます。
CSVファイルの読込まで
実際に読込に使用するCSVレイアウト
今回はサンプルとしてGogojungleのEAトレード結果にあるようなCSVレイアウトを読込することを前提に考えてみます。
ヘッダーは全部で14個ですね。
CSVファイルの読込関数
int fileHandle;
input string csvFile = "test.csv";
fileHandle = FileOpen(csvFile_1, FILE_CSV|FILE_READ,",");
まず上記の様に記述することでFiles配下のCSVファイルにアクセスし、CSVを開くことができます。区切り文字は「,(カンマ)」です。
関数の戻り値を以下ハンドル値として使用します。
で、Pythonとかだとこれでファイルの内容を見に行ったり色々できるんですが、MQLだとあくまでファイルを開いただけです。ここからがちょっと面倒くさいポイントです。
実際にファイルを読込む際には以下の関数を駆使していきます。
(参考:MT4でEA自作しちゃお~)
bool FileReadBool(int handle); //CSV形式ファイルの現在位置から読込み区切りまでの文字列を読み取り、読み取った文字列をbool型データに変換します。
datetime FileReadDatetime(int handle); //CSV形式ファイルから"YYYY.MM.DD HH:MI:SS","YYYY.MM.DD","HH:MI:SS"のいずれかの形式の文字列を読み取り、datetime型データに変換します。
double FileReadDouble(int handle); //現在位置のファイルポインタからdouble値を読み取ります
float FileReadFloat(int handle); //現在位置のファイルポインタからfloat値を読み取ります
int FileReadInteger(int handle); //現在位置のファイルポインタからint,short,char値を読み取ります
long FileReadLong(int handle); //現在位置のファイルポインタからlong値を読み取ります
double FileReadNumber(int handle); //CSV形式ファイルの現在位置から読込み区切りまでの文字列を読み取り、読み取った文字列をdouble型データに変換します。
string FileReadString(int handle); //現在位置のファイルポインタから文字列(string)を読み取ります
色々種類がありますが、結論ヘッダーの各項目ごとに読込用の関数が必要になります。
先ほどのレイアウトの例で言えば、
・約定日時:datetime型
・通貨ペア:string型
・買/売:string型
・レート:double型
・ストップ::string型([-]記号を含むため)
・リミット:string型([-]記号を含むため)
・決済日時::string型([-]記号を含むため)
・決済レート::string型([-]記号を含むため)
・ロット:double型
・手数料:string型([-]記号を含むため)
・税金:string型([-]記号を含むため)
・スワップ:string型([-]記号を含むため)
・結果:string型([-]記号を含むため)
・損益:string型([-]記号を含むため)
こんな感じですかね。特に面倒くさいのはdouble型で良いのかと思いきや、記号が入ってくるからそれを考慮しないといけないとか。迷ったら全部string型で読み込んだ後で編集するとかでも良いと思います。
で、肝心の読込の仕様部分ですが、
1ファイルを丸々読み込んでくれるわけでもなく、1レコードを丸々読み込んでくれるわけでもなく、CSVなのにTEXTファイルを読込むような感覚で処理する必要があります。
コメントで記載の通り、一回の読込で「,(カンマ)」までのデータしか読込みません。1レコードの中の項目ごとに読込が必要になります。なので必要のない項目についても読込しないと次の項目が読み込めないんですね。個人的には滅茶苦茶面倒だと思う要素の1つです。
読込のMQLコードイメージ
int data_cnt;
datetime ENTRY_datetime[];
string SYMBOL[];
string TRADE_TYPE[];
double ENTRY_RATE[];
datetime CLOSE_datetime[];
double CLOSE_RATE[];
double LOTS[];
int PROFITS[];
data_cnt = 0;
while(FileIsEnding(fileHandle) == false)
{
data_cnt++;
//---約定日時
ArrayResize(ENTRY_datetime, data_cnt);
ENTRY_datetime[data_cnt-1] = StrToTime(FileReadString(fileHandle));
//---通貨ペア
ArrayResize(SYMBOL, data_cnt);
SYMBOL[data_cnt-1] = FileReadString(fileHandle);
//---買い/売り
ArrayResize(TRADE_TYPE, data_cnt);
TRADE_TYPE[data_cnt-1] = FileReadString(fileHandle);
//---レート(エントリー)
ArrayResize(ENTRY_RATE, data_cnt);
ENTRY_RATE[data_cnt-1] = StrToDouble(FileReadString(fileHandle));
//---ストップ
FileReadString(fileHandle);
//---リミット
FileReadString(fileHandle);
//---決済日時
ArrayResize(CLOSE_datetime, data_cnt);
CLOSE_datetime[data_cnt-1] = StrToTime(FileReadString(fileHandle));
//---決済レート
ArrayResize(CLOSE_RATE, data_cnt);
CLOSE_RATE[data_cnt-1] = StrToDouble(FileReadString(fileHandle));
//---ロット
ArrayResize(LOTS, data_cnt);
LOTS[data_cnt-1] = StrToDouble(FileReadString(fileHandle));
//---手数料
FileReadString(fileHandle);
//---税金
FileReadString(fileHandle);
//---スワップ
FileReadString(fileHandle);
//---結果
ArrayResize(PROFITS, data_cnt);
PROFITS[data_cnt-1] = StrToInteger(FileReadString(fileHandle));
//---損益
FileReadString(fileHandle);
}
結論から書くとこんな感じですね。
1レコードの項目ごとに読込処理をいれて後はレコードの数分だけLOOP処理させるって感じになります。いちいち使い分けるの面倒になって「FileReadString」で全部同じにしてます。後から型変換させれば良いだけので、コードが汚いのが嫌かどうかの問題なので、この辺は好きにしてください。
処理に必要のない項目については読込処理だけして次行きます。
読込んだ項目に関してはその都度処理させても良いですし、サンプルコードのように配列でデータを一度保存した後に好きに処理することもできます。
今回はこんな感じでCSV読込のサンプルコードを紹介してみました。
ぜひ参考にしてみてください。