Skip to main content
skill CX Codex

stock-correlation — Claude Code skill: what it does, install

Finds the stocks that move alongside a given ticker and measures the link: correlation, beta, spread, or a matrix for a whole group. Useful when you need to know what drags a name along.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add himself65/finance-skills --skill stock-correlation -a claude-code
Open on GitHub

What stock-correlation does

Give it one ticker and it answers a plain question: what else moves with this thing. Price history comes from Yahoo Finance through yfinance, correlation is computed on log returns, and results are ranked by absolute value. The peer universe gets built at runtime, not from a canned list: same industry first, then the wider sector if fewer than ten names come back, then one or two adjacent industries read off the company's business summary.

From there the request routes into one of four modes. Peer discovery for a single ticker. A deep dive on a pair: correlation, beta, R², the price-ratio spread with its z-score, and a rolling window over 60 trading days. A correlation matrix for a basket. Or a look at how the correlation itself drifted over time. Defaults are one year of daily bars, Pearson, a 0.60 threshold and the top 10 hits.

Under the hood it is Python pulling quotes, so you need an interpreter with yfinance, pandas and numpy. The skill probes the environment first and pip-installs whatever is missing; with no shell access it reports the limitation instead of guessing. Worth checking before you rely on it — a sandboxed agent host is exactly where this stalls. The author states the obvious up front: research and education, not financial advice.

What it helps with

  • find tickers that move with NVDA
  • measure beta and spread for a pair like LITE/COHR
  • build a correlation matrix for a basket of stocks
  • see how a pair's correlation shifted across the year
  • spot negatively correlated names to hedge against

Example prompts for the agent

  • What correlates with NVDA over the past year?
  • Correlation, beta and spread between LITE and COHR
  • Build a correlation matrix for FAANG and flag the outliers

How to install stock-correlation

1Skills CLI (Vercel)

npx skills add himself65/finance-skills --skill stock-correlation -a claude-code

2Manually: put the files in place

~/.claude/skills/stock-correlation/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/stock-correlation/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about stock-correlation

How do I install stock-correlation in Claude Code?

Run npx skills add himself65/finance-skills --skill stock-correlation -a claude-code. The skill file lands at ~/.claude/skills/stock-correlation/SKILL.md.

What does stock-correlation do?

It ranks stocks by how closely they move with a target ticker, using Yahoo Finance price history, and reports correlation, beta and spread. For a group of tickers it returns a correlation matrix or a rolling correlation series.

What does it need to run?

A Python environment with yfinance, pandas and numpy, plus shell access. The skill checks for the packages and installs them through pip when they are missing; without a shell it reports that limitation.

Source text

SKILL.md · MIT
---
name: stock-correlation
description: >
  Analyze how stocks move together using Yahoo Finance price history (yfinance): find
  correlated peers for a ticker, measure correlation, beta, and spread between
  specific tickers, cluster a group into a correlation matrix, and track rolling or
  regime-dependent correlation. Use this skill whenever the user asks what moves with
  a stock, what else drops when it drops, related tickers or sympathy plays, sector or
  supply-chain peers, pair trading or hedging pairs, beta or relative performance,
  correlation matrices, co-movement, or rolling/realized correlation — including
  well-known pairs like AMD/NVDA, GOOGL/AVGO, or LITE/COHR. With a single ticker,
  assume the user wants its correlated peers.
---

# Stock Correlation Analysis Skill

If your host has not already executed the shell probes below (for example, in Codex), run the commands inside the `!` wrappers with its shell tool before choosing a setup path. Use the actual output; if shell access is unavailable, report that limitation.

Finds and analyzes correlated stocks using historical price data from Yahoo Finance via [yfinance](https://github.com/ranaroussi/yfinance). Routes to specialized sub-skills based on user intent.

**Important**: This is for research and educational purposes only. Not financial advice. yfinance is not affiliated with Yahoo, Inc.

---

## Step 1: Ensure Dependencies Are Available

**Current environment status:**

```
!`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\')')"`
```

If `DEPS_MISSING`, install required packages before running any code:

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

If all dependencies are already installed, skip the install step and proceed directly.

---

## Step 2: Route to the Correct Sub-Skill

Classify the user's request and jump to the matching sub-skill section below.

| User Request | Route To | Examples |
|---|---|---|
| Single ticker, wants to find related stocks | **Sub-Skill A: Co-movement Discovery** | "what correlates with NVDA", "find stocks related to AMD", "sympathy plays for TSLA" |
| Two or more specific tickers, wants relationship details | **Sub-Skill B: Return Correlation** | "correlation between AMD and NVDA", "how do LITE and COHR move together", "compare AAPL vs MSFT" |
| Group of tickers, wants structure/grouping | **Sub-Skill C: Sector Clustering** | "correlation matrix for FAANG", "cluster these semiconductor stocks", "sector peers for AMD" |
| Wants time-varying or conditional correlation | **Sub-Skill D: Realized Correlation** | "rolling correlation AMD NVDA", "when NVDA drops what else drops", "how has correlation changed" |

If ambiguous, default to **Sub-Skill A** (Co-movement Discovery) for single tickers, or **Sub-Skill B** (Return Correlation) for two tickers.

### Defaults for all sub-skills

| Parameter | Default |
|---|---|
| Lookback period | `1y` (1 year) |
| Data interval | `1d` (daily) |
| Correlation method | Pearson |
| Minimum correlation threshold | 0.60 |
| Number of results | Top 10 |
| Return type | Daily log returns |
| Rolling window | 60 trading days |

---

## Sub-Skill A: Co-movement Discovery

**Goal**: Given a single ticker, find stocks that move with it.

### A1: Build the peer universe

You need 15-30 candidates. **Do not use hardcoded ticker lists** — build the universe dynamically at runtime. See `references/sector_universes.md` for the full implementation. The approach:

1. **Screen same-industry stocks** using `yf.screen()` + `yf.EquityQuery` to find stocks in the same industry as the target
2. **Broaden to sector** if the industry screen returns fewer than 10 peers
3. **Add thematic/adjacent industries** — read the target's `longBusinessSummary` and screen 1-2 related industries (e.g., a semiconductor company → also screen semiconductor equipment)
4. **Combine, deduplicate, remove target ticker**

### A2: Compute correlations

```python
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: Present results

Show a ranked table with company names and sectors (fetch via `yf.Ticker(t).info.get("shortName")`). Values below are illustrative:

| Rank | Ticker | Company | Correlation | Why linked |
|---|---|---|---|---|
| 1 | AMD | Advanced Micro Devices | 0.82 | Same industry — GPU/CPU |
| 2 | AVGO | Broadcom | 0.78 | AI infrastructure peer |

Include:
- Top 10 positively correlated stocks
- Any notable negatively correlated stocks (potential hedges)
- Brief explanation of **why** each might be linked (sector, supply chain, customer overlap)

---

## Sub-Skill B: Return Correlation

**Goal**: Deep-dive into the relationship between two (or a few) specific tickers.

### B1: Download and compute

```python
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: Present results

Show a summary card (illustrative values):

| Metric | Value |
|---|---|
| Pearson Correlation | 0.82 |
| Beta (B vs A) | 1.15 |
| R-squared | 0.67 |
| Rolling Corr (60d avg) | 0.80 |
| Rolling Corr Range | [0.55, 0.94] |
| Rolling Corr Std Dev | 0.08 |
| Spread Z-Score (current) | +1.2 |
| Observations | 250 |

Interpretation guide:
- **Correlation > 0.80**: Strong co-movement — these stocks are tightly linked
- **Correlation 0.50–0.80**: Moderate — shared sector drivers but independent factors too
- **Correlation < 0.50**: Weak — limited co-movement despite possible sector overlap
- **High rolling std**: Unstable relationship — correlation varies significantly over time
- **Spread Z > |2|**: Unusual divergence from historical relationship

---

## Sub-Skill C: Sector Clustering

**Goal**: Given a group of tickers, show the full correlation structure and identify clusters.

### C1: Build the correlation matrix

```python
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
```

Note: if `scipy` is not available, fall back to sorting by average correlation instead of hierarchical clustering.

### C2: Present results

1. **Full correlation matrix** — formatted as a table. For more than 8 tickers, show as a heatmap description or highlight only the strongest/weakest pairs.

2. **Identified clusters** — group tickers that have high intra-group correlation:
   - Cluster 1: [NVDA, AMD, AVGO] — avg intra-correlation 0.82
   - Cluster 2: [AAPL, MSFT] — avg intra-correlation 0.75

3. **Outliers** — tickers with low average correlation to the group (potential diversifiers).

4. **Strongest pairs** — top 5 highest-correlation pairs in the matrix.

5. **Weakest pairs** — top 5 lowest/negative-correlation pairs (hedging candidates).

---

## Sub-Skill D: Realized Correlation

**Goal**: Show how correlation changes over time and under different market conditions.

### D1: Rolling correlation

```python
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: Regime-conditional correlation

```python
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: Present results

1. **Rolling correlation summary table** (illustrative values here and in the regime table):

| Window | Current | Mean | Min | Max | Std |
|---|---|---|---|---|---|
| 20-day | 0.88 | 0.76 | 0.32 | 0.95 | 0.12 |
| 60-day | 0.82 | 0.78 | 0.55 | 0.92 | 0.08 |
| 120-day | 0.80 | 0.79 | 0.68 | 0.88 | 0.05 |

2. **Regime correlation table**:

| Regime | Correlation | Days |
|---|---|---|
| All Days | 0.82 | 250 |
| Up Days | 0.75 | 132 |
| Down Days | 0.87 | 118 |
| High Vol (top 25%) | 0.90 | 63 |
| Large Drawdown (< -2%) | 0.93 | 28 |

3. **Key insight**: Highlight whether correlation **increases during sell-offs** (very common — "correlations go to 1 in a crisis"). This is critical for risk management.

4. **Trend**: Is correlation trending higher or lower recently vs. its historical average?

---

## Step 3: Respond to the User

After running the appropriate sub-skill, present results clearly:

### Always include

- The **lookback period** and **data interval** used
- The **number of observations** (trading days)
- Any tickers **dropped due to insufficient data**

### Always caveat

- **Correlation is not causation** — co-movement does not imply a causal link
- **Past correlation does not guarantee future correlation** — regimes shift
- **Short lookback windows** produce noisy estimates; longer windows smooth but may miss regime changes

### Practical applications (mention when relevant)

- **Sympathy plays**: Stocks likely to follow a peer's earnings/news move
- **Pair trading**: High-correlation pairs where the spread has diverged from its mean
- **Portfolio diversification**: Finding low-correlation assets to reduce risk
- **Hedging**: Identifying inversely correlated instruments
- **Sector rotation**: Understanding which sectors move together
- **Risk management**: Correlation spikes during stress — diversification may fail when needed most

Present the data and let the user draw conclusions; don't recommend specific trades.

---

## Reference Files

- `references/sector_universes.md` — Dynamic peer universe construction using yfinance Screener API

Read the reference file when you need to build a peer universe for a given ticker.

© himself65 · MIT · himself65/finance-skills

Similar skills

Everything for Finance and business →

From the same set22

yfinance-data Skill fetches stock quotes, financial statements, options, dividends and holder data through the yfinance library (Yahoo Finance). CX Codex +1 3,900installs options-payoff Builds an interactive options payoff chart with expiry P&L and Black–Scholes theoretical value for reviewing single- or multi-leg positions. CX Codex +1 3,400installs generative-ui Provides design system rules and templates for interactive HTML and SVG widgets. Useful when you need charts, diagrams, or calculators instead of plain text. CX Codex +1 3,200installs earnings-recap Analyzes a published company earnings report using EPS, revenue, margins and the stock reaction. Use it when you need to assess a beat, miss or post-report move. CX Codex +1 3,200installs earnings-preview Builds a pre-earnings brief for a ticker: report date and timing, EPS and revenue consensus, the beat/miss record, analyst targets. CX Codex +1 3,200installs twitter-reader Reads Twitter/X through opencli: home timeline, tweet search, trending, bookmarks, profiles and notifications. Read-only, built for financial research. CX Codex +1 3,100installs etf-premium Works out whether an ETF trades above or below NAV using Yahoo Finance data, compares funds against each other, and breaks a sudden price jump into its causes. CX Codex +1 3,100installs stock-liquidity Evaluates stock liquidity via yfinance: bid-ask spreads, trading volume, and market impact. Helps gauge trading costs before entering or exiting positions. CX Codex +1 3,100installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor