昨年 8 月 5 日の東京市場の歴史的な暴落を経験して、今さらながら先達が開発したテクニカル分析の手法を、自分でもプログラムを作って分析できるようにしようと思い、いろいろ調べています。今回は OBV です。
OBV は、各日の総出来高に、その日の価格が高いか低いかによって、プラスまたはマイナスの値が割り当てられます。具体的には、当日の終値が前日の終値より高ければその日の出来高はプラス、低ければマイナスとして前日の OBV に加えて算出します(マイナスの場合は引き算)。
OBV は、一般的に値動きを確認するために利用されます。定義は単純で下記の通りです。(数式表現に MathJax を利用しているため、スマホのブラウザなどでの閲覧では意図したとおりに表示されない場合があります。)
\[ \begin{aligned} &\text{OBV} = \text{OBV}_{prev} + \begin{cases} \text{volume,} & \text{if close} > \text{close}_{prev} \\ \text{0,} & \text{if close} = \text{close}_{prev} \\ -\text{volume,} & \text{if close} < \text{close}_{prev} \\ \end{cases} \\ \end{aligned} \]この指標は、Joseph Granville 氏が 1963 年に出版した著書 Granville's New Key to Stock Market Profits で On-Balance Volume と名付けて紹介して普及させました。日本では「累積騰落出来高」とも呼ばれているようです。
下記の OS 環境で動作確認をしています。
Fedora Linux 41 Workstation | x86_64 | |
Python | 3.13.1 | |
jupyterlab | 4.3.4 | |
matplotlib | 3.10.0 | |
mplfinance | 0.12.10b0 | |
yfinance | 0.2.51 |
以下の作業は JupyterLab 上でおこなっています。
まず、必要なパッケージをインポートして、yfinance でサンプルとする銘柄の日足データを3ヶ月分取得します。
import matplotlib.pyplot as plt import mplfinance as mpf import re import yfinance as yf pattern = re.compile(r'(.+)\.T') #pattern = re.compile(r'\^(.+)') symbol = '8306.T' ticker = yf.Ticker(symbol) df = ticker.history(period='3mo') df.head()
次に OBV を計算ですが、一行一行算出する処理に流用できるようにしたかったので、Pandas らしくない愚直なコーディングをしています。
def calc_obv(r): if r == 0: return 0 obv_prev = list_obv[r - 1] close_prev = df.iloc[r - 1]['Close'] close_curr = df.iloc[r]['Close'] volume_curr = df.iloc[r]['Volume'] if close_prev < close_curr: v_sign = +1 elif close_prev > close_curr: v_sign = -1 else: v_sign = 0 return obv_prev + volume_curr * v_sign list_obv = list() for r in range(len(df)): list_obv.append(calc_obv(r))
最後に mplfinance によるプロットです。ローソク足チャートをプロットするために mplfiance を利用していますが、matplotlib から細かい調節をしたいので、mplfinance だけで済ませようとせずに下記のような回りくどい書き方をしています。
plt.rcParams["font.size"] = 16 fig = plt.figure(figsize=(12, 6)) ax = dict() n = 3 gs = fig.add_gridspec( n, 1, wspace=0.0, hspace=0.0, height_ratios=[2 if i == 0 else 1 for i in range(n)] ) for i, axis in enumerate(gs.subplots(sharex='col')): ax[i] = axis ax[i].grid() apds = [ mpf.make_addplot( list_obv, width=1, color='magenta', ax=ax[2] ), ] mpf.plot( df, type='candle', style='default', volume=ax[1], datetime_format='%m/%d', addplot=apds, xrotation=0, ax=ax[0], ) ax[2].set_ylabel('OBV') try: ax[0].set_title('Daily chart for %s (%s)' % (ticker.info['longName'], symbol)) except KeyError: ax[0].set_title('Daily chart for %s' % symbol) plt.tight_layout() m = pattern.match(symbol) if m: plt.savefig('daily_chart_%s.png' % m.group(1)) else: plt.savefig('daily_chart_%s.png' % symbol) plt.show()
大局的なトレンド、言い換えれば、離れた日の間でこの指標の絶対値の比較をするのは意味がなさそうです。そうではなくて、その時々における価格の動きの方向性あるいは売買の勢いを確認するのに向いているように思います。
関連サイト
- bitWalk's: 【備忘録】パラボリック SAR [2024-09-06]
- bitWalk's: 【備忘録】モメンタムとボリンジャーバンド [2024-08-10]
- bitWalk's: 【備忘録】フィボナッチ・リトレースメント [2024-08-12]
- bitWalk's: 【備忘録】一目均衡表 [2024-08-15]
- bitWalk's: 【備忘録】Wilder の RSI [2024-09-05]
にほんブログ村
#オープンソース