Insights·2026-08-07

RSI・MACD・ボリンジャーバンド — クオンツエージェントが直接呼ぶ5つの指標

テクニカル指標とは、始値・高値・安値・終値・出来高という一次データからもう一段計算して得られる二次的な値である。種類は数百あるが、AIトレーディングエージェントが単一のツールで直接呼び出すのは RSI(14)・MACD(12/26/9)・ボリンジャーバンド(20, 2σ)・SMA(20/50/200)・EMA(20) のちょうど5つで、これらが過熱・トレンド転換・ボラティリティ・長期トレンドを覆う。ただし同じ名前が同じ数字を意味するとは限らない。RSI は平滑化を Wilder 方式(ewm alpha=1/14)で行うか単純移動平均(rolling 14)で行うかで、ボリンジャーバンドは標準偏差を ddof=1 で測るか ddof=0 で測るかで値が分かれる。指標を組み込む前に確認すべきなのは閾値ではなく計算式である。

보조지표 다섯(RSI 14, MACD 12/26/9, 볼린저 20·2σ, SMA·EMA)의 역할을 정리하고 rolling 단순이동평균과 Wilder ewm 두 계산 방식을 나란히 비교한 요약 도식
에이전트가 툴 하나로 부르는 보조지표 다섯과, 같은 이름이 다른 값을 내는 두 계산 방식

テクニカル指標とは何か

チャートを開くとローソク足の上下に何本もの線が敷かれている。それがテクニカル指標であり、価格と出来高からもう一段計算して取り出した二次的な値だ。

元データは一つしかない。1本の足ごとに始値・高値・安値・終値・出来高があり、この5つをまとめて OHLCV と呼ぶ。指標はすべてここから出てくる。新しい情報を加えるのではなく、人間の目がローソク足だけでは読めない性質を数字に変える装置である。

その性質は大きく4つだ。上がりすぎ下がりすぎか(過熱)、方向が変わりつつあるか(トレンド転換)、どれだけ揺れているか(ボラティリティ)、大きな流れはどちらか(長期トレンド)。指標は数百あるが、その多くはこの4つのいずれかを別の方法で測っているにすぎない。

だから最初から何十個も見る必要はない。4つをそれぞれ一つずつ覆うところから始めればよい。

エージェントが直接呼ぶのは5つだけだ

具体的な基準を一つ置こう。香港大学データインテリジェンス研究室(HKUDS)が公開したオープンソースのトレーディングエージェント Vibe-Trading は、自然言語で指示するとデータを取得しバックテストまで走らせる道具だ。このリポジトリを開くと、エージェントが単一のツールで即座に呼ぶ指標はちょうど5つである。

agent/src/tools/technical_indicator_tool.py に定数として書かれている。RSI は 14、MACD は 12・26・9、ボリンジャーバンドは20日に標準偏差2倍、SMA は 20・50・200、EMA は 20 だ。括弧内の数字は計算ウィンドウの長さ、つまり何本分さかのぼるかを表す。

この5つが先の4つをちょうど覆う。RSI が過熱、MACD が転換、ボリンジャーバンドがボラティリティ、SMA と EMA がトレンドを担う。チャート画面には KDJ(9) がもう一つ加わるが、エージェント向けのツール側にはない。

なぜ5つだけなのか。元が同じ OHLCV なので指標同士が強く重なるからだ。ストキャスティクスと RSI は測っている対象が実質同じで、重ねても確信が増えるだけで情報は増えない。5つで止めているのは機能不足ではなく選択と読むのが妥当だ。

指標既定パラメータ測るもの値の範囲
RSI14買われすぎ・売られすぎ0 – 100
MACD12 / 26 / 9トレンド転換の時点価格単位(上限なし)
ボリンジャーバンド20, 2σボラティリティの通路価格単位(上・中・下)
SMA20 / 50 / 200トレンドライン価格単位
EMA20直近加重のトレンドライン価格単位

RSI(14) — 過熱を0から100で測る

RSI は相対力指数(Relative Strength Index)である。直近14本のあいだで上げた日の力と下げた日の力を比べ、一つの数字にまとめる。

計算は4段階だ。第一に前日比の変化量を求める。第二にそれを上げ幅と下げ幅の二手に分ける。第三にそれぞれを14日基準で平均する。第四に平均上げ幅を平均下げ幅で割った値を RS とし、RSI = 100 - 100 / (1 + RS) に入れる。

式の形から値は必ず0と100の間に収まる。14日間上げ続ければ平均下げ幅が0になり RSI は 100、逆なら0だ。実際にはほとんど30から70の間を行き来する。

読み方は慣習である。70より上を買われすぎ、30より下を売られすぎと見る。この二つの数字は計算式から出たものではなく考案者 J. Welles Wilder が定めたもので、銘柄や市場に応じて調整して使うのが普通だ。

落とし穴が一つある。強い上昇トレンドでは RSI が70より上に何週間も留まる。70を超えたら売るという規則を置くと、上昇相場の入口をまるごと逃す。RSI は方向ではなく強度を伝える指標なので、トレンド指標と併せて見る必要がある。

MACD(12/26/9) — 二つの平均の距離で転換を捉える

MACD は移動平均収束拡散である。名前は長いがやることは単純で、速い平均と遅い平均の距離を測る。

値は三つ出る。MACD 線は12日 EMA から26日 EMA を引いたもので、短期平均が長期平均より上なら正、下なら負になる。シグナル線はその MACD 線をさらに9日 EMA で平滑したものだ。ヒストグラムは MACD 線からシグナル線を引いた値で、棒グラフにして二本の線の間隔を目に見えるようにしたものである。

読むのは交差だ。MACD 線がシグナル線を下から上に抜けばゴールデンクロスで買い方向のサインと見る。上から下に抜ければデッドクロスだ。ヒストグラムは交差より少し早くゼロに近づくので、先取りに使える。

MACD 線がゼロを跨ぐことも別に見る。ゼロを上抜けたということは12日平均が26日平均を追い抜いたということで、トレンド自体が反転したサインと読む。

落とし穴は遅行性だ。移動平均はすでに過ぎた価格の平均なので、実際の転換より遅れて反応する。急騰急落の多い資産ではサインが後から出て、横ばい区間では交差が無意味に繰り返される。ウィンドウを短くすれば速くなるがノイズも一緒に増える。

ボリンジャーバンド(20, 2σ) — ボラティリティで通路を描く

ボリンジャーバンドは三本の線からなる。中心線は20日単純移動平均、上限はそこに20日標準偏差の2倍を足したもの、下限は引いたものだ。価格はその間を通る通路のように見える。

肝心なのは通路の幅が固定ではないことだ。標準偏差はボラティリティの大きさなので、価格が激しく揺れればバンドは広がり、静かなら狭まる。つまりこの指標が本当に示しているのは価格の位置ではなくボラティリティである。

だから実戦で最もよく見られるのがスクイーズだ。バンド幅が直近の区間に比べて際立って狭くなればボラティリティが死んだということで、たいていその後に一方向へ大きく動く。方向は教えず大きさだけを予告する。

標準偏差2倍という数字にも根拠がある。値が正規分布に従うなら平均 ± 2標準偏差の中に約95%が入る。ただし実際の価格変動は正規分布ではなく裾が厚いため、バンドの外に出ることが理論値よりはるかに頻繁に起きる。

したがってバンドタッチ自体はサインではない。上限に触れたら売るという規則は強い上昇相場で外れ続ける。バンドに沿って上がる現象にはバンドウォークという別名があるほどだ。バンドは位置の判断ではなくボラティリティ局面の判断に使うのが妥当である。

SMA(20/50/200)・EMA(20) — 最も古く最もよく使うトレンドライン

SMA は単純移動平均だ。直近N日の終値をそのまま足してNで割る。20日線は約1か月、50日線は約1四半期、200日線はおよそ1年の営業日にあたる。

200日線が特別扱いされる理由は計算式ではなく慣習である。多くの機関がこの線を長期トレンドの基準に使うため、価格が200日線の上にあるか下にあるかが、それ自体で市場参加者の行動に影響する。

EMA は指数移動平均だ。SMA が20日分を同じ重みで扱うのに対し、EMA は直近の価格により大きな重みを与える。古い価格の影響が指数的に減るため方向転換に速く反応する。その代わりノイズにも速く反応する。

二本の線を重ねる慣習がゴールデンクロスとデッドクロスだ。短い平均線が長い平均線を上抜けばゴールデンクロス、下抜けばデッドクロスである。よく使われる組み合わせが50日線と200日線だ。

落とし穴は先の MACD と同じである。平均は過ぎた値なので必ず遅れる。ゴールデンクロスは上昇がすでにかなり進んだ後に出ることが多く、もみ合い区間では二本の線が絡んでサインが立て続けに反転する。

pandas で5つすべてを自分で計算する

ライブラリを別途入れなくても pandas だけで5つとも出せる。入力は終値ひとつで、5つの関数はいずれも10行以内に収まる。

下のコードを indicators.py として保存し、終値の時系列(pandas Series)を渡せばよい。終値は yfinance や pykrx のようなライブラリで取得してもよいし、証券会社から受け取った CSV を pandas で読んでもよい。

ewm の adjust=False が重要だ。既定値の True は初期区間を補正する別の式を使うため、これを落とすと先頭数十本の EMA が他のツールと合わなくなる。

関数を作り終えたら値が合うか一度確認しておくとよい。同じ銘柄を証券アプリや TradingView に表示し、同じ日付の RSI を比べればよい。このとき数字が合わないことがあるが、その理由が次節である。

indicators.py
import pandas as pd


def rsi(close: pd.Series, period: int = 14) -> pd.Series:
    delta = close.diff()
    gain = delta.clip(lower=0)
    loss = (-delta).clip(lower=0)
    avg_gain = gain.ewm(alpha=1 / period, adjust=False).mean()
    avg_loss = loss.ewm(alpha=1 / period, adjust=False).mean()
    return 100 - 100 / (1 + avg_gain / avg_loss)


def macd(close, fast=12, slow=26, signal=9):
    line = (close.ewm(span=fast, adjust=False).mean()
            - close.ewm(span=slow, adjust=False).mean())
    sig = line.ewm(span=signal, adjust=False).mean()
    return pd.DataFrame({"macd": line, "signal": sig, "hist": line - sig})


def bollinger(close, period=20, num_std=2.0, ddof=0):
    mid = close.rolling(period).mean()
    sd = close.rolling(period).std(ddof=ddof)
    return pd.DataFrame({"upper": mid + num_std * sd,
                         "middle": mid,
                         "lower": mid - num_std * sd})


def sma(close, period):
    return close.rolling(period).mean()


def ema(close, period):
    return close.ewm(span=period, adjust=False).mean()
使い方
import yfinance as yf
from indicators import rsi, macd, bollinger, sma, ema

close = yf.download("AAPL", period="1y")["Close"].squeeze()

print("RSI(14) :", round(rsi(close).iloc[-1], 2))
print("MACD    :", macd(close).iloc[-1].round(4).to_dict())
print("BB(20,2):", bollinger(close).iloc[-1].round(2).to_dict())
print("SMA200  :", round(sma(close, 200).iloc[-1], 2))
print("EMA20   :", round(ema(close, 20).iloc[-1], 2))

同じ名前が同じ数字ではない — RSI 平滑化の二系統

ここが本稿で最も重要な箇所だ。RSI 14 と書かれていてもツールごとに値が違うことがある。第三段階、つまり上げ幅と下げ幅を平均する方法が二系統あるからだ。

一つは Wilder 方式である。考案者が本来提示した方法で、指数加重移動平均に alpha = 1 / 14 を与える。過去の値が完全には消えず少しずつ残り続ける。TA-Lib がこの方式だ — ソース ta_RSI.c の注釈が "Wilder's approach" と記し、直前の平均に period-1 を掛けて当日の値を足し period で割る(2026-08-07 ソース確認)。

もう一つは単純移動平均方式だ。直近14日だけを同じ重みで平均し15日前の値は捨てる。Cutler's RSI という別名があるほど別の指標として扱われる。値は Wilder 方式より敏感に振れ、計算ウィンドウから外れる値が急に抜けることで飛ぶこともある。

これが他人事でないことを、先に見た Vibe-Trading のリポジトリが示している。指標ツール technical_indicator_tool.py の RSI 関数は rolling(14).mean() で計算する。ところが同じリポジトリの戦略スキル文書 technical-basic/SKILL.md は、RSI と ADX が Wilder EWM すなわち ewm(alpha=1/period) を使うと明記している。一つのリポジトリの中で二つの方式が共存している(2026-08-07 ソース確認)。

どちらが間違いという話ではない。どちらも実際に使われている定義だ。問題はこの違いを知らないまま一方でバックテストし他方で実売買すると、同じ規則なのに入る時点が変わることにある。RSI が 69.4 か 71.2 かが売買条件なら、その差はそのまま別の結果である。

二系統を並べて差を見る
wilder = gain.ewm(alpha=1 / 14, adjust=False).mean()   # Wilder 원본 · TA-Lib ta_RSI.c
cutler = gain.rolling(14).mean()                       # Cutler's RSI · 単純移動平均

# 同じ終値から二つの RSI を作り最後の値を比べる
print(round(rsi_wilder(close).iloc[-1], 2),
      round(rsi_cutler(close).iloc[-1], 2))

ボリンジャーバンドも同じ — 標準偏差の自由度 ddof

標準偏差を求めるとき、偏差平方の和を何で割るかが二系統ある。標本数 n で割れば母標準偏差(ddof=0)、n - 1 で割れば標本標準偏差(ddof=1)だ。統計学では標本から母集団を推定する際に n - 1 を使うのが慣習である。

pandas の rolling(20).std() は既定値が ddof=1 だ。引数を何も与えなければ標本標準偏差が出るということである。

TA-Lib は違う。ソースの ta_BBANDS.c を見るとバンド幅の計算が ta_VAR.c の分散式に降りていき、その式が variance = sum(x²)/n - mean² である。n で割る母分散なので ddof=0 だ(2026-08-07 ソース確認)。

差は計算できる。標本標準偏差は母標準偏差に sqrt(n / (n - 1)) を掛けた値だ。n が20なら sqrt(20 / 19) = 1.0260 なので、pandas の既定値で描いたバンドは TA-Lib で描いたバンドより半幅が 2.60% 広い。

2.60% は小さく見えるが、バンドタッチを売買条件にしていれば話が変わる。価格がバンド付近にある日には、一方では条件が成立し他方では成立しない。バックテストの結果が実売買と合わないとき、戦略を疑う前にここから見る必要がある理由だ。

合わせ方は簡単である。どちらを使ってもかまわないがバックテストと実売買が一致していなければならないので、コードに ddof を明示しておく。前節の bollinger 関数に ddof=0 を既定値として入れてあるのはその意味だ。

ddof の差を目で確認する
sd_sample = close.rolling(20).std()          # pandas 既定値 · ddof=1
sd_pop = close.rolling(20).std(ddof=0)       # TA-Lib と同じ母標準偏差

print(round(sd_sample.iloc[-1] / sd_pop.iloc[-1], 4))   # 1.026 = sqrt(20 / 19)

指標を組み込む前のチェックリスト

第一に、ウィンドウ長を明示する。RSI 14、MACD 12/26/9、ボリンジャー 20 といった値は既定値にすぎずツールごとに異なりうる。コードに引数として書いておけば、後で値が合わないときに原因を絞り込める。

第二に、平滑化方式を確認する。RSI や ADX のように Wilder が作った指標は ewm(alpha=1/period) が本来の定義だ。ライブラリの文書に何と書かれていようと、ソースで rolling か ewm かを直接見る。1分あれば済む。

第三に、ddof を明示する。標準偏差を使うすべての指標に当てはまる。ボリンジャーバンドだけでなくボラティリティ自体を指標として使う場合にも同じ問題が起きる。

第四に、EMA の adjust を確認する。pandas ewm の既定値 adjust=True は初期区間を別に計算する。他のツールと合わせるなら adjust=False だ。

第五に、指標一つで売買規則を作らない。先に見た Vibe-Trading の technical-basic スキルも、トレンド(EMA と ADX)、平均回帰(ボリンジャーバンドと RSI)、出来高(OBV と出来高比率)の三軸をそれぞれ計算したうえで投票により一つのシグナルにまとめる。三軸が同じ方向を指すときだけ入り、食い違えば見送る構造だ。

まとめるとこうなる。テクニカル指標を学ぶことの半分は各指標が何を測るかを知ることであり、残りの半分は自分の使う道具がそれをどう計算するかを知ることだ。二つ目を飛ばすと、数字は出るのにその数字が何を意味するのか分からない状態になる。