MQL5で足データを取得する方法|配列の向きに注意

MQL5で過去のローソク足を取るには CopyRates を使います。受け取る配列は MqlRates 型です。

ここで多くの人が一度つまずきます。受け取った配列の index 0 は、既定では「最新の足」ではなく「いちばん古い足」です。MQL4の感覚のまま書くと、値は取れているのに時系列が逆になります。

(確認環境:MetaTrader 5 / Windows 11)

最小のコード

MqlRates rates[];
ArraySetAsSeries(rates, true);          // index 0 を最新にする

int copied = CopyRates(_Symbol, _Period, 0, 100, rates);
if(copied <= 0)
  {
   Print("取得失敗 err=", GetLastError());
   return;
  }

Print("最新の終値 ", rates[0].close);
Print("1本前の高値 ", rates[1].high);

CopyRates はコピーできた本数を返し、失敗すると −1 を返します。戻り値を見ずに配列を参照すると、中身が空のまま進みます。

MqlRates に入っているもの

メンバ 内容
time 足の開始時刻(サーバー時刻)
open / high / low / close 4本値
tick_volume ティック数
spread スプレッド(ポイント)
real_volume 実ボリューム(FXでは0のことが多い)

1行目の time はサーバー時刻です。日本時間で判定したい場合は自分でずらします。違いはMT5の時刻がずれる理由にまとめています。

🔴 配列の向きは「並べ替え」ではない

ArraySetAsSeries の説明としてよくあるのが「配列を新しい順に並べ替える」ですが、実際には要素は動いていません。

MQL5公式リファレンスの CopyRates の項にはこう書かれています。

対象配列の as_series が true か false かにかかわらず、最も古い要素が、配列に割り当てられた物理メモリの先頭に置かれる。

つまりデータの並びは常に「古い順」で、ArraySetAsSeries が変えるのはアクセスする時のインデックスの向きだけです。

設定 index 0 index 1
既定(false) いちばん古い足 その次に古い足
ArraySetAsSeries(arr, true) 最新の足 1本前

MQL4では index 0 が常に最新でした。MQL5では自分で指定しない限りそうなりません。「計算結果がおかしい」「移動平均のクロス判定が逆になる」といった症状は、ここが原因であることが多いです。

設定できない配列がある

公式リファレンスによると、AS_SERIESフラグは多次元配列と静的配列には設定できません。

double a[];        // 動的配列 → 設定できる
double b[100];     // 静的配列 → 🔴 設定できない

宣言時に角括弧の中へサイズを書いた配列は静的配列です。ArraySetAsSeries を呼んでも効きません。必ず動的配列で受け取ってください。

🔴 インジケーターでは −1 が返ることがある

もう1つ、公式リファレンスに明記されている挙動です。

インジケーターから呼んだ場合、履歴の準備ができていなければ即座に −1 を返します。そのうえで、裏で読み込みが開始されます。

EAやスクリプトから呼んだ場合は、タイムアウトまでに用意できた分を返し、次に同じ要求をすればより多く返ります。

起動直後の1回だけ失敗するのはこのためです。対策は単純で、失敗したらその回は何もせず戻ることです。

int copied = CopyRates(_Symbol, _Period, 0, 100, rates);
if(copied < 100)
   return(prev_calculated);   // 次の呼び出しに任せる

ここでエラーを表示して止めてしまうと、本来なら次の呼び出しで取れるものを取り損ねます。値が取れない場合の切り分け全般はMQL5でiCustom・CopyBufferの値が取れない原因にまとめています。

必要な本数だけ取る

毎回1万本コピーするような書き方は、OnTick や OnCalculate の中では重くなります。

  • 判定に使う本数だけ取る — 直近3本で足りるなら3本
  • 足が更新された時だけ取り直す — 同じ足の中で何度も取らない

取得した値をそのまま検証したい場合は、画面で数えるよりファイルに書き出す方が確実です。方法はMQL5でCSVを出力する方法に、実際にZigZagの値を書き出す例はMT5のZigZagをCSVに出力する方法にまとめました。

高値・安値だけが必要なら、配列を持たずに済む方法もあります。MQL5で高値・安値を探す方法を参照してください。

まとめ

  1. CopyRates はコピーできた本数を返す。失敗は −1。戻り値を必ず見る
  2. 🔴 既定では index 0 がいちばん古い足。MQL4とは逆
  3. 🔴 ArraySetAsSeries は並べ替えではなくインデックスの向きの変更
  4. 静的配列・多次元配列にはAS_SERIESを設定できない
  5. インジケーターでは起動直後に −1 が返る。その回は戻って次に任せる

本記事はMQL5の仕様と実装方法を説明したものであり、特定の売買を推奨するものではありません。仕様はビルドによって変わる可能性があります。投資判断はご自身の責任で行ってください。