VWAPで日本株の仕掛けポイントをPythonで自動検出する方法

Python実装・コード

先日、トヨタ株を買うタイミングを完全に逃した。。。朝イチで「安そう」と思って指値を入れたら、そのまま上昇していってしまった。「なんで僕が買う前に上がるんだ」という、投資家なら誰でも経験したことがある悔しさ。そんな悩みを解決するヒントとして「VWAP」というものに出会った。今日はこれをPythonで実装してみた記録を書く。

そもそも僕がVWAPを調べたきっかけ

子供が生まれてから、日中にチャートを見る時間がほぼゼロになった。朝にざっと注文を入れたら、あとは仕事に集中するしかない生活だ。RSIやMACDは前日の終値ベースで計算できるので朝に確認できるんだけど、「その日の相場の文脈」がまったくわからない。

そこで調べていて出てきたのがVWAP(Volume Weighted Average Price=出来高加重平均価格)。機関投資家が「今日の平均コスト」として意識している価格帯で、「VWAPより下で買えれば割安」「VWAPより上で売れれば割高」という判断ができるらしい。これ、仕事中でも朝に設定しておけば機能するんじゃないか? → 試してみた。

VWAPとは何か(サクッと説明)

VWAPは一言で言うと「その日の取引量で重みをつけた平均株価」だ。単純平均と違って、出来高が多い時間帯の価格が重く反映される。機関投資家はVWAPを基準にして注文を分割することが多く、個人投資家にとっては「プロが意識している水準」として使える。

計算式はシンプルで:

VWAP = Σ(高値+安値+終値)/3 × 出来高) ÷ Σ(出来高)

分足データが必要になるので、日足だけでは計算できない点に注意が必要。

PythonでVWAPを計算する

yfinanceで1分足データを取得してVWAPを計算してみる。yfinanceは直近7日分の1分足が無料で取れるので十分だ。

import yfinance as yf
import pandas as pd
import numpy as np

def calculate_vwap(df):
    """
    1日分のOHLCVデータからVWAPを計算する。
    日をまたがないよう、日ごとにリセットして計算すること。
    """
    df = df.copy()
    # 典型価格(Typical Price)= (高値 + 安値 + 終値) / 3
    df['tp'] = (df['High'] + df['Low'] + df['Close']) / 3
    # 典型価格 × 出来高
    df['tp_vol'] = df['tp'] * df['Volume']
    # 累積計算
    df['cum_tp_vol'] = df['tp_vol'].cumsum()
    df['cum_vol'] = df['Volume'].cumsum()
    # VWAP
    df['VWAP'] = df['cum_tp_vol'] / df['cum_vol']
    return df

# トヨタ(7203.T)の1分足データを取得
ticker = yf.Ticker("7203.T")
df_raw = ticker.history(period="5d", interval="1m")
df_raw.index = pd.to_datetime(df_raw.index)

# 日付ごとにVWAPをリセットして計算(これが超重要)
daily_results = []
for date, group in df_raw.groupby(df_raw.index.date):
    group_with_vwap = calculate_vwap(group)
    daily_results.append(group_with_vwap)

df = pd.concat(daily_results)

# 直近のデータを確認
print(df[['Close', 'VWAP', 'Volume']].tail(20))

実行してみると、こんな感じのデータが取れる(数値はサンプル):

                           Close      VWAP  Volume
2026-06-28 09:00:00+09:00  3210.0  3210.00    8500
2026-06-28 09:01:00+09:00  3215.0  3213.21   12300
2026-06-28 09:02:00+09:00  3208.0  3211.44    9800
...
2026-06-28 15:29:00+09:00  3225.0  3218.73   45200

VWAPクロス戦略をシンプルにバックテストする

VWAPの使い方はいろいろあるけど、最もシンプルな「VWAPクロス戦略」を試してみる。ルールはこれだけ:

・終値がVWAPを上から下に抜けた → 買いシグナル(VWAP割れからの反発を狙う)
・終値がVWAPを下から上に抜けた → 売りシグナル(利確)

def backtest_vwap_strategy(df, initial_capital=1_000_000):
    """
    VWAPクロス戦略の簡易バックテスト。
    VWAP下抜けで買い、上抜けで売り(当日内のみ)。
    """
    df = df.copy()
    # シグナル生成
    df['above_vwap'] = df['Close'] > df['VWAP']
    df['signal'] = 0

    # VWAPを下から上に抜けた → 売り(+1 → 決済)
    # VWAPを上から下に抜けた → 買い(-1 → 仕掛け)
    df['signal'] = df['above_vwap'].astype(int).diff()
    # signal: +1=売り場、-1=買い場

    position = 0
    buy_price = 0
    capital = initial_capital
    trades = []

    for i, row in df.iterrows():
        if row['signal'] == -1 and position == 0:
            # VWAPを下抜け → 買い
            buy_price = row['Close']
            shares = int(capital * 0.1 / buy_price / 100) * 100  # 資金の10%、単元株
            position = shares
        elif row['signal'] == 1 and position > 0:
            # VWAP上抜け → 売り
            sell_price = row['Close']
            pnl = (sell_price - buy_price) * position
            capital += pnl
            trades.append({
                'buy': buy_price, 'sell': sell_price,
                'shares': position, 'pnl': pnl
            })
            position = 0

    if trades:
        df_trades = pd.DataFrame(trades)
        print(f"取引回数: {len(df_trades)}")
        print(f"勝率: {(df_trades['pnl'] > 0).mean():.1%}")
        print(f"合計損益: {df_trades['pnl'].sum():,.0f}円")
        print(f"最終資本: {capital:,.0f}円")
    else:
        print("シグナルなし")

# バックテスト実行
backtest_vwap_strategy(df)

実際に動かしてみた感想と注意点

トヨタで試してみたところ、直近5日間で4〜6回のシグナルが出た。勝率は6割前後といったところで、「まぁそんなもんか」という感じ。ただし注意点がいくつかある:

①yfinanceの分足データは遅延がある
yfinanceは無料なので、1分足データには15〜20分の遅延がある場合がある。リアルタイムトレードには使えない。バックテスト目的と割り切ろう。

②日をまたいでVWAPをリセットしないと意味がない
VWAPは当日のデータのみで計算する。前日のデータを引き継いで計算すると全然違う数値になるので注意。上のコードではgroupby(df_raw.index.date)で日ごとにリセットしている。

③製造業株は出来高が時間帯によって偏る
トヨタなどの大型株は寄り付き(9:00〜9:30)と大引け前(14:30〜15:30)に出来高が集中する。この時間帯はVWAPが激しく動くので、シグナルの信頼性が落ちやすい。

まとめ+Ken個人の感想

VWAPは「その日の相場の重心」を教えてくれる指標として、テクニカル初心者でも理解しやすいと思う。RSIやMACDと違って「当日のコンテキスト」を反映してくれるのが強みだ。

個人的な感想としては、VWAPを単体で使うよりも「VWAPのどちら側にいるか」をRSIのフィルターと組み合わせると精度が上がりそうな気がしている。次は「VWAP+RSIダブルフィルター」を試してみたい。製造業銘柄は出来高のクセがあるので、業種別にチューニングが必要かもしれない。。。

タイトルとURLをコピーしました