株価分析の世界で リターン と一言で呼ばれる値には、実は複数の定義があります。本記事では、もっとも基本的な「単純リターン」と「対数リターン」を、計算式・性質・使い分けの観点から整理します。
目次
- 単純リターン
- 対数リターン
- どちらを使うか
- Python で計算する
- 期間合算の確認
- 年率換算の例
単純リターン
ある日の終値が前日の終値と比べて 何 % 動いたか を表す、もっとも直感的な定義です。
- : 当日の終値
- : 前日の終値
たとえば前日が 1000 円、今日が 1030 円なら、単純リターンは (1030 - 1000) / 1000 = 0.03(3%)です。
期間リターンへの拡張
複数日のリターンを合算するときは、掛け算で連鎖 させます(単純加算ではない点に注意)。
たとえば 2 日連続で 10% 上がった場合、合計のリターンは 20% ではなく 1.10 × 1.10 - 1 = 0.21(21%)です。
対数リターン
価格の 対数(自然対数 ln)の差 で定義するリターンです。
価格が 1000 → 1030 のとき、対数リターンは ln(1030 / 1000) ≒ 0.02956(約 2.956%)。単純リターン 3% より少しだけ小さい値になります。
期間リターンへの拡張(加算で済む)
対数リターンの嬉しさは、複数期間の合算が 足し算で書ける ことです。
これは「日次リターンを年率に換算する」ような場面で計算が楽になります。
どちらを使うか
雑に言えば、次のような使い分けです。
| 場面 | 推奨 |
|---|---|
| 投資家への損益説明 | 単純リターン(直感的、計算した % がそのまま儲け率) |
| 統計モデル・数理ファイナンス | 対数リターン(加算で扱える、対称性が良い) |
| ボラティリティ計算 | 対数リターンが慣例 |
| 短期・小さい変動 | どちらもほぼ同じ値(下記の性質) |
「短期・小さい変動」で値が近いのは、( が 0 に近いとき)という近似によるものです。日次レベルではほとんど差がありません。
Python で計算する
pandas の pct_change で単純リターン、NumPy の log で対数リターンが計算できます。
import numpy as npimport pandas as pd
# サンプル: 5 日分の終値prices = pd.Series([1000, 1030, 1020, 1050, 1080], name="C")
# 単純リターンsimple_return = prices.pct_change()
# 対数リターンlog_return = np.log(prices / prices.shift(1))# あるいは np.log(prices).diff() でも同じ
df = pd.DataFrame({ "C": prices, "simple_return": simple_return, "log_return": log_return,})print(df.round(6))実行結果(イメージ):
C simple_return log_return0 1000 NaN NaN1 1030 0.030000 0.0295592 1020 -0.009709 -0.0097563 1050 0.029412 0.0289884 1080 0.028571 0.028171最初の行は前日が無いので NaN(計算不能)になります。
期間合算の確認
両者の合算ルールが正しいことを Python で確かめます。
# 単純リターン: 連鎖total_simple = (1 + simple_return.dropna()).prod() - 1# 対数リターン: 加算total_log = log_return.dropna().sum()
# 価格の比率からの直接計算total_direct = prices.iloc[-1] / prices.iloc[0] - 1
print(f"単純リターンの連鎖: {total_simple:.6f}")print(f"対数リターンの合計: {total_log:.6f}")print(f"対数→単純に変換 : {np.expm1(total_log):.6f}")print(f"価格比から直接 : {total_direct:.6f}")単純リターンの連鎖: 0.080000対数リターンの合計: 0.076961対数→単純に変換 : 0.080000価格比から直接 : 0.080000「対数リターンの合計」を expm1(= exp - 1)で単純リターンに戻すと、ぴったり一致します。
年率換算の例
日次リターンから年率を出すときの慣例は次の通りです。営業日数は 1 年あたり約 252 日とします。
mean_log_daily = log_return.mean()std_log_daily = log_return.std()
mean_annual = mean_log_daily * 252vol_annual = std_log_daily * np.sqrt(252)
print(f"日次平均(対数): {mean_log_daily:.6f}")print(f"年率平均(対数): {mean_annual:.6f}")print(f"年率ボラ : {vol_annual:.6f}")平均は単純に 252 倍、ボラティリティ(標準偏差)は 倍します。これは対数リターンが独立同分布に近い前提でのみ正しい近似ですが、実務では出発点として広く使われます。
注意点
- 配当・株式分割を加味する場合は調整済み終値 を使うこと(調整なしだと、分割の日に大きな偽のリターンが出ます)
- 株価が 0 や負の値 にはならないので、対数リターンは常に定義できます。ただし、レバレッジ商品の累積価格や CFD などでは注意が必要です
- 「リターンの平均」と「リターンを年率換算した値」は別物です。混同しないように
生成AI へのプロンプト例
リターン計算とまとめて分布の可視化まで行いたい場合の例です。
pandas Series として渡された日次終値から、次の処理を行う関数 compute_returns(prices) を書いてください。
戻り値: 次の列を持つ DataFrame- simple_return: 単純リターン- log_return: 対数リターン- cum_simple: 単純リターンの累積(初日を 0 として連鎖)- cum_log: 対数リターンの累積(累計の和)
要件:- 入力に NaN を含むデータでも壊れない- pandas 2.2 系の API を使う- docstring を日本語で書くまとめ
- 単純リターン は「儲け率」をそのまま表す。投資家視点で直感的
- 対数リターン は加算でつながる。統計処理・年率換算と相性が良い
- 短期・小さい変動ではほぼ同じ値になる
- 配当・分割を含む長期分析では 調整済み終値 を必ず使う