嘘をつく価格履歴
企業が株式を4分割すると、株主は1株につき4株を受け取り、価格は4分の1になります。誰も損をしていませんが、生の履歴には-75%の日が現れます。現金配当も小さな規模で同じことが起き、権利落ち日に価格は配当額ほど下がります。生の価格を読む戦略は、誰も傷つかなかった暴落を見てしまいます。対策は履歴を調整することです。イベント前のすべての日を再スケールし、系列を連続させて今日の価格と比較できるようにします。
import pandas as pd
index = pd.bdate_range("2026-03-02", periods=6)
raw = pd.Series([480.0, 484.0, 488.0, 123.0, 124.5, 126.0], index=index, name="close") # 4-for-1 split on 5 March
print(raw.pct_change().round(4).tolist())
# [nan, 0.0083, 0.0083, -0.748, 0.0122, 0.012] the -74.8% day never happened to anyone株式分割の調整
変わるのは分割の前の日だけで、価格を比率(4分割なら4)で割ります。現在の価格は取引されたままなので、調整後の系列は実際の現在価格で終わります。index >= split_date で真偽のマスクを作り(文字列は DatetimeIndex と比較できます)、where を使います。where はマスクが真の位置では元の値を残し、それ以外では置換値を採用します。出来高は逆方向で、分割後は4倍の株数が取引されるため、過去の出来高には比率を掛けます。株式併合は1未満の比率で同じ式を使います。
split_date = "2026-03-05"
adjusted = raw.where(raw.index >= split_date, raw / 4) # the days before the split, divided by 4
print(adjusted.tolist()) # [120.0, 121.0, 122.0, 123.0, 124.5, 126.0]
print(adjusted.pct_change().round(4).tolist()) # [nan, 0.0083, 0.0083, 0.0082, 0.0122, 0.012] no more crash# Volume goes the other way: older days are multiplied
volume = pd.Series([1000, 1100, 900, 4200, 4000, 4300], index=index)
print(volume.where(volume.index >= split_date, volume * 4).tolist()) # [4000, 4400, 3600, 4200, 4000, 4300]配当の調整
配当は分割より小さいので、調整は1に近い係数になります。1 - 配当 / 直前の終値 で、直前の終値とは権利落ち日の前の最後の終値です。権利落ち日より前のすべての価格にこの係数を掛けます。すると権利落ち日直前の終値は配当額ちょうどだけ下がり、権利落ち日の値動きは市場が実際にした動きだけを示し、調整後の系列から計算したリターンには配当が含まれます。リターン計算に使うべきなのはこの調整後終値です。係数は小さな専用の関数にして、テストと再利用ができるようにしましょう。
def dividend_factor(prev_close, dividend):
return 1 - dividend / prev_close
prices = pd.Series([100.0, 101.0, 102.0, 100.8, 101.5, 102.5], index=index) # a 1.50 dividend, ex-date 5 March
ex_date, dividend = "2026-03-05", 1.5
prev_close = prices[prices.index < ex_date].iloc[-1] # 102.0, the last close before the ex-date
factor = dividend_factor(prev_close, dividend)
print(round(factor, 6)) # 0.985294
adjusted = prices.where(prices.index >= ex_date, prices * factor)
print(adjusted.round(4).tolist()) # [98.5294, 99.5147, 100.5, 100.8, 101.5, 102.5]
print(prices.pct_change().round(4).tolist()[3], adjusted.pct_change().round(4).tolist()[3]) # -0.0118 0.003リターンには調整後、取引には生の価格調整後価格はリターンの測定と時点間の比較のためのもので、実際に支払う金額ではありません。注文はその日に提示された生の価格で出され、古い調整後価格は当時の実際の取引価格より低くなることがあります。
close と adj_close の両方を残し、各計算がどちらを使うかを明示しましょう。- 分割は過去の価格を比率で割り、過去の出来高に掛ける。変わるのは分割前の日だけ
- 配当は権利落ち日より前の価格に
1 - 配当 / 直前の終値を掛ける - ループではなくマスクで
where(index >= date, 調整後)を使う。リターンは調整後価格で計算し、取引は生の価格で行う
次は matplotlib による折れ線グラフです。きれいになった価格系列を描きます。
ラボ:採点される内容
adjust_for_splitで株式分割をまたいで価格を比較可能にする25点adjust_volume_for_splitで過去の出来高を換算する25点dividend_factorで配当の調整係数を計算する25点adjust_for_dividendで履歴から配当落ちの下げを取り除く25点