MQL4版のiATR関数の記事では、`iATR(symbol, timeframe, period, shift)`を呼ぶだけで、
ATR(平均真の値幅)の値がその場で`double`型として返ってくる、
シンプルな設計を解説しました。
MQL5の`iATR()`は、見た目は似ていますが中身が大きく変わっています。
呼び出しても値そのものは返らず、
代わりに「ハンドル」と呼ばれる整数の識別子が返ってくるだけです。
この記事では、この設計変更が何を意味するのか、
そしてMQL4版から移行するときにつまずきやすいポイントを解説します。
MQL4版との違い: 1回の呼び出しで値が返らない
//MQL4版(直接値が返る) double atr = iATR(NULL, 0, 14, 1); //MQL5版(ハンドルが返るだけ) int atrHandle = iATR(_Symbol, PERIOD_CURRENT, 14);
MQL5の`iATR()`の第3引数までしかなく、
shift(何本前の足か)を指定する引数がありません。
これは仕様が簡素化されたのではなく、
「値を取る」という処理そのものが別の関数に分離されたためです。
実際の値は、このハンドルを使って`CopyBuffer()`で取得します。
double atrBuffer[];
ArraySetAsSeries(atrBuffer, true);
int copied = CopyBuffer(atrHandle, 0, 1, 1, atrBuffer);//1つ前の確定足を1本取得
if(copied <= 0)
{
Print("CopyBufferに失敗しました。エラーコード=", GetLastError());
return;
}
double atr = atrBuffer[0];
MQL4版の記事で解説した「shift=0は形成中の足なので危険、
shift=1(1つ前の確定足)を使うのが安全」という注意点は、
`CopyBuffer()`の第3引数(start_pos)にそのまま引き継がれています。
なぜ2段階に分離したのか
MQL5がこの設計を採用しているのは、`iATR()`に限った話ではなく、
`iMA()`・`iRSI()`・`iADX()`・`iIchimoku()`など、
MQL5のテクニカル指標関数はすべて同じ「ハンドル+CopyBuffer」
方式です(iCustomの記事やiRSIの記事でも同じ設計が出てきます)。
ハンドルは通常`OnInit()`で1回だけ作成し、
以降は`OnCalculate()`や`OnTick()`の中で使い回します。
これにより、指標の計算処理自体は内部で1回だけ実行され、
複数の関数から同じ計算結果を共有できるようになっています。
MQL4のように毎回`iATR()`を呼ぶたびに計算し直すのではなく、
「計算する準備をする(ハンドル作成)」と「計算済みの値を取り出す(CopyBuffer)」
を分けることで、同じ指標を何度も参照する場面での効率が上がる設計になっています。
応用: iADX・iIchimoku(MQL5版)も同じ考え方
MQL5関数ギャップの一覧には、
`iADX`・`iIchimoku`のMQL5版も挙がっていますが、
この2つも`iATR()`と全く同じ「ハンドル+CopyBuffer」
の型に当てはまります。
//iADXのハンドルを作る(バッファ0=ADX本線、1=+DI、2=-DI) int adxHandle = iADX(_Symbol, PERIOD_CURRENT, 14); //iIchimokuのハンドルを作る(バッファ0=転換線、1=基準線、2=先行スパンA、3=先行スパンB、4=遅行スパン) int ichimokuHandle = iIchimoku(_Symbol, PERIOD_CURRENT, 9, 26, 52);
値の取り出し方は、この記事で解説した`iATR()`と同じく、
それぞれのハンドルと欲しいバッファ番号を指定して、
`CopyBuffer()`を呼ぶだけです。
`iATR()`の使い方さえ理解すれば、
MQL5のテクニカル指標関数はほぼすべて同じパターンの応用で読み解けます。
実際に動くコード全体
現在のATRと、そこから計算した推奨損切りラインをチャート左上に表示する、
実際にMetaEditorでコンパイルできるインジケーターです。
//+------------------------------------------------------------------+
//| ATRStopDemoMql5.mq5 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property indicator_chart_window
#property indicator_plots 0
input int ATRPeriod = 14;//ATR計算期間
input double ATRMultiplier = 1.5;//ATRに掛ける倍率
int atrHandle = INVALID_HANDLE;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
atrHandle = iATR(_Symbol, PERIOD_CURRENT, ATRPeriod);
if(atrHandle == INVALID_HANDLE)
{
Print("iATRのハンドル作成に失敗しました。エラーコード=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(atrHandle != INVALID_HANDLE)
IndicatorRelease(atrHandle);//使い終わったハンドルは必ず解放する
Comment("");
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
double atrBuffer[];
ArraySetAsSeries(atrBuffer, true);
int copied = CopyBuffer(atrHandle, 0, 1, 1, atrBuffer);//1つ前の確定足のATR
if(copied <= 0)
{
Comment("ATRの取得に失敗しました。エラーコード=", GetLastError());
return(rates_total);
}
double atr = atrBuffer[0];
double slDistance = atr * ATRMultiplier;
MqlTick lastTick;
if(!SymbolInfoTick(_Symbol, lastTick))
{
Comment("最新気配の取得に失敗しました。エラーコード=", GetLastError());
return(rates_total);
}
double buySL = lastTick.bid - slDistance;
double sellSL = lastTick.ask + slDistance;
Comment(
"ATR(", ATRPeriod, ")= ", DoubleToString(atr, _Digits), "\n",
"推奨損切り幅(ATR×", DoubleToString(ATRMultiplier, 1), ")= ", DoubleToString(slDistance, _Digits), "\n",
"買いなら損切りライン: ", DoubleToString(buySL, _Digits), "\n",
"売りなら損切りライン: ", DoubleToString(sellSL, _Digits)
);
return(rates_total);
}
//+------------------------------------------------------------------+
MetaEditorで実際に動かす手順
- MetaTrader 5の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
- 「ファイル」→「新規作成」→「インジケーター」を選び、名前を「ATRStopDemoMql5」にして作成する(中身は空のテンプレートで構いません)
- テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
- F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- チャートへドラッグ&ドロップし、チャート左上にATRの値と推奨損切りラインが表示されれば成功です
コピペしてコンパイルが通らない・値が表示されないときに確認すること
- `OnInit()`の時点で失敗する: `iATR()`の第2引数は`ENUM_TIMEFRAMES`型(`PERIOD_CURRENT`等)であり、MQL4のように`0`という整数を渡すとコンパイルエラーになる
- `CopyBuffer()`が常に失敗する: チャートを開いた直後で、指定期間分の過去データがまだ読み込まれていない可能性がある。しばらく待つか、通貨ペアの履歴データをダウンロードし直す
- 値がMQL4版と微妙に違う: MQL5とMQL4ではATRの内部計算(初期値の扱い等)が完全に同一とは限らないため、多少の誤差が出ることがある。大きく乖離する場合は`ATRPeriod`の指定間違いを疑う
- インジケーターを外しても次回起動時にエラーが出る: `OnDeinit()`で`IndicatorRelease()`を呼び忘れていないか確認する。ハンドルを解放しないまま繰り返しアタッチすると、無駄なハンドルが積み上がる原因になる
まとめ
MQL5の`iATR()`は、MQL4のように直接値を返す関数ではなく、
ハンドルを作成したうえで`CopyBuffer()`から
値を取り出す2段階方式に変わりました。
この設計は`iATR()`に限らず、
`iMA()`・`iRSI()`・`iADX()`・`iIchimoku()`など、
MQL5のテクニカル指標関数に共通するパターンです。
ハンドルの作成は`OnInit()`で1回だけ、
値の取得は`OnCalculate()`や`OnTick()`の中で、
`CopyBuffer()`、
という型を覚えてしまえば、他の指標関数にもそのまま応用できます。
コメント