alphalens-reloadedで日本株ファクター分析入門【IC・クワンタイルリターンを見る】

Python実装・コード

「PBR1倍割れ銘柄を買えばいい」とか「ROEが高い株は上がる」とか、ネットで拾ってきたスクリーニング条件をそのまま使っていた時期があった。でも冷静に考えると、そのファクターが本当に効いてるのか確かめたことが一度もない。子供が寝たあとにふとそれが気になって調べ始めたのが alphalens-reloaded だ。ファクターの有効性を定量的に測れるツールで、プロのクオンツが使うやつらしい。

alphalens-reloadedとは

もともとQuantopianが開発した alphalens を、現在もメンテされているのが alphalens-reloaded だ。ファクター値(例:PBR)と将来リターンの関係を可視化・数値化してくれる。主な指標は次の2つ。

IC(Information Coefficient、情報係数):ファクター値と翌日・翌週リターンのスピアマン相関係数。+1で完璧な予測、0なら無意味。実用的には平均ICが0.05以上あると「まあ効いてる」とされる。

クワンタイルリターン:銘柄をファクター値で5等分(Q1〜Q5)し、各グループの平均リターンを比べる。Q5(ファクター上位)がQ1(下位)より高ければ、そのファクターは有効といえる。

インストール

pip install alphalens-reloaded yfinance pandas numpy

データ準備:ファクター値と価格データ

今回は「移動平均乖離率」をファクターとして使う。PBRやROEは財務データAPIが必要で手間がかかるので、まず手に入りやすい価格ベースのファクターで動かし方を覚えるのがおすすめだ。

import yfinance as yf
import pandas as pd
import numpy as np
import alphalens

# 分析対象:日本の製造業銘柄10社
tickers_raw = [
    "7203.T",  # トヨタ
    "7267.T",  # ホンダ
    "7011.T",  # 三菱重工
    "6301.T",  # 小松製作所
    "6326.T",  # クボタ
    "7269.T",  # スズキ
    "7270.T",  # SUBARU
    "7261.T",  # マツダ
    "6702.T",  # 富士通
    "6501.T",  # 日立
]

# 2年分の終値取得
raw = yf.download(tickers_raw, period="2y", auto_adjust=True)["Close"]
raw.columns = [t.replace(".T", "") for t in tickers_raw]
raw = raw.dropna(how="all")

print(raw.shape)

ファクター値を計算する(25日移動平均乖離率)

# 25日移動平均からの乖離率を計算
ma25 = raw.rolling(25).mean()
factor_raw = (raw - ma25) / ma25  # 乖離率(プラスなら割高)

# alphalensが期待するフォーマット: MultiIndex (date, asset) の Series
factor_df = factor_raw.stack()
factor_df.index.names = ["date", "asset"]
factor_df.name = "ma25_deviation"
factor_df = factor_df.dropna()

print(factor_df.head())

alphalensに渡す価格データのフォーマット

# 価格データもMultiIndex形式に
prices = raw.copy()
prices.index = pd.to_datetime(prices.index)

# alphalens.utils.get_clean_factor_and_forward_returns でまとめて計算
factor_data = alphalens.utils.get_clean_factor_and_forward_returns(
    factor=factor_df,
    prices=prices,
    quantiles=5,             # Q1〜Q5の5グループ
    periods=(1, 5, 10),      # 1日後・5日後・10日後リターン
    max_loss=0.35            # データ欠損が35%以上の銘柄を除外
)

print(factor_data.head())

ICの計算と可視化

import matplotlib.pyplot as plt

# IC の計算
ic = alphalens.performance.factor_information_coefficient(factor_data)

# 移動平均でトレンドを見やすくする
ic_ma = ic.rolling(20).mean()

fig, ax = plt.subplots(figsize=(12, 4))
ax.bar(ic.index, ic["1D"], color="#38bdf8", alpha=0.5, label="IC (1D)")
ax.plot(ic_ma.index, ic_ma["1D"], color="white", linewidth=1.5, label="IC 20MA")
ax.axhline(0, color="gray", linewidth=0.8)
ax.set_title("移動平均乖離率ファクター IC(1日後リターン)")
ax.set_ylabel("IC")
ax.legend()
plt.tight_layout()
plt.savefig("factor_ic.png", dpi=150)
plt.show()

mean_ic = ic["1D"].mean()
ic_ir = ic["1D"].mean() / ic["1D"].std()  # ICIR(IC安定性の指標)
print(f"平均IC: {mean_ic:.4f}")
print(f"ICIR: {ic_ir:.4f}")

クワンタイルリターンでファクターの有効性を確認

# クワンタイル別平均リターン
mean_ret_by_q = alphalens.performance.mean_return_by_quantile(factor_data)
mean_ret_1d = mean_ret_by_q[0]["1D"] * 100  # %表示

mean_ret_1d.plot(
    kind="bar",
    color="#38bdf8",
    figsize=(8, 4),
    title="クワンタイル別平均1日リターン(移動平均乖離率ファクター)",
    ylabel="平均リターン (%)"
)
plt.xticks(rotation=0)
plt.tight_layout()
plt.savefig("quantile_returns.png", dpi=150)
plt.show()

「Q5(乖離率が高い=割高)のリターンがQ1より低い」なら逆張りファクターとして有効、逆ならモメンタムファクターとして有効と判断できる。実際に試したところ、短期(1日後)では「乖離率が低い方がリターンが高い」逆張り効果が弱く出ていた。

ティアシートで一括確認

# フルのティアシート(IC・クワンタイルリターン・ターンオーバーなど一括表示)
alphalens.tears.create_full_tear_sheet(
    factor_data,
    long_short=True,   # ロングショート前提で計算
    group_neutral=False
)

create_full_tear_sheet を呼ぶだけで、IC時系列・クワンタイルリターン・ターンオーバー分析がまとめて出力される。Jupyter Notebook上で実行すると見やすい。

まとめ

alphalens-reloaded を使えば「このスクリーニング条件、本当に意味あるの?」という疑問を数字で確かめられる。感覚で選んでいたファクターにエビデンスが出るのは気持ちいい。個人的には、次はPBR(割安度)ファクターをjquants APIのデータで計算して、移動平均乖離率と比較してみたいと思っている。

タイトルとURLをコピーしました