計算結果をファイルに出力して検証したかったので、CSVファイルを出力する方法を調べました。FileOpen関数、FileWrite関数、FileClose関数を使います。
この記事内のコードで使われているeVLDMI関数
このブログの過去記事にもeVLDMI関数が登場しますが、それとは少し仕様が異なります。
以下のコードに登場するeVLDMI関数は、自分が所属しているチームで活用してもらうために少し内容を修正したものです。修正点は次の2つです。
コード
// CSVファイルを出力するScript // CSVファイルの出力先はMT4の「MQL4 → Files」フォルダ #property copyright "Copyright 2020. PHILOJUAN" #property link "https://uhoho.hatenablog.jp/" #property version "1.00" #property strict void OnStart() { int limit = Bars - 28; double vlValue[]; // VLDMIの値を格納する配列を用意 ArrayResize(vlValue, limit); // 配列の要素数をセット for(int i = 0; i < limit; i++) { vlValue[i] = eVLDMI(NULL , 14, 5, 3, i); } // eVLDMI.csvというファイルをオープン(作成) int fHandle = FileOpen("eVLDMI.csv", FILE_READ | FILE_WRITE | FILE_CSV, ","); //<失敗例> // int fHandle = FileOpen("eVLDMI.csv", FILE_WRITE | FILE_CSV, ","); // FILE_READ を記述しなかったら、CSVファイルの中身が1行だけになった(汗) FileWrite(fHandle, "シフト", "VLDMIの値"); // CSVファイルの見出し行を作成 for(int k = 0; k < limit; k++) // CSVファイルにvlValue配列の中身を出力 { // FileSeek(fHandle, 0, SEEK_END); // 上のFileSeek行は無くても問題なさそうだが、将来ハマった時のヒント // になるかもしれないので残してある。 FileWrite(fHandle, IntegerToString(k) + "本目", vlValue[k]); } // ファイルを閉じる FileClose(fHandle); } //------------------------------------------------------------------ // 某チーム用 eVLDMI関数 //------------------------------------------------------------------ // 引数1 timeframe 時間軸(PERIOD_M5等) // 引数2 base_period 基準期間 // 引数3 M_period 標準偏差を単純平均する期間(1以上の整数値) // 引数4 N_period 標準偏差計算期間 (1以上の整数値) // 引数5 shift バーシフト // // 【自分用eVLDMI関数との相違点】 // // ・引数の順番を変えてある(自分用では、引数3 と 引数4 が逆) // ・VL期間が、基準期間の「2分の1 ~ 2倍」の範囲に収まるようにしてある double eVLDMI(int timeframe, int base_period, int M_period, int N_period, int shift) { // N_period や M_periodが 0 の場合、エラーメッセージを出して終了 // 戻り値は -1 となる if(!N_period || !M_period) { printf("eVLDMI function: Zero Division Error"); Alert("eVLDMI: Error, Zero Division"); return -1.0; } double sd_0 = 0.0; //「shift時点の」終値のN日間標準偏差 double sd_total = 0.0; // 過去 M 日間の標準偏差の合計 double sd_ave = 0.0; // 終値の N 日間標準偏差の M 日単純平均 double res1 = 0.0; // VL期間(int型にキャストする前の値) double res2 = 0.0; // 戻り値 for(int i = shift; i < shift + M_period; i++) { double c_sum = 0.0; // 終値の N 日間合計 // N 日間の終値を合計 for(int j = i; j < i + N_period; j++) { c_sum += iClose(NULL, timeframe, j); } double c_ave = c_sum / N_period; // 終値の N 日間単純平均 double d_sum = 0.0; // (各日の終値 - 平均)の2乗を N 日間分だけ合計 for(int k = i; k < i + N_period; k++) { double diff = iClose(NULL, timeframe, k) - c_ave; d_sum += diff * diff; } // N 日間標準偏差を M 日分だけ合計 sd_total += MathSqrt(d_sum / N_period); // i == shift の時の標準偏差を sd_0 に代入 if(i == shift) sd_0 = sd_total; // shift時点の N 日間標準偏差 } // 終値の N 日間標準偏差の M 日単純平均 sd_ave = sd_total / M_period; // VL期間の計算 if(!sd_0) res1 = base_period; else res1 = base_period * sd_ave / sd_0; // res1 を基準期間(base_period)の「2分の1 ~ 2倍」の範囲に収める if(res1 > base_period * 2) res1 = base_period * 2; if(res1 < base_period / 2.0) res1 = base_period / 2.0; int VL_period = (int)res1; // 小数点以下を切捨てて、VL_period に代入 res2 = iRSI(NULL, timeframe, VL_period, PRICE_CLOSE, shift); return res2; }