iATR関数は、ATR(Average True Range=平均的な値幅)の値をMQL5プログラムから取得する関数です。ATRは「その相場がいま1本でどれくらい動いているか」をボラティリティとして数値化する指標で、買い/売りのサインそのものではなく、SL・TPの幅、ロットの大きさ、トレールの追従幅を相場に合わせて自動調整する“物差し”として使います。この記事では、iATRの構文と「ハンドル+CopyBufferの2段階」、そしてコピーしてすぐ動く4つのサンプル(ATRの取得・ATRでSL/TPを決める・ATRでロットを逆算・ATRトレーリング)を丁寧に解説します。
iATR(ATR)とは
ATRは、各足の「真の値幅(前日終値とのギャップも含めた高安幅)」を一定期間で平均した指標です。値が大きいほど荒い相場、小さいほど穏やかな相場を表します。重要なのは、ATRは方向(上がる/下がる)を示さないこと。「どれだけ動くか」だけを測るので、トレンド系・逆張り系のサインと組み合わせ、リスク管理の部品として使うのが王道です。MQL5では iATR() でこの値を取得します。
MQL5のインジケーターは「①
OnInit() でハンドルを作る → ② OnTick() で CopyBuffer() により値を取り出す」の2段階です(詳しくは iMAの記事 を参照)。iATRも同じ作法で、バッファ番号は 0 の1本だけです。
iATR() の構文と引数
int iATR(
string symbol, // 通貨ペア(_Symbol で現在のペア)
ENUM_TIMEFRAMES period, // 時間足(PERIOD_CURRENT 等)
int ma_period // 期間(一般的に 14)
);
戻り値はハンドル(整数のID)です。RSIやMAと違い、適用価格の引数はありません(高安を使うため)。取り出したATRの値は「価格の値幅」である点に注意してください(後述)。
サンプル①:現在のATRを取得して表示する
ATR(14) の現在値をチャート左上に表示します。ATRは価格の値幅なので、pips換算もあわせて出してみます。
コピペOK
int atrHandle = INVALID_HANDLE;
int OnInit()
{
// ① ハンドルを1回だけ作る(期間14)
atrHandle = iATR(_Symbol, PERIOD_CURRENT, 14);
if(atrHandle == INVALID_HANDLE)
{
Print("iATRハンドルの作成に失敗: ", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
void OnTick()
{
double atr[];
ArraySetAsSeries(atr, true); // [0]を最新足にそろえる
if(CopyBuffer(atrHandle, 0, 0, 2, atr) < 2) return;
double atrPrice = atr[0]; // 値幅(価格)
double atrPips = atrPrice / _Point / 10; // pips換算(5/3桁口座の目安)
Comment("ATR(14) = ", DoubleToString(atrPrice, _Digits),
" (約 ", DoubleToString(atrPips, 1), " pips)");
}
void OnDeinit(const int reason)
{
IndicatorRelease(atrHandle); // 後始末
}
多くのFX口座は「1pip = 10 ポイント」(5桁・3桁表示)なので
_Point / 10 で割ります。一方、ゴールドのような銘柄では「pips」の定義がブローカーで異なります。迷ったらATRは“価格の値幅”のままSLやロット計算に使うのが安全です。
サンプル②:ATRでSL・TPの幅を決めて発注する
「いつも固定で20pips」ではなく、ATR × 倍率でSL/TPを決めると、荒い相場では広く・穏やかな相場では狭く、自動で適応します。確定足のATRを使います。
コピペOK(デモ口座で動作確認用)
#include <Trade\Trade.mqh>
CTrade trade;
input double InpLot = 0.10;
input double InpSlMult = 1.5; // SL = ATR × 1.5
input double InpTpMult = 2.0; // TP = ATR × 2.0
void OpenBuyWithAtrStops()
{
double atr[];
ArraySetAsSeries(atr, true);
if(CopyBuffer(atrHandle, 0, 0, 2, atr) < 2) return;
double atrVal = atr[1]; // 確定足のATR(価格の値幅)
double slDist = atrVal * InpSlMult;
double tpDist = atrVal * InpTpMult;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = NormalizeDouble(ask - slDist, _Digits);
double tp = NormalizeDouble(ask + tpDist, _Digits);
trade.Buy(InpLot, _Symbol, 0.0, sl, tp); // ATR基準のSL/TP付きで買い
}
サンプル③:ATRからロットを逆算する(リスク%固定)
SL幅をATRで決めるなら、「1トレードで失う額を資金の◯%に固定」するロット計算と相性が抜群です。SLが広い相場では自動でロットが小さくなり、損失額が一定に保たれます。
コピペOK
input double InpRiskPct = 1.0; // 1トレードのリスク(残高に対する%)
input double InpSlMult = 1.5; // SL = ATR × 倍率
double NormalizeLot(double lot)
{
double mn = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double mx = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double st = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(st > 0) lot = MathRound(lot / st) * st;
if(lot < mn) lot = mn;
if(lot > mx) lot = mx;
return(lot);
}
double AtrRiskLot()
{
double atr[];
ArraySetAsSeries(atr, true);
if(CopyBuffer(atrHandle, 0, 0, 2, atr) < 2) return(0.0);
double slDist = atr[1] * InpSlMult; // SL幅(価格)
double tickVal = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSz = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
if(slDist <= 0.0 || tickVal <= 0.0 || tickSz <= 0.0) return(0.0);
double riskAmt = AccountInfoDouble(ACCOUNT_BALANCE) * InpRiskPct / 100.0;
double lossPerLot = (slDist / tickSz) * tickVal; // 1ロットあたりの損失額
return NormalizeLot(riskAmt / lossPerLot);
}
サンプル④:ATRトレーリングストップ
保有中の買いポジションのSLを、現在値 − ATR × 倍率で追いかけます。値動きが荒くなればトレール幅も自動で広がり、ノイズで切られにくくなります(チャンデリア・ストップの考え方)。
コピペOK(デモ口座で動作確認用)
input double InpTrailMult = 2.0; // トレール幅 = ATR × 2.0
void AtrTrailing()
{
double atr[];
ArraySetAsSeries(atr, true);
if(CopyBuffer(atrHandle, 0, 0, 2, atr) < 2) return;
double dist = atr[0] * InpTrailMult;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY) continue;
double curSL = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double newSL = NormalizeDouble(bid - dist, _Digits);
// 利益方向にだけ動かす(SLを下げ戻さない)
if(newSL > curSL && newSL < bid)
trade.PositionModify(ticket, newSL, tp);
}
}
エントリー条件・スプレッド確認・売りポジション側の処理などは省いています。実運用では、ストップレベル(最小SL距離)の確認や、確定足での更新なども検討してください。まずはデモ口座で動きを確認しましょう。
ATRを使うときの注意・落とし穴
ATRが上がっても、それは「動きが激しくなった」だけで、上昇か下落かは分かりません。エントリーの向きは iMA や iRSI などサイン系で決め、ATRはあくまで幅・リスクの調整に使うのが正しい役割分担です。
取り出した値はそのまま価格差です。SL価格=
ask − ATR×倍率 のように価格にそのまま足し引きできます。pipsや損益額に直す時だけ、口座の桁数・ティック価値を使って換算してください。
ハンドルは
OnInit() で1回だけ/CopyBuffer() の戻り値を必ずチェック/ArraySetAsSeries(配列, true) を忘れない。これはどのインジでも共通です。
まとめ
iATR()はATRのハンドルを返す。値はCopyBuffer()で取り出す(バッファ番号0・適用価格の引数なし)- ATRは「どれだけ動くか」だけを測る指標。方向は出さない=サイン系と役割分担する
- 取り出した値は価格の値幅。SL/TPは
価格 ± ATR×倍率でそのまま付けられる - ATRでSL幅を決め、リスク%固定でロットを逆算すると、損失額を一定に保てる(サンプル③)
- トレール幅をATR連動にすると、荒い相場でノイズ切られしにくい(サンプル④)

