株価分析の世界で リターン と一言で呼ばれる値には、実は複数の定義があります。本記事では、もっとも基本的な「単純リターン」と「対数リターン」を、計算式・性質・使い分けの観点から整理します。

目次

  1. 単純リターン
  2. 対数リターン
  3. どちらを使うか
  4. Python で計算する
  5. 期間合算の確認
  6. 年率換算の例

単純リターン

ある日の終値が前日の終値と比べて 何 % 動いたか を表す、もっとも直感的な定義です。

rt=PtPt1Pt1=PtPt11r_t = \frac{P_t - P_{t-1}}{P_{t-1}} = \frac{P_t}{P_{t-1}} - 1
  • PtP_t : 当日の終値
  • Pt1P_{t-1} : 前日の終値

たとえば前日が 1000 円、今日が 1030 円なら、単純リターンは (1030 - 1000) / 1000 = 0.03(3%)です。

期間リターンへの拡張

複数日のリターンを合算するときは、掛け算で連鎖 させます(単純加算ではない点に注意)。

1+RT=(1+r1)(1+r2)(1+rT)1 + R_T = (1 + r_1)(1 + r_2) \cdots (1 + r_T)

たとえば 2 日連続で 10% 上がった場合、合計のリターンは 20% ではなく 1.10 × 1.10 - 1 = 0.21(21%)です。

対数リターン

価格の 対数(自然対数 ln)の差 で定義するリターンです。

t=lnPtPt1=lnPtlnPt1\ell_t = \ln \frac{P_t}{P_{t-1}} = \ln P_t - \ln P_{t-1}

価格が 1000 → 1030 のとき、対数リターンは ln(1030 / 1000) ≒ 0.02956(約 2.956%)。単純リターン 3% より少しだけ小さい値になります。

期間リターンへの拡張(加算で済む)

対数リターンの嬉しさは、複数期間の合算が 足し算で書ける ことです。

1T=1+2++T\ell_{1 \to T} = \ell_1 + \ell_2 + \cdots + \ell_T

これは「日次リターンを年率に換算する」ような場面で計算が楽になります。

どちらを使うか

雑に言えば、次のような使い分けです。

場面推奨
投資家への損益説明単純リターン(直感的、計算した % がそのまま儲け率)
統計モデル・数理ファイナンス対数リターン(加算で扱える、対称性が良い)
ボラティリティ計算対数リターンが慣例
短期・小さい変動どちらもほぼ同じ値(下記の性質)

「短期・小さい変動」で値が近いのは、ln(1+x)x\ln(1 + x) \approx x(xx が 0 に近いとき)という近似によるものです。日次レベルではほとんど差がありません。

Python で計算する

pandas の pct_change で単純リターン、NumPy の log で対数リターンが計算できます。

import numpy as np
import 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_return
0 1000 NaN NaN
1 1030 0.030000 0.029559
2 1020 -0.009709 -0.009756
3 1050 0.029412 0.028988
4 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 * 252
vol_annual = std_log_daily * np.sqrt(252)
print(f"日次平均(対数): {mean_log_daily:.6f}")
print(f"年率平均(対数): {mean_annual:.6f}")
print(f"年率ボラ : {vol_annual:.6f}")

平均は単純に 252 倍、ボラティリティ(標準偏差)は 252\sqrt{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 を日本語で書く

まとめ

  • 単純リターン は「儲け率」をそのまま表す。投資家視点で直感的
  • 対数リターン は加算でつながる。統計処理・年率換算と相性が良い
  • 短期・小さい変動ではほぼ同じ値になる
  • 配当・分割を含む長期分析では 調整済み終値 を必ず使う