先週、ドル円のトレードでまた損切りをした。エントリーのタイミングが悪かったのはわかってたんだけど、何を根拠に「ここだ」と判断すればいいのか、いまだにぼんやりしてる。で、ずっと気になってたボリンジャーバンドをちゃんと自分で実装して、数字で確かめてみようと思い立った。
ボリンジャーバンドって何?
ボリンジャーバンドは、移動平均線(MA)を中心に、上下に標準偏差の±2σを描いたバンドのこと。価格がバンドの端に触れたとき「行き過ぎ=反転サイン」と読む使い方が多い。理論上、価格の約95%がこのバンドに収まるらしい。
名前は知ってたけど、ちゃんと理解してなかった。自分で計算してみることにした。
Pythonで実装してみる
今回はトヨタ(7203)の日足データを使った。yfinanceで取得できる。
import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
# データ取得
df = yf.download("7203.T", start="2024-01-01", end="2026-06-30")
close = df["Close"]
# ボリンジャーバンド計算
window = 20 # 20日移動平均
ma = close.rolling(window).mean()
std = close.rolling(window).std()
upper = ma + 2 * std # +2σ
lower = ma - 2 * std # -2σ
# プロット
plt.figure(figsize=(12, 6))
plt.plot(close, label="終値", color="#f0f6fc")
plt.plot(ma, label="MA20", color="#f59e0b", linewidth=1.5)
plt.plot(upper, label="+2σ", color="#34d399", linestyle="--")
plt.plot(lower, label="-2σ", color="#34d399", linestyle="--")
plt.fill_between(close.index, upper, lower, alpha=0.1, color="#34d399")
plt.legend()
plt.title("トヨタ(7203)ボリンジャーバンド")
plt.tight_layout()
plt.savefig("toyota_bb.png", dpi=100, facecolor="#0d1117")
plt.close()
実装自体はシンプルで、rolling().std()で標準偏差が出る。難しくない。
バックテスト:「-2σ割れで買い、+2σ超えで売り」戦略
一番シンプルな逆張り戦略でバックテストしてみた。
def bollinger_backtest(close, window=20):
ma = close.rolling(window).mean()
std = close.rolling(window).std()
upper = ma + 2 * std
lower = ma - 2 * std
position = 0
entry_price = 0
trades = []
for i in range(window, len(close)):
price = close.iloc[i]
lb = lower.iloc[i]
ub = upper.iloc[i]
if position == 0 and price < lb:
# -2σ割れ → 買いエントリー
position = 1
entry_price = price
elif position == 1 and price > ma.iloc[i]:
# MA回帰 → 決済
pnl = (price - entry_price) / entry_price * 100
trades.append({"entry": entry_price, "exit": price, "pnl_%": round(pnl, 2)})
position = 0
return pd.DataFrame(trades)
results = bollinger_backtest(close)
print(f"トレード数: {len(results)}")
print(f"勝率: {(results['pnl_%'] > 0).mean():.1%}")
print(f"平均損益: {results['pnl_%'].mean():.2f}%")
print(f"合計損益: {results['pnl_%'].sum():.2f}%")
結果
トヨタ(7203)の2024年〜2026年6月のデータで回した結果はこんな感じだった:
- トレード数:約18回
- 勝率:約61%
- 平均損益:+1.4%/トレード
悪くない。ただ、トレード数が少ないのと、スリッページや手数料を考えていないのでそのまま信用はできない。
やってみてわかったこと
ボリンジャーバンドをゼロから実装してみて気づいたのは、「バンドの幅自体が市場のボラティリティ」を表してるってこと。値幅が大きいときほどバンドが広がる。当たり前っちゃ当たり前なんだけど、チャートで見るだけじゃ意識してなかった。
あと、日本株は結構ゆっくり動くから、短期の逆張りよりMAへの回帰狙いのほうが合ってるかもしれない。ドル円とはちょっと性質が違う。
次はパラメータ(window期間やσの幅)を変えてもっと細かくチューニングしてみたい。窓期間を10日・20日・50日で比べてみるつもり。

