この記事でわかること
- 平均回帰(リバーサル)トレードの4つの判定条件をPine Scriptで数値化する方法
- スパイク検出・出来高判定・MAクロス回数・レンジ判定の実装コード
- ストップロス幅の最低ライン・利確幅を自動計算するコード
支持線・抵抗線で反発を狙ってエントリーしたのに、そのまま突き抜けられて損切りになった経験はありませんか。反発するかどうかを感覚で判断していると、同じような負けパターンを繰り返しやすくなります。
この記事では、反発を狙う平均回帰トレードで「今は反発しやすい状況か」を4つの条件で数値化し、Pine Scriptのインジケーターとして自動判定するコードを解説します。
📊 この記事はTradingViewユーザー向けです
TradingViewをまだ使っていない方は、まず無料アカウントを作成してみましょう。登録は30秒、クレジットカード不要です。
無料でTradingViewを始める →平均回帰(リバーサル)トレードとは
トレードには大きく2つのスタイルがあります。順張り(モメンタム)は価格がそのまま同じ方向に動き続けることに賭け、逆張り(平均回帰)は価格が反転することに賭けます。同じチャート・同じ支持線を見ていても、順張り派は「抜けそう」、逆張り派は「持ちこたえそう」と真逆の判断をします。
平均回帰トレードで勝率を上げる鍵は、「反発しやすい状況かどうか」を条件化しておくことです。この記事では、その条件を4つのフィルターに分解し、それぞれをPine Scriptの数値判定に落とし込みます。
| フィルター | 見るポイント | 反発しやすい状態 |
|---|---|---|
| ①スパイク | 直近の値幅 | ATRの1.5倍以上の急な値動き |
| ②出来高 | 直近と過去の出来高平均 | 横ばい・減少 |
| ③MAクロス回数 | 直近20本での30MA交差回数 | 4回以上(レンジ相場) |
| ④直近レンジ | 直近8本の高値・安値 | 更新していない(レンジ内) |
Pine Scriptの基礎文法をまだ押さえていない場合は、先にPine Script v5 基礎文法まとめに目を通しておくとコードが読みやすくなります。
4つのフィルターをPine Scriptで数値化する
フィルター1:スパイク検出
「急な値動きで支持線・抵抗線に到達したか」を、直近のATR(平均的な値幅)と当該バーの値幅を比較して判定します。
atrLen = input.int(20, "ATR期間")
spikeMult = input.float(1.5, "スパイク判定倍率", step=0.1)
atrVal = ta.atr(atrLen)
barRange = high - low
isSpike = barRange > atrVal * spikeMult
当該バーの値幅が直近20本の平均的な値幅(ATR)の1.5倍を超えていれば、急な値動きとみなします。倍率はチャートの銘柄・時間足によってspikeMultで調整してください。
フィルター2:出来高の傾き
スパイクの最中に出来高が増え続けている場合、新規の買い(または売り)が入り続けている可能性が高くなります。この場合は反発の期待値が下がります。直近の出来高平均と、少し長い期間の出来高平均を比較して判定します。
volLookback = input.int(5, "直近出来高の期間")
volLen = input.int(20, "比較対象の出来高期間")
volAvgRecent = ta.sma(volume, volLookback)
volAvgPast = ta.sma(volume, volLen)
isVolFlat = volAvgRecent <= volAvgPast
直近5本の出来高平均が、直近20本の出来高平均以下であれば「出来高は横ばいか減少」と判定します。
フィルター3:30MAクロス回数
レンジ相場か、トレンド相場かを判定するために、直近一定期間で終値が30MAを何回またいだかを数えます。
maLen = input.int(30, "MA期間")
crossLen = input.int(20, "クロス回数を数える期間")
crossMin = input.int(4, "レンジ相場とみなす最低回数")
ma30 = ta.sma(close, maLen)
crossNow = ta.cross(close, ma30) ? 1 : 0
crossCount = math.sum(crossNow, crossLen)
isChoppy = crossCount >= crossMin
直近20本で終値が30MAを4回以上またいでいれば、方向感の定まらないレンジ相場と判定します。クロス回数が少ない場合は、片側に伸び続けるトレンド相場である可能性が高く、平均回帰には不向きです。
フィルター4:直近レンジのブレイク有無
直近数本の高値・安値を更新していないかを確認し、素直にレンジ内で推移しているかを判定します。
lhsLen = input.int(8, "左サイド判定の期間")
lhsHigh = ta.highest(high, lhsLen)[1]
lhsLow = ta.lowest(low, lhsLen)[1]
isRangeBound = high <= lhsHigh * 1.002 and low >= lhsLow * 0.998
直近8本の高値・安値を(0.2%の許容範囲を持たせつつ)更新していなければ、レンジ内での値動きと判定します。
TradingViewで実際に試してみよう
この記事の内容はTradingViewで今すぐ実践できます。無料プランでも十分対応できます。
▶ TradingViewを無料で開くクレジットカード不要・いつでも解約OK
4フィルターを統合したインジケーター実装
上記4つの条件をすべて満たしたバーで、支持線付近ならロング、抵抗線付近ならショートのシグナルを出す完全なコードです。
//@version=5
indicator("平均回帰4フィルター判定", overlay=true)
atrLen = input.int(20, "ATR期間")
spikeMult = input.float(1.5, "スパイク判定倍率", step=0.1)
volLookback = input.int(5, "直近出来高の期間")
volLen = input.int(20, "比較対象の出来高期間")
maLen = input.int(30, "MA期間")
crossLen = input.int(20, "クロス回数を数える期間")
crossMin = input.int(4, "レンジ相場とみなす最低回数")
lhsLen = input.int(8, "左サイド判定の期間")
// フィルター1: スパイク検出
atrVal = ta.atr(atrLen)
barRange = high - low
isSpike = barRange > atrVal * spikeMult
// フィルター2: 出来高の傾き
volAvgRecent = ta.sma(volume, volLookback)
volAvgPast = ta.sma(volume, volLen)
isVolFlat = volAvgRecent <= volAvgPast
// フィルター3: MAクロス回数
ma30 = ta.sma(close, maLen)
crossNow = ta.cross(close, ma30) ? 1 : 0
crossCount = math.sum(crossNow, crossLen)
isChoppy = crossCount >= crossMin
// フィルター4: 直近レンジのブレイク有無
lhsHigh = ta.highest(high, lhsLen)[1]
lhsLow = ta.lowest(low, lhsLen)[1]
isRangeBound = high <= lhsHigh * 1.002 and low >= lhsLow * 0.998
// 4フィルター統合
allFiltersPass = isSpike and isVolFlat and isChoppy and isRangeBound
longSignal = allFiltersPass and close > open and low <= lhsLow
shortSignal = allFiltersPass and close < open and high >= lhsHigh
plotshape(longSignal, title="ロングシグナル", style=shape.triangleup, location=location.belowbar, color=color.new(color.green, 0), size=size.small)
plotshape(shortSignal, title="ショートシグナル", style=shape.triangledown, location=location.abovebar, color=color.new(color.red, 0), size=size.small)
alertcondition(longSignal, title="平均回帰ロングシグナル", message="4フィルター成立、ロング反発シグナル")
alertcondition(shortSignal, title="平均回帰ショートシグナル", message="4フィルター成立、ショート反発シグナル")
コードのポイント
- 4つの条件は
andでつないでいます。allFiltersPassが1つでもfalseならシグナルは出ません。条件を緩めたい場合は一部をorに変えて検証してください - シグナルの方向は当該バーの陽線・陰線で判定しています。
close > openなら反発上昇、close < openなら反発下落とみなしています alertcondition()を使えば、条件成立時にTradingViewのアラート機能から通知を受け取れます。アラートの設定手順はアラート機能の設定方法と活用術を参考にしてください
ストップロス幅とリスクリワードを計算する
反発シグナルが出た後、どこにストップロスを置くかも数値化しておきます。直近のスイング高値・安値を基準にしつつ、値幅が近すぎる場合は最低1%の距離を確保するコードです。単体でPineエディタに貼り付けて動作確認できるよう、これだけで完結したインジケーターにしています。
//@version=5
indicator("平均回帰 SL/TP計算", overlay=true)
pivotLen = input.int(3, "スイング判定の左右期間")
minStopPct = input.float(1.0, "最低ストップ幅(%)", step=0.1)
swingHigh = ta.pivothigh(high, pivotLen, pivotLen)
swingLow = ta.pivotlow(low, pivotLen, pivotLen)
var float lastSwingHigh = na
var float lastSwingLow = na
if not na(swingHigh)
lastSwingHigh := swingHigh
if not na(swingLow)
lastSwingLow := swingLow
// ショートエントリーの例(ロングは高値・安値を入れ替えて同じ考え方で計算)
entryPrice = close
rawStopDist = lastSwingHigh - entryPrice
minStopDist = entryPrice * minStopPct / 100
stopDist = math.max(rawStopDist, minStopDist)
stopPrice = entryPrice + stopDist
takeProfitPrice = entryPrice - stopDist
plot(stopPrice, title="ストップ価格(ショート例)", color=color.red, style=plot.style_circles)
plot(takeProfitPrice, title="利確価格(1R)", color=color.green, style=plot.style_circles)
直近のスイング高値までの距離がエントリー価格の1%未満だった場合、ストップが近すぎてしまいます。この場合はminStopDist(1%)を採用してストップ幅を確保します。利確価格はストップと同じ値幅(リスクリワード1:1、いわゆる1R)に設定しています。この考え方を実際のトレードで検証する手順はバックテスト実行方法で解説しています。
こんな場合は向かない
- 強いトレンド相場が続いている場合は、フィルター3(MAクロス回数)がほとんど成立せず、シグナルがそもそも出にくくなります
- 出来高データがない銘柄・市場では、フィルター2が正しく機能しません。FXペアなど出来高の概念がない市場では出来高フィルターを外す調整が必要です
- 時間足を大きく変えて使い回すなら、ATR・MA・クロス回数の各期間を時間足ごとに調整してください。日足用の初期値をそのまま1分足に使うとシグナルの頻度が大きくずれます
まとめ
- 平均回帰トレードは「反発しやすい状況か」を4つのフィルター(スパイク・出来高・MAクロス回数・レンジ)で数値化できる
- 4条件を
andで統合し、成立時にシグナル表示・アラート通知が可能 - ストップロスは直近スイング幅と最低1%のいずれか広い方、利確幅はストップと同じ値幅(1R)で計算できる
- 強いトレンド相場や出来高のない市場では機能しにくいため、実際に使う前にバックテストでの検証が必須
今回のコードをベースに、自分の得意な銘柄・時間足でパラメータを調整しながらバックテストしてみてください。複数の条件を同時にアラート監視したい場合は、現在のプランで足りるかを有料プランの選び方で確認しておくとスムーズです。RSIなど他の指標と組み合わせたい場合はRSIの使い方もあわせてご覧ください。
📊 TradingViewプラン比較
| プラン | 月額 | 主な特徴 |
|---|---|---|
| Basic(無料) | $0 | 1チャート・広告あり・インジケーター3つ |
| Essential | $12.95〜 | 広告なし・インジケーター5つ・アラート20件 |
| Plus ⭐人気 | $24.95〜 | インジケーター10個・アラート100件・同期チャート2つ |
| Premium | $49.95〜 | インジケーター25個・アラート無制限・同期チャート8つ |
まずは無料プランで試して、必要なら有料プランへアップグレード

