EAのストップロスをATRで自動設定する方法|固定pipsより賢い損切り設計
Photo by Maxim Hopman on Unsplash
最終更新: 2026年6月
ATRでストップロスを設定する方法は?
MQL4では
iATR(NULL, 0, 14, 1)で前バーのATR値(Point単位)を取得し、ATR × 倍率(一般的には1.5〜2.0)で損切り幅を算出する。ロングならAsk - (ATR × 倍率)がストップロス価格になる。最小ストップ距離チェックとゼロ値ガード節を必ず実装すること。詳細な実装コードは「MQL4でATRベース損切りを実装する」セクションを参照。
固定50pipsで損切りを設定していた時期、筆者は繰り返し同じ壁にぶつかっていた。米雇用統計の発表後や、ロンドン・ニューヨーク時間のオーバーラップ帯では、エントリー直後に50pipsの損切りラインに即到達してポジションが刈られる。数分後に価格は元の方向に戻っているにも関わらず、自分のポジションだけが消えているという経験だ。
問題は損切りの「位置」ではなく、損切りの「設定方法」にあった。市場のボラティリティは一定ではない。静かなアジア時間の夜間に設定した50pipsは適切でも、経済指標後の欧米時間に同じ50pipsを使えば「ノイズの射程圏内」に損切りを置いていることになる。
ATRベースの損切り設計はこの問題に対する統計的な回答だ。「今この瞬間の相場が1バーあたりどれだけ動くか」を定量化し、その値動きの外側に損切りを自動配置する。固定pipsとの決定的な違いは、損切り幅が「相場の状態」を反映する点にある。
固定pips損切りの限界とATRベース損切りのメリット
ボラティリティが高い日に固定損切りがすぐ刈られる問題
「損切りが多すぎる」という悩みを持つEA開発者と話すと、高い確率で固定pips損切りを使っている。直感的には固定幅の方がシンプルで管理しやすいように見えるが、数理的には重大な問題を抱えている。
市場のボラティリティは時間帯・曜日・市場環境によって大きく変動する。ドル円の日足ATR(14)を例に取ると、2024〜2026年のデータでは通常80〜150pipsの範囲で推移しつつ、政策金利発表や地政学リスクイベントが重なると200pipsを超えることがある(出典: 市場データの一般的な観察値。具体的な数値はブローカーのチャートで要確認)。
H1足のATRはさらに変動が大きい。通常10〜25pipsだが、ロンドン開場直後やニューヨーク開場時間には30〜40pipsに跳ね上がることがある。一方、アジア時間の深夜は5〜10pipsまで低下する局面も珍しくない。
固定50pipsを設定した場合、静かなアジア時間には「ATRの5〜10倍」という過剰な損切り幅になる半面、活発なロンドン時間には「ATRを下回る」ノイズに刈られやすい幅になる。同じパラメーターがまったく異なる意味を持ってしまうわけだ。
これは単純に「大きいか小さいか」の問題ではない。損切りの論理的な役割は「エントリー根拠が否定された地点で撤退する」ことだ。相場のノイズ幅より小さい損切りは、根拠の否定とは無関係に、ランダムな価格変動によって執行される。
ATRベースにすることで相場に合わせた損切りになる原理
ATRの数理的な意味を正確に言えば「この期間のTrueRangeの平均値」であり、より実用的には「1バーあたりのボラティリティの代理指標」だ。
ATR × 1.5倍の損切りを設定した場合、その損切りは「この相場が1バーで動く典型的な値幅の1.5倍の外側」に置かれることになる。相場のノイズ(通常の値動きの揺れ)を超えたところに損切りを配置するという設計思想の実装だ。
高ボラティリティの局面ではATRが大きくなり、損切り幅も自動的に広がる。低ボラティリティ局面ではATRが小さくなり、損切り幅も収縮する。相場の呼吸に合わせて損切りが変化する仕組みだ。
固定pipsから切り替えた際、典型的に起きる変化は損切り回数の減少と1回あたりの損失額の増加だ。初期に「損切りが減った」と誤解しやすいが、実際には「意味のある損切りに絞られた」のであって、期待値が改善している可能性がある。
ATR(Average True Range)とは何か
Photo by path digital on Unsplash
計算式(True Rangeの定義と平均化)
ATRを正確に理解するには、まずTrue Range(TR)の定義から入る。J. Welles Wilderが1978年の著書「New Concepts in Technical Trading Systems」で発表したTRは、以下の3つの計算値の最大値として定義される。
TR = MAX(
High − Low, // 当バーの高値と安値の差
|High − 前バーClose|, // 当バーの高値と前バー終値の差の絶対値
|Low − 前バーClose| // 当バーの安値と前バー終値の差の絶対値
)
最初の「High − Low」だけでは翌日ギャップアップ・ギャップダウン(窓開け)の影響が計測できない。後者2つの式を追加することで、前バーから当バーにかけての「実質的な価格変動幅」を捉えている。FXは24時間市場であるため週明けのギャップが主な出現場面だが、この設計はMT4のH1〜H4足でも機能する。
ATRはこのTRをWilderの平滑化移動平均(EMAの一種、α = 1/n)で平均化したものだ。
ATR(n) = ((n-1) × 前期ATR + 当期TR) / n
EMAと同一の計算形式であり、n = 14の場合は直近バーほど重みが大きく、古いバーの影響が指数的に減衰する。単純移動平均(SMA)との違いは、過去のボラティリティショックが徐々に薄れる点にある。
期間設定(14が標準の理由)
ATRの標準期間「14」はWilder自身が実証的に「短期・長期のバランスが良い」と判断して選んだ値だ。当時の商品先物市場での運用実績がその背景にあるが、FXでも現在まで広く採用されている。
数理的な根拠を加えると、期間14のATRは約半月分のデータを参照することになる(日足の場合)。月次の中間的なボラティリティを捉えるのに適したウィンドウサイズだ。
これより短い期間(5〜7)は直近ボラティリティへの感応度が上がるが、単発のスパイクによる一時的な急上昇・急低下に引っ張られやすくなる。長い期間(20〜30)は安定的だが、相場環境の変化への追従が遅れる。14はこのトレードオフの中間点として選ばれた、経験則に基づく値だ。
H1・H4でのEA開発では14を出発点として使い、バックテストで7〜20の範囲を最適化するアプローチが実務的だ。
ドル円でのATR値の読み方
「ATRが0.008」という数値だけ見ても直感的に意味が掴みにくい。実際の相場で使うには、pipsへの換算が要る。
ドル円の場合(5桁業者)、1pip = 0.01円 = 10 × _Point。したがって:
ATR値(pips)= iATR取得値 ÷ (_Point × 10)
例えばH1足ATRが0.0020なら「20pips」、0.0008なら「8pips」だ。「今日のATRは20pipsある」という解釈は「直近14本のH1バーを見ると、平均して1バーあたり20pips動いている」という意味になる。
エントリー前にATR値を確認するクセをつけると、「今は動きがある相場か、静かな相場か」を数値で把握できる。経済指標発表後はATRが急上昇しているため、同じ損切り幅設定でもリスクが増大しているサインとして読める。
MQL4でATRベース損切りを実装する
iATR()関数の使い方
MQL4でATR値を取得するための関数が iATR() だ。関数シグネチャは以下の通り。
double iATR(
string symbol, // 通貨ペア(NULLで現在のシンボル)
int timeframe, // 時間軸(0で現在の時間軸)
int period, // ATR期間(通常14)
int shift // バーのシフト(0=現在バー、1=完成した直前バー)
);
shift パラメーターの選択が実装上の最重要ポイントだ。shift = 0 は現在形成中のバーを参照するため、バーが閉まるまでATR値が確定しない。エントリーシグナルの判断に未確定値を使うことになり、バックテストと実運用で挙動が変わりやすい。shift = 1 を使えば、直前の確定バーのATRを参照でき、再描画なしの安定した計算が可能になる。
なお、symbol と timeframe に NULL と 0 を使う方法もあるが、EAを異なる通貨ペアのチャートに貼り付けたとき、意図しないシンボルのATRを参照するバグが発生しやすい。複数の通貨ペアで稼働させる予定があるなら、Symbol() と Period() を明示的に指定するか、チャートのシンボル・時間軸を固定する設計を推奨する。
ATR値 × 倍率で損切り幅を計算するコード
ATR値はPoint単位で返されるため、pips換算に注意が必要だ。損切り幅の計算においてATR値をそのまま演算に使うこと自体は問題ない(価格計算なのでPoint単位のままで構わない)が、「何pipsの損切りになっているか」を確認するには換算が要る。
// ATR損切り幅の計算(サンプルコード)
double atr = iATR(Symbol(), Period(), 14, 1); // 直前確定バーのATR
// ゼロ値ガード(必須)
if(atr <= 0.0)
{
Print("ATR取得エラー: エントリーをスキップします");
return; // または return(false);
}
double atrMultiplier = 1.5; // ATR倍率(バックテストで最適化)
double slDistance = atr * atrMultiplier; // 損切り幅(Point単位)
// 参考: pips換算(ドル円5桁業者の確認用)
double slPips = slDistance / (_Point * 10);
Print("損切り幅: ", DoubleToStr(slPips, 1), " pips");
if(atr <= 0.0) return; というガード節は「当たり前すぎて省略されがち」だが、MT4のデータ未初期化バー(チャートの最左端付近)やブローカーのデータフィード問題で iATR() が0を返すケースが実際に存在する。このガードがないと、slDistance = 0 となりゼロ除算や異常ロット計算につながりかねない。
SLをコードで自動セットする実装例
実際のEAで使えるATRベースSL設定の完全実装例を示す。既存EAのSL設定部分を置き換えるユースケースで記述した。
// ===== ATRベースSL/TP自動設定 実装例(MQL4)=====
// 注意: このコードは教育目的のサンプルです。実際の取引への適用は自己責任で行ってください。
extern int ATRPeriod = 14; // ATR期間(標準値。バックテストで最適化)
extern double ATRMultiplierSL = 1.5; // SL倍率
extern double ATRMultiplierTP = 3.0; // TP倍率(SL倍率1.5との比でSL:TP=1:2。ATRMultiplierSLを変更した場合は合わせて調整が必要)
extern int MagicNumber = 12345;
extern double LotSize = 0.1;
//+------------------------------------------------------------------+
//| ATRベースSL/TP価格を計算してロング注文を発注する関数 |
//+------------------------------------------------------------------+
bool SendBuyOrderWithATRSL()
{
// --- ATR取得(直前確定バー: shift=1)---
double atr = iATR(Symbol(), Period(), ATRPeriod, 1);
// ゼロ値ガード(必須)
if(atr <= 0.0)
{
Print("[ATR_EA] ATR取得失敗: エントリーをスキップ");
return(false);
}
double slDistance = atr * ATRMultiplierSL; // 損切り幅
double tpDistance = atr * ATRMultiplierTP; // 利確幅
// ブローカーの最小ストップ距離チェック
double minStopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * _Point;
if(slDistance < minStopLevel)
{
Print("[ATR_EA] ATR損切り幅が最小ストップ距離を下回るためスキップ");
return(false);
}
double entryPrice = Ask;
double stopLoss = entryPrice - slDistance; // ロングの損切り
double takeProfit = entryPrice + tpDistance; // ロングの利確
// 価格の正規化(ブローカー要件)
stopLoss = NormalizeDouble(stopLoss, Digits);
takeProfit = NormalizeDouble(takeProfit, Digits);
// 注文送信
int ticket = OrderSend(
Symbol(), // 通貨ペア
OP_BUY, // 注文タイプ
LotSize, // ロット
entryPrice, // エントリー価格
3, // スリッページ(pips)
stopLoss, // ストップロス
takeProfit, // テイクプロフィット
"ATR_SL_EA", // コメント
MagicNumber, // マジックナンバー
0, // 注文期限(無制限)
clrBlue // チャート表示色
);
if(ticket < 0)
{
Print("[ATR_EA] OrderSendエラー: ", GetLastError());
return(false);
}
Print("[ATR_EA] ロング発注完了 SL=", DoubleToStr(stopLoss, Digits),
" TP=", DoubleToStr(takeProfit, Digits),
" ATR=", DoubleToStr(atr / (_Point * 10), 1), "pips");
return(true);
}
コードの設計上の注意点を補足しておく。ATRPeriod を extern 変数として外出しにしているのは、MT4のストラテジーテスターで最適化対象にできるようにするためだ。倍率2つも同様に外出しにしており、バックテストで一括最適化できる。
NormalizeDouble() を必ず適用している点も意図的だ。MT4では生の浮動小数点演算で桁数が一致しないとブローカーがエラーを返すことがある。損切り・利確価格には常に Digits で正規化する習慣をつけておきたい。
ATR倍率の選び方(1.0倍〜3.0倍の比較)
倍率別のバックテスト結果比較
以下は一般的なトレンドフォローEAにATRベース損切りを適用した際の倍率別傾向を示したものだ。具体的な数値は戦略・通貨ペア・バックテスト期間に大きく依存するため、あくまで傾向の目安として参照してほしい。
表: ATR倍率別の損切り特性(目安)
| ATR倍率 | 損切り幅の目安 | 勝率の傾向 | PFの傾向 | 特性 | |--------|--------------|----------|---------|------| | 1.0倍 | タイト | 高め | 低め | ノイズ刈りが多発。損切り回数が多い | | 1.5倍 | 標準 | 中程度 | 中程度 | トレンドフォローEAで汎用的な起点 | | 2.0倍 | やや広め | 低め | 高め | ノイズ耐性高い。逆張りEAや荒れた相場向き | | 2.5倍 | 広め | 低め | 要検証 | 大きな相場変動への対応用。1回の損失額が大きい | | 3.0倍 | 最大 | 最低 | 要検証 | 急騰急落への対応。ロット管理が重要になる |
※上記は一般的な傾向であり、実際の成績は戦略・通貨ペア・市場環境に大きく依存します。バックテスト結果は将来の運用成果を保証しません。
倍率1.0倍が「勝率は上がるが期待値が低い」というのは直感に反するように見えるが、統計的には説明できる。損切りがノイズの射程圏内にあると、シグナルの正否と無関係に損切りが執行される確率が上がる。勝率が高くても「本来勝てたトレードの利益を刈られている」状況が発生し、プロフィットファクターが下押しされるメカニズムだ。
1.5倍はWilderが想定した「標準的なノイズの1.5倍外側」という数理的解釈と合致する起点だ。ここから始めてバックテストで±0.25の感応度を確認し、パラメーター周辺でなだらかな性能分布が得られるかを検証する。急峻なピーク(1.5倍だけ突出して他は悪い)は過剰適合の疑いが強い。
通貨ペア別の推奨倍率の目安
通貨ペアの特性を踏まえた倍率の目安を以下に整理する。いずれも「一般的な傾向」であり、個別の戦略・相場環境に応じて最適化は当然必要だ。
- ドル円: 1.5〜2.0倍が起点として適切とされる。スプレッドが比較的狭く、方向感が出やすい局面が多いため、標準倍率でのトレンドフォローが機能しやすい
- ユーロドル: 1.5〜2.0倍。ドル円と同様に流動性が高く、標準的なボラティリティ水準
- ポンドドル: 2.0〜3.0倍。ボラティリティが高く、タイトな損切りが刈られやすいため、倍率は大きめに設定する
- ポンド円: 2.5〜3.0倍。ポンドと円の複合ボラティリティにより値動きが大きく、ATR異常値も出やすい。逆張り戦略での適用には特に慎重なバックテストが要る
通貨ペアのボラティリティ特性については、逆張りEAの設計とバックテスト手法でも詳しく解説しているので参照してほしい。
ATRベースのテイクプロフィット設定
SL:TP = 1:1.5 / 1:2 / 1:3 の選び方
テイクプロフィットもATRベースにするかどうかは、戦略の設計思想に依存する。ただし、SLをATRベースにしておきながらTPを固定pipsにする設計は、損切り幅が相場に応じて変動するのに対してTPが固定されているという不整合を生む。原則としてSL・TP両方をATRベースに揃えることを推奨する。
SL:TP比率の選択は期待値計算から逆算できる。スリッページ・スプレッドを無視した理論値は以下の通りだ。
| SL:TP比率 | 期待値プラスに必要な最低勝率 | |-----------|--------------------------| | 1:1.5 | 約40%以上 | | 1:2 | 約34%以上 | | 1:3 | 約26%以上 |
実際のFX取引ではスリッページとスプレッドがコストとして加算されるため、上記より数ポイント高い勝率が実質的に必要になる。あくまで理論上の目安だ。
1:1.5は勝率の下限が高い(40%が必要)代わりに、利確にかかる時間が短い。短時間足のEAや、ポジションの保有時間を短くしたい場合に向く。1:3は勝率26%超えさえあれば理論上プラス期待値を持てるが、実際に3倍幅のTPまで価格が届く確率を考えると、トレンド相場でなければ利確が遠すぎる問題が生じる。
トレンドフォローEAと逆張りEAで異なる設計
トレンドフォローEAは「大きなトレンドに乗って利益を伸ばす」設計のため、1:2〜1:3の比率が適性が高い。損切りをATR × 1.5〜2.0倍に設定し、テイクプロフィットをATR × 3.0〜4.0倍まで引っ張る設計が機能しやすい。この場合、利確ラインまで到達できず損切りを繰り返す時期(相場のもみ合い)が続く期間を、資金管理で乗り越える設計が前提になる。
逆張りEAは「過剰な動きからの反発」を狙うため、SL:TP = 1:1〜1:1.5の設計が多い。損切りはATR × 2.0〜2.5倍(ノイズを吸収するために広め)、テイクプロフィットはATR × 1.5〜2.0倍(反発の到達しやすい幅)という非対称性が典型的だ。見かけのSL:TP比は1:1以下になることもあるが、高勝率で補完する設計だ。
逆張りEAの詳細な設計方法についてはレンジ相場向け逆張りEAの設計とバックテストで具体例を交えて解説している。また、エントリー精度を高めるためのADXフィルター実装についてはADXフィルターをEAに実装する方法も参照してほしい。
ATRベースのEAを一から設計する手間を省きたい場合、Hedgrow FXでは設計済みのATR対応EAをClaudeと対話しながら即座に活用できる。月額1,980円で、ATR倍率の調整やバックテストまでサポートしている。
EA動的損切り(ATRストップロス)の注意点とボラティリティ対応
スプレッド拡大時にATRが過小評価される問題
ATRはスプレッドを含まない「実際の価格の値動き」で計算される。これは重要な含意を持つ。
経済指標(米CPI・FOMC・非農業部門雇用者数など)の発表前後には、通常1〜2pipsのスプレッドが5〜20pipsまで拡大することがある。しかしATRはスプレッドの変化を検知しない。ATRが20pipsを示していても、その20pipsの中にスプレッド10pipsが含まれているわけではない。スプレッド10pipsが上乗せされた状態で20pipsのATR損切り幅を使うと、実質的な損切り幅はスプレッド分だけ狭まった10pipsになってしまう。
対策として有効なのは、経済指標発表前後の一定時間はEAの新規エントリーを停止するニュースフィルターの実装だ。
// 簡易ニュースフィルター(時間帯チェックのサンプル)
bool IsNewsTime()
{
// 現在のGMT時間を取得(ブローカーのサーバー時間に応じて調整が必要)
int hour = TimeHour(TimeCurrent());
int minute = TimeMinute(TimeCurrent());
// 例: 毎週金曜日21:30(米雇用統計の発表時間帯)前後30分を除外
// ※ 実際の運用では金融カレンダーAPIとの連携が理想
if(DayOfWeek() == 5 && hour == 21 && minute >= 0 && minute <= 59)
return(true);
return(false);
}
これは簡易実装の例であり、本格的な運用には外部カレンダーとの連携が望ましい。
低流動性時間帯(週明け・祝日)でのATR異常値対策
週明け月曜日の早朝は、週末の出来事を受けた価格ギャップが発生しやすい。このギャップがTR計算に含まれると、ATRが急上昇して実態を反映しない過大な損切り幅が算出される。ポンド円のような元々ボラが高い通貨ペアでは、週明けのATR異常値が顕著に現れる。
同様のことが、日本・米国・英国・ニュージーランドの祝日にも起きる。祝日はマーケット参加者が減少してスプレッドが拡大し、小さな売買でも価格が大きく動くため、ATRが通常より高い値を示すことがある。
ATR異常値への対策として、ATR上限キャップの実装が有効だ。
// ATR上限キャップ実装例
double GetCappedATR(int period)
{
double atr = iATR(Symbol(), Period(), period, 1);
if(atr <= 0.0) return(0.0); // ゼロ値ガード
// 直近20バーの平均ATRを基準として計算
double sumATR = 0.0;
for(int i = 1; i <= 20; i++)
sumATR += iATR(Symbol(), Period(), period, i);
double avgATR = sumATR / 20.0;
// ATRが平均の3倍を超えている場合は平均の3倍にキャップ
double capValue = avgATR * 3.0;
if(atr > capValue)
{
Print("[ATR_EA] ATR異常値検出: ", DoubleToStr(atr / (_Point*10), 1),
"pips → ", DoubleToStr(capValue / (_Point*10), 1), "pipsにキャップ");
return(capValue);
}
return(atr);
}
このキャップ実装と組み合わせて、週明け月曜日の最初の数バーや特定の時間帯のエントリーを禁止する時間フィルターを追加するとさらに安定する。時間フィルターの具体的な実装方法についてはADXフィルターをEAに実装する方法でも触れているので参照してほしい。
よくある質問(FAQ)
ATRの期間は14以外に変える必要があるか?
スキャルピングEA(M1・M5足)では7〜10期間に短縮するケースが多い。日足・H4足のスイングEAでは14〜20期間が使われることもある。ただし、まず14を起点としてバックテストで最適化範囲を探るアプローチが実務的で、先に期間を変えることに根拠はない。最重要なのは期間の変更より、倍率の最適化と過剰適合チェックだ。
ATRベースと固定pipsどちらが安定するか?
一律の答えはなく、相場環境と戦略の組み合わせに依存する。バックテストでATRベースと固定pipsを同じEAに両方試すと、ボラティリティが変動する長期期間ではATRベースが安定しやすい傾向が出ることが多い。ただし「ATRベースだから安定する」のではなく「相場のボラティリティを参照した損切り設計だから合理的」という理解が正確だ。
ATRがゼロになることはあるか?
理論的には価格が少しでも動けばTR > 0のため、ATRがゼロになることはない。ただし、
iATR()関数がデータ未初期化バー(チャートの最左端付近)の場合や、ブローカーのデータフィード問題でゼロを返すケースが実際に存在する。if(atr <= 0.0) return;というガード節は必ず実装すること。
テイクプロフィットもATRベースにすべきか?
SLをATRベースにするなら、TPもATRベースに揃えることを推奨する。SLのみATRベースでTPを固定pipsにすると、高ボラ局面ではSLが広がっているのにTPが変わらず、リスクリワード比が悪化するという不整合が生じる。SLとTPを同じATR値からの倍率で設定することで、リスクリワード比が相場環境を問わず一定に保たれる。ATR対応EAの設計・バックテストを対話しながら進めたい場合は、Claudeと会話しながらインジケータが作れるhedgrow-fxも活用してほしい。
免責事項
本記事はFXに関する教育・情報提供を目的としており、投資勧誘を目的とするものではありません。掲載しているコードサンプルは教育目的のものであり、実際の取引への適用は自己責任で行ってください。
FX取引には元本割れリスクが伴います。バックテスト結果は過去のデータに基づくものであり、将来の運用成果を保証するものではありません。ATR倍率等のパラメーター推奨値は「一般的な目安」であり、個別の相場環境・取引戦略・資金規模に応じて結果は大きく異なります。実際の運用判断は、必ずご自身で十分に検証した上で行ってください。
ATRベースの損切り設計済みEAを手軽に試したい方は、Hedgrow FX(月額1,980円)をご活用ください。Claudeと対話しながらパラメーター調整・バックテストまで一貫して行える環境を提供しています。
