ADX・移動平均・ATRの三層設計 — 参加可否・方向・撤退幅を別々の指標に担当させる

ロジックを組むとき、多くの人は「どこで入るか」から考え始めます。ただ、実際に効いてくるのはその手前にある「そもそも今この局面に手を出す意味があるのか」という問いのほうではないでしょうか。本記事では、ADXに参加可否のゲート、移動平均に方向の確定、ATRに撤退幅の算出を割り当てる三層設計を扱います。狙いは指標を3つ並べて条件を厳しくすることではなく、「参加しない」という結論を一番上で出せる構造にすることにあります。cBotの自作を検討している方、シグナルは出るのに挙動が読みにくいと感じている方に向けた内容です。

ADXが参加可否のゲート、移動平均が方向の確定、ATRが撤退幅の算出をそれぞれ担当する三層構造を、答える質問と答えない質問の対比表として示した図

ADXの役割 — 参加するかどうかを決めるゲート層

ADX(Average Directional Index)は、値動きが一方向にどれだけ偏っているかを0〜100の数値で表します。この設計では、ADXをシグナルを出す係としてではなく、後段を動かすかどうかを切り替えるスイッチとして一番上に置きます。

ゲートに求めるのは、当たりを増やすことではありません。明らかに向いていない場面を先に外しておくことです。偏りの乏しい局面では、方向を示す指標が何を返してきてもその前提自体が薄くなります。そこをADXが先に止めてしまえば、下の2層は「偏りのある局面でだけ働く部品」として単純に設計できます。

単独で使ったときの限界もはっきりしています。ADXは向きを持たないので、値が高くても上下どちらへ寄っているのかは分かりません。指数平滑を重ねた計算のため、動き出しの初期には反応が遅れます。加えて、判定水準のすぐ近くを値が行き来すると、フラグが短い間隔でON/OFFを繰り返すこともあります。ADX単体は入る理由になりません。参加可否のふるいとして置いたときに、最も素直に働いてくれる指標だと考えておくのが安全です。

移動平均の役割 — 方向を1つに絞る層

移動平均は、決められた本数ぶんの終値をならして1本の線にしたものです。ゲートを通った局面に対して、この層は「どちら側の前提で相場を見るか」を1つに確定させます。判定を凝る必要はなく、価格が線のどちら側にいるか、線そのものがどちらへ傾いているか、この2点で足ります。

向きを先に固定しておく意味は、下流が単純になる点にあります。前提が決まっていれば、順張りか逆張りかを場面ごとに考え直す必要がなくなり、条件の分岐も増えません。分岐の少ないロジックは、後から挙動を追いかけるときの負担も軽くなります。

限界は、ならすという処理そのものから来る遅れです。転換の場面では線の反応が実際の値動きに一歩遅れますし、レンジでは価格が線をまたいで往復するため、向きの判定が短い間隔でひっくり返ります。ただ、この弱点の大部分は前段のゲートが吸収してくれます。向きが定まりにくいのはまさに偏りの乏しい局面であり、そこは既に止まっているからです。方向と強度を分担させる考え方そのものは、ADXと移動平均を組み合わせる考え方でも扱っています。

ATRの役割 — 撤退幅とロットを決める層

ATR(Average True Range)は、直近何本かの値幅をならして、いま相場がどれくらいの振れで動いているかを示します。向きについては何も語りません。

この設計でATRに引き受けてもらうのは、シグナルの成立判断ではなく撤退水準と枚数の算出に限られます。荒い時期と静かな時期とでは、ポジションが通常の振れに耐えるために必要な余裕は同じではありません。ここを固定値にすると、荒い時期には何でもない戻りで叩き出され、静かな時期には過剰な余裕を抱え込むことになります。ATRの倍率で出しておけば、その差を相場側の数値に追従させられます。考え方の詳細はATRベースの利確幅設計でも整理しています。

幅が決まれば枚数も決まります。許容できる損失額を先に決めておけば、幅から逆算して枚数が一意に定まるためです(ロットの基礎)。ATRはそれ自体では入る理由にも出る理由にもなりませんが、リスクに関わる計算をこの層だけに閉じ込められるところに意味があります。

ADXとATRは何が違うのか

この2つは混同されやすいので、先に整理しておきます。ADXが測るのは向きの偏りの度合い、ATRが測るのは振れ幅の大きさです。どちらも「相場が動いている」という言葉で語られがちですが、答えている質問が別物です。

実際には、次の4通りが起こり得ます。

3つ目が特に厄介です。振れ幅だけを見て「動いているから参加する」と決めると、向きの定まらない往復に正面から乗ることになります。逆に2つ目では、振れ幅が小さいという理由で見送ると、向きの揃った場面を落とします。強度と振れ幅を1つの条件式に混ぜず、別の層に割り当てるのは、この取り違えを構造として防ぐためでもあります。

なぜ強度を最上流に置くのか

三層はそれぞれ別の質問に答えています。

順序には意味があります。向きを先に決めてから強度で絞っても、通過する集合はよく似た形になります。それでも強度を先頭に置くほうが設計としては素直です。判断が不要な場面では下を一切評価しないため、処理の並びがそのまま「見送った理由」を表す形になるからです。

補完の関係も整理できます。移動平均の弱点である「レンジでの反転の多さ」はゲートが落とし、ADXの弱点である「向きを持たないこと」は移動平均が埋めます。ノイズフィルターとして機能することが期待できるのは、この2層が互いの死角を補い合っているからです。ATRはこの2層とは性質が違い、シグナルの成立には関与させません。判定の条件と幅の設計が同じ式に同居していると、挙動が変わったときに「判定を触ったせいか、幅を触ったせいか」を切り分けられなくなります。

ただし、層を重ねればシグナルの成立回数は確実に減ります。そして、検証を繰り返すうちに条件が積み上がっていく過剰最適化とは常に隣り合わせです。この構成が優先しているのは機会の量ではなく、判断の筋道が一本に通っていることと、後から原因を切り分けられることだと押さえておくと、運用に入ってからの見込み違いが減ります。

パラメータをどう考えるか

触る対象は、ADXの期間と判定水準、移動平均の種類と期間、ATRの期間と倍率です。数が多いので、正解を探すより性質を押さえるほうが実用的です。

ADXは期間を詰めると値動きの変化に敏感になり、伸ばすとならされて落ち着きます。判定水準は単一の値で切るとフラグが振動しやすいため、通過用と離脱用で水準を分けたバンドにしておくと挙動が安定します。移動平均は、期間を伸ばせば向きの判定が安定する代わりに切り替わりが遅れ、詰めればその裏返しになります。ATRの倍率は、大きくすれば日常的な振れで叩き出されにくくなる一方、1回あたりに引き受ける損失の幅も広がります。

どれも「短期寄りに振るか、長期寄りに振るか」という粒度で捉え、特定の数値を正解として固定しないほうが健全です。三層をまとめて触ると、変化の原因がどこにあったのか追えなくなります。他の2層を止めたまま1層だけ動かす、という手順をバックテストに持ち込むのが現実的な進め方になります。

cBot化する際の考慮点

cTraderのcBotとして書くときに、押さえておきたい論点を挙げます。

評価の並び: ゲート → 方向 → 幅の順に見て、前段が崩れたらその足はそこで終える早期リターン型に組みます。コードの並びと設計の意図が一致するので、読み返したときに追いやすくなります。

参照する足を揃える: 形成途中のバーでは、ADXもATRも値が確定していません。3つの層がばらばらの足を見ないよう、参照先は直前の確定足に統一しておきます。

ウォームアップ: ADXは平滑処理を重ねる都合上、他より多くのバーを要求します。起動直後は値が落ち着かないので、最も長い期間を基準にバー数のガードを置き、NaNのチェックも通してから判定に入ります。

幅の下限: 静かな時間帯にATRが縮むと、算出された撤退幅がブローカーの最小ストップ距離に届かないことがあります。下限を設けたうえで、届かない足は発注そのものを見送る扱いにしておくと事故を避けられます。

枚数の丸め: 幅から枚数を求める段では、Pip値の換算と最小取引単位への丸めが入ります。丸めで許容額をはみ出さないよう、切り捨て側に倒しておくのが無難です。

// ゲート → 方向 → 幅 の順に見て、崩れたらその足は終える
var dms     = Indicators.DirectionalMovementSystem(AdxPeriod);
var maLine  = Indicators.MovingAverage(Bars.ClosePrices, MaPeriod, MovingAverageType.Exponential);
var atrLine = Indicators.AverageTrueRange(AtrPeriod, MovingAverageType.Exponential);

if (Bars.Count < MaPeriod + AdxPeriod * 2) return;   // ウォームアップ不足

// ① ゲート: 参加する局面かどうかだけを見る
var adxValue = dms.ADX.Last(1);
if (double.IsNaN(adxValue) || adxValue < AdxGateLevel) return;

// ② 方向: 前提とする向きを一つに決める
var maValue = maLine.Result.Last(1);
var closed  = Bars.ClosePrices.Last(1);
var goLong  = closed > maValue && maValue > maLine.Result.Last(5);
var goShort = closed < maValue && maValue < maLine.Result.Last(5);
if (!goLong && !goShort) return;

// ③ 幅: 撤退距離を出す(成立判断には使わない)
var stopDistance = atrLine.Result.Last(1) * AtrMultiple;   // 倍率は検証対象
if (stopDistance < MinStopDistance) return;                // 下限に届かない足は見送る

3つとも計算コストは小さく、OnBarで回す限り負荷が問題になる場面はほとんどありません。動かし始めた時期は、各層のフラグと算出された幅をバーごとに書き出しておき、チャートを見ながら「止まってほしい足で止まっているか」を確かめる時間を取ると、後の調整が楽になります。

実装の流れ

処理全体は、上から下へ一方向に降りていく形に整理できます。

ゲート層でADXが基準を満たすか判定し、通過した場合のみ方向層で移動平均による向きを確定させ、さらに幅決め層でATRから撤退幅とロットを算出して発注へ進む戦略フロー図。各層で条件を満たさない場合は見送りへ分岐する

  1. 入力: 対象の銘柄と時間足を決め、終値と各指標を確定足ベースで更新する
  2. ゲート層: ADXが基準に届いているかだけを見る。届かなければ、その足では何も評価せず終える
  3. 方向層: 価格と線の位置関係、および線の傾きから、前提とする向きを1つに決める
  4. 幅決め層: ATRから撤退距離を出し、下限のガードを通したうえで許容損失額から枚数を求める
  5. 発注・管理: 決まった撤退水準と枚数で発注し、その後の決済管理へ引き継ぐ

書き方の勘所は、三層をひとつの複合条件式に畳まないことです。層ごとに独立したフラグとして持たせ、どこで止まったかを記録しておけば、後から段別に集計できます。とりわけゲートで止まった割合は、その銘柄と時間足がこの構成に噛み合っているかどうかを測る手がかりになります。

どう活用するか

自作派の方は、Claude Code でcBotを組むときの下書きとして、この「ゲート・方向・幅」という並びを流用してみてください。ゲートに置くものはADXでなくても構いません。時間帯の制限や指標発表の回避条件に差し替えても、三層の骨格はそのまま生きます。

委託派の方は、ai-programming.xyz に相談する際、「参加可否・方向・幅を別々に扱いたい」という前提を先に伝えておくと、仕様の詰めが短く済みます。教育派の方は、手元にある2指標のロジックの上流にゲートを1枚足す改造課題にすると、入る条件を考える前に入らない条件を決める意味が、手を動かしながら確認できます。

本記事は一般的な情報提供を目的としています。投資助言ではありません。 取引判断はご自身の責任で行ってください。