RSI+MACDの組み合わせ戦略とは
テクニカル分析において、RSI(Relative Strength Index)とMACD(Moving Average Convergence Divergence)は個人投資家から機関投資家まで広く使われる指標です。それぞれ単体で使うより、組み合わせることでシグナルの精度を高められます。本記事では、Pythonでこの組み合わせ戦略をゼロから実装し、バックテストで実際の勝率を検証する方法を解説します。
RSIとMACDの基本をおさらい
RSI(相対力指数)
RSIは0〜100の値をとり、30以下が売られすぎ(買いシグナル)、70以上が買われすぎ(売りシグナル)の目安です。
MACD(移動平均収束拡散法)
MACDは短期EMA(12日)と長期EMA(26日)の差で、シグナル線(9日EMA)とのクロスで売買タイミングを判断します。MACDがシグナルを上抜けで買い、下抜けで売りが基本です。
Pythonで実装:環境準備
# 必要ライブラリのインストール
# pip install yfinance pandas numpy matplotlib ta
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import ta # Technical Analysis library
株価データの取得とテクニカル指標の計算
def fetch_and_calculate_indicators(ticker: str, period: str = "2y") -> pd.DataFrame:
"""
株価データを取得してRSIとMACDを計算する
Args:
ticker: ティッカーシンボル(例: '7203.T')
period: データ期間(例: '1y', '2y', '5y')
"""
df = yf.download(ticker, period=period, auto_adjust=True)
df = df.dropna()
# RSI計算(14日)
df['RSI'] = ta.momentum.RSIIndicator(df['Close'], window=14).rsi()
# MACD計算(12, 26, 9)
macd_indicator = ta.trend.MACD(df['Close'], window_fast=12, window_slow=26, window_sign=9)
df['MACD'] = macd_indicator.macd()
df['MACD_signal'] = macd_indicator.macd_signal()
df['MACD_hist'] = macd_indicator.macd_diff()
# 移動平均線(トレンド判断用)
df['MA50'] = df['Close'].rolling(50).mean()
df['MA200'] = df['Close'].rolling(200).mean()
return df.dropna()
# 実行例:トヨタ自動車の2年分データ
df = fetch_and_calculate_indicators('7203.T', '2y')
print(df[['Close', 'RSI', 'MACD', 'MACD_signal']].tail(10))
売買シグナルの定義
def generate_signals(df: pd.DataFrame) -> pd.DataFrame:
"""
RSI + MACD の組み合わせシグナルを生成
買い条件: RSI < 45 かつ MACDがシグナルを上抜け
売り条件: RSI > 55 かつ MACDがシグナルを下抜け
"""
df = df.copy()
# MACDクロスの判定
df['MACD_cross_up'] = (
(df['MACD'] > df['MACD_signal']) &
(df['MACD'].shift(1) <= df['MACD_signal'].shift(1))
)
df['MACD_cross_down'] = (
(df['MACD'] < df['MACD_signal']) &
(df['MACD'].shift(1) >= df['MACD_signal'].shift(1))
)
df['signal'] = 0
# 買いシグナル
df.loc[(df['MACD_cross_up'] == True) & (df['RSI'] < 45), 'signal'] = 1
# 売りシグナル
df.loc[(df['MACD_cross_down'] == True) & (df['RSI'] > 55), 'signal'] = -1
return df
df = generate_signals(df)
buy_signals = df[df['signal'] == 1]
sell_signals = df[df['signal'] == -1]
print(f"買いシグナル数: {len(buy_signals)}")
print(f"売りシグナル数: {len(sell_signals)}")
シンプルなバックテストの実装
def simple_backtest(df: pd.DataFrame, initial_capital: float = 1_000_000) -> dict:
"""シンプルなバックテスト(手数料0.1%考慮)"""
capital = initial_capital
position = 0
entry_price = 0.0
commission_rate = 0.001
trades = []
equity_curve = [capital]
for i in range(len(df)):
row = df.iloc[i]
price = float(row['Close'])
signal = row['signal']
# 買いシグナル & ポジションなし
if signal == 1 and position == 0:
shares = int(capital * 0.95 / price / 100) * 100 # 100株単位
if shares > 0:
cost = shares * price * (1 + commission_rate)
capital -= cost
position = shares
entry_price = price
# 売りシグナル & ポジションあり
elif signal == -1 and position > 0:
proceeds = position * price * (1 - commission_rate)
pnl = proceeds - (position * entry_price)
pnl_pct = (price - entry_price) / entry_price * 100
trades.append({'entry': entry_price, 'exit': price, 'pnl': pnl, 'pnl_pct': pnl_pct})
capital += proceeds
position = 0
equity_curve.append(capital + position * price)
if not trades:
return {'error': 'トレードが発生しませんでした'}
trades_df = pd.DataFrame(trades)
total_return = (equity_curve[-1] - initial_capital) / initial_capital * 100
win_rate = len(trades_df[trades_df['pnl'] > 0]) / len(trades_df) * 100
# 最大ドローダウン
equity_series = pd.Series(equity_curve)
drawdown = (equity_series - equity_series.cummax()) / equity_series.cummax() * 100
return {
'total_return': round(total_return, 2),
'win_rate': round(win_rate, 2),
'total_trades': len(trades_df),
'max_drawdown': round(drawdown.min(), 2),
'final_capital': round(equity_curve[-1], 0)
}
results = simple_backtest(df)
print("=== バックテスト結果 ===")
for key, value in results.items():
print(f"{key}: {value}")
バックテスト結果の解釈と改善ポイント
バックテストで確認すべき主要指標:
- 勝率:50%以上が目安。ただし平均利益と平均損失の比率(リスクリワード比)も重要
- 最大ドローダウン:-20%以内が許容範囲の目安
- 総トレード数:統計的有意性のため最低30〜50回以上必要
改善のヒント:RSIの閾値をパラメータ最適化で調整する、MA200超のみ買いに絞るトレンドフィルタを追加するなどが有効です。ただし最適化しすぎるとオーバーフィッティングになるため注意が必要です。
まとめ・次のステップ
RSI+MACDの組み合わせ戦略をPythonでゼロから実装する方法を解説しました。今回のコードをベースに、ボリンジャーバンドを追加したり、複数銘柄で同時テストしたりと発展させてみてください。次のステップとして、backtraderやvectorbtなどの専用バックテストフレームワークを使うと、スリッページや資金管理など、より実践的な検証が可能になります。

