出来高プロファイル(Volume Profile)は、時間軸ではなく 価格帯ごとに出来高を積み上げて 表示する分析手法です。本記事では、定義の整理・pandas での簡易実装・チャートとの並列表示までを扱います。
目次
- 出来高プロファイルが示すもの
- 計算の考え方
- サンプルデータの準備
- 価格ビンを作る
- POC と Value Area を計算する
- チャートと並べて描く
- 高安均等分割版
出来高プロファイルが示すもの
通常のチャートは「横軸=時間、縦軸=価格」で、出来高は下段に時系列で並びます。出来高プロファイルは縦軸を価格、横軸を出来高に取り直した 横棒グラフ です。
得られる情報は次のとおりです。
- POC(Point of Control): もっとも出来高が多かった価格帯。「市場が長く滞在した価格」
- VAH / VAL(Value Area High / Low): 全出来高の 70% を含む上下の境界
- High Volume Node / Low Volume Node: 出来高が多い帯 / 少ない帯。サポート・レジスタンス候補
「価格帯にどれだけ売買が積み上がっているか」を直感的に見ることが目的です。時系列だけ見ていると気づきにくい「滞在時間の偏り」を可視化できます。
計算の考え方
最も簡単な方式は、当日の終値が属する価格ビンに、当日の出来高をすべて足す やり方です。
ここで は価格ビン、 は当日の出来高です。
より精緻に分解するなら、当日の高値・安値の幅を均等に分けて出来高を配分する方法もあります(TPO 方式 / 高安均等分割)。本記事は終値ベースの簡易版で進めます。
サンプルデータの準備
import numpy as npimport pandas as pd
rng = np.random.default_rng(seed=99)n = 200returns = rng.normal(loc=0.0003, scale=0.013, size=n)close = 1500 * np.exp(np.cumsum(returns))high = close * (1 + np.abs(rng.normal(scale=0.008, size=n)))low = close * (1 - np.abs(rng.normal(scale=0.008, size=n)))volume = rng.integers(80_000, 600_000, size=n)
ohlc = pd.DataFrame( {"H": high, "L": low, "C": close, "Vo": volume}, index=pd.date_range("2025-08-01", periods=n, freq="B"),)価格ビンを作る
pd.cut で終値を等間隔のビンに割り振ります。
bin_count = 30price_min = ohlc["L"].min()price_max = ohlc["H"].max()edges = np.linspace(price_min, price_max, bin_count + 1)labels = (edges[:-1] + edges[1:]) / 2 # 各ビンの中心価格
ohlc["bin"] = pd.cut( ohlc["C"], bins=edges, labels=labels, include_lowest=True,)
profile = ( ohlc.groupby("bin", observed=True)["Vo"] .sum() .sort_index())print(profile.head(10))observed=True は、Categorical を使ったときに「実データに現れたカテゴリだけ」を集計するためのオプションです。
POC と Value Area を計算する
poc_price = profile.idxmax()poc_volume = profile.max()
# 全体出来高の 70% を含む上下境界 = Value Areatotal = profile.sum()target = total * 0.70
# POC を中心に、両隣のビンを大きい方から取り込んでいくsorted_by_vol = profile.sort_values(ascending=False)acc = 0.0included = []for price, vol in sorted_by_vol.items(): included.append(price) acc += vol if acc >= target: breakval = min(included)vah = max(included)
print(f"POC: {poc_price:.1f} ({poc_volume:,.0f})")print(f"VAL: {val:.1f}")print(f"VAH: {vah:.1f}")「Value Area を POC から両隣に伸ばしていく」アルゴリズムは、より厳密には「左右で出来高が大きい側を 1 ビンずつ取り込む」反復が原典です。簡易版として、出来高上位から 70% に達するまで取り込む方式でも実用的な範囲です。
チャートと並べて描く
価格チャートを左、プロファイルを右に置く 2 列レイアウトです。
import matplotlib.pyplot as plt
fig, (ax_price, ax_vp) = plt.subplots( ncols=2, sharey=True, figsize=(12, 6), gridspec_kw={"width_ratios": [3, 1]},)
ax_price.plot(ohlc.index, ohlc["C"], color="black", linewidth=0.8)ax_price.set_title("C")ax_price.set_xlabel("Date")ax_price.set_ylabel("Price")ax_price.grid(alpha=0.3)
bin_height = (price_max - price_min) / bin_count * 0.9ax_vp.barh( profile.index.astype(float), profile.values, height=bin_height, color="tab:blue", alpha=0.6,)ax_vp.axhline(poc_price, color="red", linewidth=1.0, label="POC")ax_vp.axhline(vah, color="orange", linewidth=0.8, linestyle="--", label="VAH")ax_vp.axhline(val, color="orange", linewidth=0.8, linestyle="--", label="VAL")ax_vp.set_title("Vo Profile")ax_vp.set_xlabel("Vo")ax_vp.legend()ax_vp.grid(alpha=0.3)
plt.tight_layout()plt.savefig("volume_profile.png", dpi=120)plt.close(fig)
sharey=True で価格軸を揃えるのがコツです。プロファイル側は barh で横棒にします。
高安均等分割版
精度を上げる場合、各日の高値〜安値の範囲に出来高を均等分配する方式に切り替えます。
def volume_profile_hl(df: pd.DataFrame, bins: int = 30) -> pd.Series: edges = np.linspace(df["L"].min(), df["H"].max(), bins + 1) centers = (edges[:-1] + edges[1:]) / 2 profile = pd.Series(0.0, index=centers)
for _, row in df.iterrows(): lo, hi, vol = row["L"], row["H"], row["Vo"] # その日が触れた価格ビンに均等分配 mask = (centers >= lo) & (centers <= hi) if mask.sum() == 0: continue profile[centers[mask]] += vol / mask.sum()
return profile
profile_hl = volume_profile_hl(ohlc, bins=30)ビンを跨がない日が出ないよう、ビン数 (bins) は値幅の広さに応じて調整します。終値版と比べると、よりなだらかなプロファイルになります。
注意点
- 約定価格の精度: 簡易版は終値・高安だけを使うため、本来はティックデータ単位で計算する出来高プロファイルとは差が出る
- 期間の選び方: 半年・1 年など期間が長いと滞在価格が偏り、POC が「過去の中心」になる。短い期間で何度も再計算するほうが現状を映す
- イベントの影響: 株式分割・大型決算・配当落ちの前後では価格水準が不連続になり、ビン分割が歪む。調整済み終値を使う
- シグナル化は慎重に: 「POC = サポート」のような単純な解釈は、強いトレンドが出ているときには通用しない
生成AI へのプロンプト例
ロング形式の DataFrame に対し、Code ごとに最終 N 日のプロファイルを返す関数を依頼します。
入力 DataFrame:- columns: Date, Code, H, L, C, Vo
Code ごとに、最新の lookback 日(デフォルト 120)に対する高安均等分配方式の出来高プロファイルを計算し、Code, bin_center, Vo の 3 列の DataFrame を返す関数 volume_profile(df, lookback=120, bins=30) を書いてください。
要件:- pandas 2.2 系- 各 Code 内で日付昇順に整列- bins は Code ごとに [L.min(), H.max()] を等間隔に分割- 末尾に簡単な動作確認サンプルを付けるまとめ
- 出来高プロファイルは「価格帯 × 出来高」の横棒グラフ。滞在時間の偏り が見える
- 簡易版は
pd.cut+groupbyで実装できる - POC・VAH・VAL は出来高プロファイルの代表的な指標
- 高安均等分配にすれば終値版より滑らかになる
- ティック非対応の簡易版である点・期間設定の影響に注意して使う