mcpField
S
stock-correlation

stock-correlation

github.com/himself65データ・データベース3.5k3.6k 回インストール3 日前に更新
リポジトリ

stock-correlation について

stock-correlation は、yfinance 経由で Yahoo Finance の過去価格を使って株式の関係を分析するスキルです。依頼に応じて、連動銘柄の探索、ペア分析、グループ分類、期間別・相場環境別の相関分析に振り分けます。

主な機能

  1. 01対象銘柄と連動する株式の探索
  2. 02指定銘柄間のリターン相関の計算
  3. 03相関行列と銘柄クラスターの作成
  4. 04ローリング相関と相場環境別の分析
  5. 05初期設定と結果解釈のガイド

活用シーン

  1. 01特定銘柄と連動する株式の探索
  2. 022銘柄の相関や回帰指標の比較
  3. 03株式グループの関係や外れ値の把握
  4. 04下落時や高ボラティリティ時の変化の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/himself65/finance-skills --skill stock-correlation

インストール後、Claude Code で/stock-correlationを入力して読み込まれたか確認します。

同梱ファイルREADME.mdreferences/sector_universes.md

詳細

株価相関分析スキル

ホストが以下のシェルプローブをまだ実行していない場合(たとえば、Codex の場合)、セットアップ方法を選ぶ前に、シェルツールで ! ラッパー内のコマンドを実行してください。実際の出力を使用してください。シェルにアクセスできない場合は、その制限を報告してください。

yfinance を介して Yahoo Finance の過去の株価データを使用し、相関する銘柄を見つけて分析します。ユーザーの意図に応じて、専門のサブスキルに振り分けます。

重要:このスキルは調査および教育目的のみです。投資助言ではありません。yfinance は Yahoo, Inc. と提携していません。


ステップ 1:依存関係が利用可能であることを確認する

現在の環境の状態:

!`python3 -c "exec('try:\n import yfinance, pandas, numpy\n print(f\'yfinance={yfinance.__version__} pandas={pandas.__version__} numpy={numpy.__version__}\')\nexcept Exception:\n print(\'DEPS_MISSING\')')"`

DEPS_MISSING の場合は、コードを実行する前に必要なパッケージをインストールしてください。

import subprocess, sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "yfinance", "pandas", "numpy"])

すべての依存関係がすでにインストールされている場合は、インストール手順をスキップして、そのまま次に進んでください。


ステップ 2:適切なサブスキルに振り分ける

ユーザーのリクエストを分類し、以下の該当するサブスキルのセクションに進んでください。

ユーザーのリクエスト振り分け先例
単一のティッカーについて、関連する銘柄を探したいサブスキル A:連動銘柄の探索「NVDA と相関する銘柄は?」「AMD の関連銘柄を探して」「TSLA の連れ高・連れ安銘柄」
2 つ以上の特定ティッカーについて、関係の詳細を知りたいサブスキル B:リターン相関「AMD と NVDA の相関」「LITE と COHR はどのように連動する?」「AAPL と MSFT を比較」
ティッカーのグループについて、構造やグループ分けを知りたいサブスキル C:セクターのクラスター分析「FAANG の相関行列」「これらの半導体株をクラスター化して」「AMD のセクターピア」
時間とともに変化する相関や条件付き相関を知りたいサブスキル D:実現相関「AMD と NVDA のローリング相関」「NVDA が下落したとき、他に何が下落する?」「相関はどう変化した?」

曖昧な場合は、単一のティッカーならデフォルトで サブスキル A(連動銘柄の探索)、2 つのティッカーなら サブスキル B(リターン相関)を選択してください。

すべてのサブスキルに共通するデフォルト値
パラメーターデフォルト
参照期間1y(1 年)
データ間隔1d(日次)
相関手法Pearson
最小相関しきい値0.60
結果数上位 10 件
リターンの種類日次対数リターン
ローリング期間60 取引日

サブスキル A:連動銘柄の探索

目標:単一のティッカーを指定して、それと連動する銘柄を見つけます。

A1:ピア銘柄の候補群を作成する

候補を 15~30 銘柄用意してください。ハードコードされたティッカーリストは使用しないでください。実行時に動的に候補群を作成します。完全な実装については references/sector_universes.md を参照してください。手順は次のとおりです。

  1. yf.screen() と yf.EquityQuery を使用して同じ業種の銘柄をスクリーニングし、対象と同じ業種の銘柄を見つける
  2. 業種のスクリーニングでピア銘柄が 10 未満の場合は、セクターまで対象を広げる
  3. テーマや隣接業種の銘柄を追加する — 対象の longBusinessSummary を読み、関連する 1~2 業種をスクリーニングする(例:半導体企業なら、半導体製造装置もスクリーニングする)
  4. 結果を統合し、重複を除き、対象のティッカーを削除する
A2:相関を計算する
import yfinance as yf
import pandas as pd
import numpy as np

def discover_comovement(target_ticker, peer_tickers, period="1y"):
    all_tickers = [target_ticker] + [t for t in peer_tickers if t != target_ticker]
    data = yf.download(all_tickers, period=period, auto_adjust=True, progress=False)

    # Extract close prices — yf.download returns MultiIndex (Price, Ticker) columns
    closes = data["Close"].dropna(axis=1, thresh=max(60, len(data) // 2))

    # Log returns
    returns = np.log(closes / closes.shift(1)).dropna()
    corr_series = returns.corr()[target_ticker].drop(target_ticker, errors="ignore")

    # Rank by absolute correlation
    ranked = corr_series.abs().sort_values(ascending=False)

    result = pd.DataFrame({
        "Ticker": ranked.index,
        "Correlation": [round(corr_series[t], 4) for t in ranked.index],
    })
    return result, returns
A3:結果を提示する

会社名とセクターを含む順位付きの表を示します(yf.Ticker(t).info.get("shortName") で取得)。以下の値は例示です。

順位ティッカー会社名相関関連する理由
1AMDAdvanced Micro Devices0.82同じ業種 — GPU/CPU
2AVGOBroadcom0.78AI インフラのピア銘柄

以下を含めてください。

  • 正の相関が高い上位 10 銘柄
  • 注目すべき負の相関銘柄(ヘッジ候補)
  • それぞれが関連する可能性がある理由の簡潔な説明(セクター、サプライチェーン、顧客の重複)

サブスキル B:リターン相関

目標:2 つ(または少数)の特定ティッカー間の関係を詳しく分析します。

B1:データをダウンロードして計算する
import yfinance as yf
import pandas as pd
import numpy as np

def return_correlation(ticker_a, ticker_b, period="1y"):
    data = yf.download([ticker_a, ticker_b], period=period, auto_adjust=True, progress=False)
    closes = data["Close"][[ticker_a, ticker_b]].dropna()

    returns = np.log(closes / closes.shift(1)).dropna()
    corr = returns[ticker_a].corr(returns[ticker_b])

    # Beta: how much does B move per unit move of A
    cov_matrix = returns.cov()
    beta = cov_matrix.loc[ticker_b, ticker_a] / cov_matrix.loc[ticker_a, ticker_a]

    # R-squared
    r_squared = corr ** 2

    # Rolling 60-day correlation for stability
    rolling_corr = returns[ticker_a].rolling(60).corr(returns[ticker_b])

    # Spread (log price ratio) for mean-reversion
    spread = np.log(closes[ticker_a] / closes[ticker_b])
    spread_z = (spread - spread.mean()) / spread.std()

    return {
        "correlation": round(corr, 4),
        "beta": round(beta, 4),
        "r_squared": round(r_squared, 4),
        "rolling_corr_mean": round(rolling_corr.mean(), 4),
        "rolling_corr_std": round(rolling_corr.std(), 4),
        "rolling_corr_min": round(rolling_corr.min(), 4),
        "rolling_corr_max": round(rolling_corr.max(), 4),
        "spread_z_current": round(spread_z.iloc[-1], 4),
        "observations": len(returns),
    }
B2: 結果を提示する

要約カードを表示します(以下は説明用の値です)。

指標値
ピアソン相関係数0.82
ベータ(B 対 A)1.15
R-squared0.67
ローリング相関(60 日平均)0.80
ローリング相関の範囲[0.55, 0.94]
ローリング相関の標準偏差0.08
スプレッドの Z スコア(現在)+1.2
観測数250

解釈の目安:

  • 相関 > 0.80:強い連動性 — これらの株式は密接に連動しています
  • 相関 0.50–0.80:中程度 — 共通のセクター要因がありますが、独自の要因もあります
  • 相関 < 0.50:弱い — セクターの重複があっても連動性は限定的です
  • ローリング相関の標準偏差が高い:関係が不安定 — 相関が時間とともに大きく変動します
  • スプレッドの Z スコア > |2|:過去の関係性から見て異例の乖離です

サブスキル C:セクターのクラスター分析

目的:ティッカーのグループを受け取り、相関構造全体を示してクラスターを特定します。

C1: 相関行列を作成する
import yfinance as yf
import pandas as pd
import numpy as np

def sector_clustering(tickers, period="1y"):
    data = yf.download(tickers, period=period, auto_adjust=True, progress=False)

    # yf.download returns MultiIndex (Price, Ticker) columns
    closes = data["Close"].dropna(axis=1, thresh=max(60, len(data) // 2))
    returns = np.log(closes / closes.shift(1)).dropna()
    corr_matrix = returns.corr()

    # Hierarchical clustering order
    from scipy.cluster.hierarchy import linkage, leaves_list
    from scipy.spatial.distance import squareform

    dist_matrix = 1 - corr_matrix.abs()
    np.fill_diagonal(dist_matrix.values, 0)
    condensed = squareform(dist_matrix)
    linkage_matrix = linkage(condensed, method="ward")
    order = leaves_list(linkage_matrix)
    ordered_tickers = [corr_matrix.columns[i] for i in order]

    # Reorder matrix
    clustered = corr_matrix.loc[ordered_tickers, ordered_tickers]

    return clustered, returns

注:scipy を利用できない場合は、階層的クラスタリングの代わりに平均相関で並べ替えます。

C2: 結果を提示する
  1. 相関行列全体 — 表形式で示します。ティッカーが 8 個を超える場合は、ヒートマップの説明を示すか、最も強い/弱いペアのみを取り上げます。

  2. 特定されたクラスター — グループ内相関の高いティッカーをまとめます:

    • クラスター 1:[NVDA, AMD, AVGO] — グループ内平均相関 0.82
    • クラスター 2:[AAPL, MSFT] — グループ内平均相関 0.75
  3. 外れ値 — グループとの平均相関が低いティッカー(分散投資の候補)。

  4. 最も強いペア — 行列内で相関が最も高い上位 5 ペア。

  5. 最も弱いペア — 相関が最も低い、または負の上位 5 ペア(ヘッジ候補)。


サブスキル D:実現相関

目的:相関が時間の経過や市場環境によってどのように変化するかを示します。

D1: ローリング相関
import yfinance as yf
import pandas as pd
import numpy as np

def realized_correlation(ticker_a, ticker_b, period="2y", windows=[20, 60, 120]):
    data = yf.download([ticker_a, ticker_b], period=period, auto_adjust=True, progress=False)
    closes = data["Close"][[ticker_a, ticker_b]].dropna()

    returns = np.log(closes / closes.shift(1)).dropna()

    rolling = {}
    for w in windows:
        rolling[f"{w}d"] = returns[ticker_a].rolling(w).corr(returns[ticker_b])

    return rolling, returns
D2: レジーム別の条件付き相関
def regime_correlation(returns, ticker_a, ticker_b, condition_ticker=None):
    """Compare correlation across up/down/volatile regimes."""
    if condition_ticker is None:
        condition_ticker = ticker_a

    ret = returns[condition_ticker]

    regimes = {
        "All Days": pd.Series(True, index=returns.index),
        "Up Days (target > 0)": ret > 0,
        "Down Days (target < 0)": ret < 0,
        "High Vol (top 25%)": ret.abs() > ret.abs().quantile(0.75),
        "Low Vol (bottom 25%)": ret.abs() < ret.abs().quantile(0.25),
        "Large Drawdown (< -2%)": ret < -0.02,
    }

    results = {}
    for name, mask in regimes.items():
        subset = returns[mask]
        if len(subset) >= 20:
            results[name] = {
                "correlation": round(subset[ticker_a].corr(subset[ticker_b]), 4),
                "days": int(mask.sum()),
            }

    return results
D3: 結果を提示する
  1. ローリング相関の要約表(以下およびレジーム別の表の値は説明用です):
ウィンドウ現在平均最小最大標準偏差
20 日0.880.760.320.950.12
60 日0.820.780.550.920.08
120 日0.800.790.680.880.05
  1. レジーム別の相関表:
レジーム相関日数
全日0.82250
上昇日0.75132
下落日0.87118
高ボラティリティ(上位 25%)0.9063
大幅下落(< -2%)0.9328
  1. 重要な洞察:売り局面で相関が高まるか(非常によく見られる現象で、「危機時には相関が 1 に近づく」と言われます)を強調します。これはリスク管理において非常に重要です。

  2. 傾向:最近の相関は、過去の平均と比べて上昇傾向ですか、それとも低下傾向ですか?


ステップ 3:ユーザーに回答する

適切なサブスキルを実行した後、結果をわかりやすく提示します:

必ず含める項目
  • 使用した参照期間とデータ間隔
  • 観測数(取引日数)
  • データ不足のため除外したティッカー
必ず注意書きを添える項目
  • 相関は因果関係を意味しません — 連動していても、因果関係があるとは限りません
  • 過去の相関は将来の相関を保証しません — レジームは変化します
  • 短い参照期間では推定値にノイズが多くなります。長い期間では平滑化されますが、レジームの変化を見逃すことがあります
実用例(関連する場合に言及)
  • 連れ高・連れ安の取引:同業他社の決算やニュースによる値動きに追随しやすい株式
  • ペアトレード:相関が高く、スプレッドが平均から乖離しているペア
  • ポートフォリオの分散:リスク低減のための低相関資産の特定
  • ヘッジ:逆相関の金融商品を特定
  • セクターローテーション:連動して動くセクターの把握
  • リスク管理:ストレス時には相関が急上昇し、最も必要な局面で分散投資の効果が失われることがあります

データを提示し、結論はユーザーに委ねます。特定の取引を推奨しないでください。


参考ファイル

  • references/sector_universes.md — yfinance Screener API を使用した、動的な同業銘柄ユニバースの構築

指定したティッカーの同業銘柄ユニバースを構築する必要がある場合は、参考ファイルをお読みください。

コメント