【MQL5】FileWriteArray関数の使い方と自動売買実装コード

1. FileWriteArray関数の概要と実務での活用法

FileWriteArrayは、MQL5で配列の内容を一括してバイナリファイルに書き出すための関数です。

実務開発において、この関数は「データの高速な保存」と「バックテスト結果の外部出力」に非常に重宝されます。初心者がよく使うFileWrite関数は、1データずつテキスト形式(CSVなど)で書き込むため、ループ処理が介在すると処理が重くなり、特にTickデータのような膨大な情報を扱う際にはパフォーマンス上のボトル判ネックになりがちです。

一方で、FileWriteArrayはメモリ上の配列をそのままバイナリ形式でファイルへ転送するため、書き込み速度が圧倒的に速いのが特徴です。
実務での具体的な活用シーンは以下の通りです。
EAのステート管理: 構造体配列を保存し、EAの再起動時やMT5の再起動時に前回の取引状態を復元する。
独自インジケーターのバックアップ: 計算負荷の高い指標データを保存しておき、過去チャートの再読み込みを高速化する。
機械学習用データの抽出: 学習に用いる大量の価格データや特徴量を一気に書き出し、Python等の外部環境へ渡す。

バイナリ形式であるため、そのままメモ帳で開いても中身は読めませんが、その分ファイルサイズが小さく、高速な読み書き(FileReadArray)が可能になるというメリットがあります。

2. 構文と戻り値

FileWriteArrayの構文は以下の通りです。

uint  FileWriteArray(
   int          file_handle,    // ファイルハンドル(FileOpenで取得したもの)
   const void&  array[],       // 書き込む配列(すべての数値型、構造体が指定可能)
   int          start=0,       // 書き込みを開始する要素のインデックス
   int          count=WHOLE_ARRAY // 書き込む要素数
   );

パラメーター

  1. file_handle: FileOpen() 関数によって返されたハンドル番号です。
  2. array[]: ファイルに保存したい配列を指定します。数値型(int, double等)だけでなく、文字列を含まない単純な構造体の配列も保存可能です。
  3. start: 書き込みを開始する配列のインデックス番号です。デフォルトは0(最初から)です。
  4. count: 書き込む要素の数です。デフォルトの WHOLE_ARRAY は、配列の最後まで全て書き出すことを意味します。

戻り値

  • 実際にファイルへ書き込まれた要素の数が返されます。
  • 書き込みに失敗した場合は 0 が返ります。エラーの詳細を確認するには GetLastError() を呼び出します。

3. 具体的な使い方・実践サンプルコード

以下のコードは、直近100本のローソク足の情報を構造体配列に格納し、バイナリファイルとして保存する実戦的な例です。

//+------------------------------------------------------------------+
//|                                              SampleFileWrite.mq5 |
//+------------------------------------------------------------------+
#property strict

// 構造体の定義(文字列を含まない単純なもの)
struct CandleData {
   datetime time;
   double   open;
   double   high;
   double   low;
   double   close;
};

void OnStart()
{
   int historyCount = 100;
   CandleData dataArray[];
   ArrayResize(dataArray, historyCount);

   // 1. 保存するデータの準備
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(_Symbol, _Period, 0, historyCount, rates) < 0) {
      Print("データ取得失敗");
      return;
   }

   for(int i=0; i < historyCount; i++) {
      dataArray[i].time  = rates[i].time;
      dataArray[i].open  = rates[i].open;
      dataArray[i].high  = rates[i].high;
      dataArray[i].low   = rates[i].low;
      dataArray[i].close = rates[i].close;
   }

   // 2. ファイルを開く (バイナリ書き込みモード)
   string fileName = "CandleDataBackup.bin";
   int fileHandle = FileOpen(fileName, FILE_WRITE|FILE_BIN);

   if(fileHandle != INVALID_HANDLE) {
      // 3. 配列を一括書き込み
      uint writtenCount = FileWriteArray(fileHandle, dataArray, 0, WHOLE_ARRAY);

      if(writtenCount > 0) {
         PrintFormat("成功: %d 個の要素を %s に書き込みました。", writtenCount, fileName);
      } else {
         Print("書き込み失敗。エラーコード: ", GetLastError());
      }

      // 4. ファイルを閉じる
      FileClose(fileHandle);
   } else {
      Print("ファイルオープン失敗。エラーコード: ", GetLastError());
   }
}

4. 使用上の注意点とよくあるエラー

開発者が陥りやすいミスとして、以下の3点に注意してください。

  1. FILE_BINフラグの必須指定
    FileWriteArrayを使用する場合、FileOpen関数のフラグには必ず FILE_BIN を指定してください。FILE_CSVFILE_TXT を指定すると、バイナリデータの整合性が崩れ、正しく読み書きができなくなります。

  2. 動的配列(文字列)を含む構造体の制限
    構造体の中に string 型(動的配列)が含まれている場合、そのまま FileWriteArray で保存することはできません。string はメモリアドレスを保持しているため、ファイルに保存しても再読み込み時に意味をなさないからです。構造体を保存する場合は、固定長配列(例: char name[64])にするか、数値データのみに限定する必要があります。

  3. 戻り値の確認
    「ファイルが書き込めない」というトラブルの多くは、権限不足やディスク容量不足、あるいは他のプロセスがファイルを開いていることが原因です。必ず writtenCount が意図した数になっているか、戻り値のチェックを実装する癖をつけましょう。

5. 【重要】自動売買における約定スピードと環境の罠

アルゴリズムトレードにおいて、プログラムのコード効率と同じか、それ以上に重要なのが「物理的な実行環境」です。自宅のデスクトップPCやWi-Fi環境でEAを稼働させている場合、MT5が発注指示を出してからブローカーのサーバーに届くまでに、致命的なネットワーク遅延(レイテンシ)が発生しています。この数ミリ秒から数百ミリ秒の遅延は、スリッページを増大させ、バックテストとリアルトレードの結果が乖離する最大の原因となります。

特に秒単位の攻防を繰り広げるスキャルピングや高頻度取引(HFT)に近いロジックでは、自宅環境での運用は「ネットワーク遅延によって利益をブローカーに献上している」と言っても過言ではありません。約定スピードを極限まで高め、安定した24時間の稼働を確保するには、ブローカーのサーバーに近いロケーションに位置する専用のVPS(仮想専用サーバー)が必須です。プロのクオンツエンジニアにとって、物理的な距離の壁を打破するVPSの導入は、手法の最適化以前の「最低限のスタートライン」です。

💡 この記事の内容を実運用で活かすには?

この記事の内容を実運用で活かすには、正しい環境が必要です。
特にVPSを使わないと、このロジックは再現できません。

コメント

タイトルとURLをコピーしました