
Stock Correlation
- 1.9k installs
- 3.1k repo stars
- Updated July 21, 2026
- himself65/finance-skills
stock-correlation is an agent skill that finds and analyzes correlated stocks using yfinance historical prices with co-movement, pair, clustering, and rolling correlation workflows.
About
The stock-correlation skill analyzes how equities move together using historical price data from Yahoo Finance through the yfinance library. It routes requests to four sub-skills: co-movement discovery for a single ticker, return correlation for specific pairs, sector clustering for groups, and realized correlation for time-varying or regime-conditional relationships. Default parameters use one year of daily data, Pearson correlation on log returns, a 0.60 threshold, and top ten results. Co-movement discovery builds a peer universe dynamically with yf.screen and EquityQuery rather than hardcoded lists, then ranks peers by absolute correlation. Return correlation reports beta, R-squared, rolling 60-day correlation, and spread z-scores. Sector clustering produces a correlation matrix with hierarchical ordering when scipy is available. Realized correlation compares rolling windows and regime splits such as up days, down days, and high-volatility periods. Results always include lookback period, observation count, and disclaimers that correlation is not causation and past co-movement may not persist. Use when developers ask what correlates with a ticker, how two stocks move together, o.
- Routes to four sub-skills: co-movement discovery, return correlation, sector clustering, and realized correlation.
- Builds peer universes dynamically with yf.screen and EquityQuery instead of hardcoded ticker lists.
- Default lookback is one year of daily log returns with Pearson correlation and 0.60 threshold.
- Return correlation reports beta, R-squared, rolling correlation range, and spread z-score.
- Regime analysis highlights correlation spikes during sell-offs for risk management context.
Stock Correlation by the numbers
- 1,938 all-time installs (skills.sh)
- +128 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #74 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
stock-correlation capabilities & compatibility
- Capabilities
- co movement discovery with dynamic peer screenin · return correlation with beta and spread z score · sector clustering correlation matrix · rolling and regime conditional correlation · pearson log return correlation ranking
- Use cases
- trading · research · data analysis
npx skills add https://github.com/himself65/finance-skills --skill stock-correlationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.9k |
|---|---|
| repo stars | ★ 3.1k |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 21, 2026 |
| Repository | himself65/finance-skills ↗ |
How do I find stocks that move with NVDA, measure correlation between two tickers, or see how co-movement changes in volatile regimes?
Find correlated stocks, sector peers, pair-trading spreads, and rolling co-movement using Yahoo Finance data via yfinance.
Who is it for?
Developers researching sympathy plays, pair-trading spreads, sector peer structure, or hedging candidates from price history.
Skip if: Skip for fundamental valuation, live trade execution, or non-equity asset correlation without price data.
When should I use this skill?
User asks what correlates with a ticker, correlation between two stocks, sector peers, pair trading, or rolling co-movement.
What you get
Ranked correlation tables, pair metrics including beta and spread z-score, clustered correlation matrices, and regime-conditional correlation summaries.
- correlated ticker list
- pairwise correlation report
- sector cluster matrix
Files
Stock Correlation Analysis Skill
Finds and analyzes correlated stocks using historical price data from Yahoo Finance via 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 "import yfinance, pandas, numpy; print(f'yfinance={yfinance.__version__} pandas={pandas.__version__} numpy={numpy.__version__}')" 2>/dev/null || echo "DEPS_MISSING"`If DEPS_MISSING, install required packages before running any code:
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
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, returnsA3: Present results
Show a ranked table with company names and sectors (fetch via yf.Ticker(t).info.get("shortName")):
| 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
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:
| 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
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, returnsNote: 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
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, returnsD2: Regime-conditional correlation
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 resultsD3: Present results
1. Rolling correlation summary 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
Important: Never recommend specific trades. Present data and let the user draw conclusions.
---
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.
stock-correlation
Analyze stock correlations to find related companies, sector peers, and pair-trading candidates using historical price data.
What it does
Routes to four specialized sub-skills based on user intent:
- Co-movement Discovery — given a single ticker, find the most correlated stocks from curated sector and thematic peer universes (e.g., "what correlates with NVDA?")
- Return Correlation — deep-dive pairwise analysis between two tickers: Pearson correlation, beta, R-squared, spread Z-score, and rolling stability (e.g., "correlation between AMD and NVDA")
- Sector Clustering — full NxN correlation matrix with hierarchical clustering to identify groups and outliers (e.g., "correlation matrix for FAANG")
- Realized Correlation — time-varying and regime-conditional correlation: rolling windows (20/60/120-day), up vs down days, high-vol vs low-vol, drawdown regimes (e.g., "when NVDA drops what else drops?")
Triggers
- "what correlates with NVDA", "find stocks related to AMD"
- "correlation between AAPL and MSFT", "how do LITE and COHR move together"
- "what moves with", "stocks that move together", "sympathy plays"
- "sector peers", "pair trading", "hedging pair"
- "when NVDA drops what else drops", "rolling correlation"
- "correlation matrix for FAANG", "cluster these stocks"
- Well-known pairs: AMD/NVDA, GOOGL/AVGO, LITE/COHR
Prerequisites
- Python 3.8+
- The skill auto-installs
yfinance,pandas, andnumpyvia pip if not already present scipyis optional (used for hierarchical clustering in Sector Clustering sub-skill; falls back to sorting if unavailable)
Platform
Works on all platforms (Claude Code, Claude.ai with code execution, etc.).
Setup
# As a plugin (recommended — installs all skills)
npx plugins add himself65/finance-skills --plugin finance-market-analysis
# Or install just this skill
npx skills add himself65/finance-skills --skill stock-correlationSee the main README for more installation options.
Reference files
references/sector_universes.md— Dynamic peer universe construction using yfinance Screener API, with fallback strategies
Dynamic Peer Universe Construction
How to build a peer universe at runtime for correlation analysis. Do not hardcode ticker lists — fetch them dynamically so results stay current.
---
Method 1: Same-Sector Screen (Primary)
Use yfinance's yf.screen() + EquityQuery to find stocks in the same sector as the target. Note: the screener supports filtering by sector but not directly by industry — use sector-level screening and let the correlation math surface the closest peers.
import yfinance as yf
from yfinance import EquityQuery
def get_sector_peers(ticker_symbol, min_market_cap=1_000_000_000, max_results=30):
"""Find peers in the same sector above a market cap threshold."""
target = yf.Ticker(ticker_symbol)
info = target.info
sector = info.get("sector", "")
if not sector:
return []
# Screen for same-sector stocks on major US exchanges
query = EquityQuery("and", [
EquityQuery("eq", ["sector", sector]),
EquityQuery("gt", ["intradaymarketcap", min_market_cap]),
EquityQuery("is-in", ["exchange", "NMS", "NYQ"]),
])
result = yf.screen(query, size=max_results, sortField="intradaymarketcap", sortAsc=False)
peers = []
for quote in result.get("quotes", []):
symbol = quote.get("symbol", "")
if symbol and symbol != ticker_symbol:
peers.append(symbol)
return peersMethod 2: Thematic Expansion
For cross-sector correlations (e.g., AI supply chain spans semis + cloud + software), read the target's business description and screen adjacent sectors:
def get_thematic_context(ticker_symbol):
"""Get company context to inform adjacent-sector screening."""
target = yf.Ticker(ticker_symbol)
info = target.info
return {
"sector": info.get("sector", ""),
"industry": info.get("industry", ""),
"description": info.get("longBusinessSummary", ""),
}After reading the company description, screen 1-2 adjacent sectors. For example:
- A semiconductor company (Technology sector) → also consider screening for related names in "Industrials" (equipment suppliers)
- A cloud platform → also screen for networking/data-center REITs
- An EV maker (Consumer Cyclical) → also screen "Basic Materials" (battery materials), "Industrials" (auto parts)
Combining Methods
Build the full universe by combining sector screen + thematic expansion:
def build_peer_universe(ticker_symbol):
"""Build a comprehensive peer universe for correlation analysis."""
peers = set()
# 1. Same sector
sector_peers = get_sector_peers(ticker_symbol, min_market_cap=1_000_000_000, max_results=25)
peers.update(sector_peers)
# 2. If too few, lower the market cap threshold
if len(peers) < 10:
more_peers = get_sector_peers(ticker_symbol, min_market_cap=500_000_000, max_results=30)
peers.update(more_peers)
# 3. Add thematic/adjacent sectors based on business description
# (model should reason about which adjacent sectors to screen)
peers.discard(ticker_symbol)
return list(peers)Target: 15-30 peers for a meaningful correlation scan. Too few gives sparse results; too many slows the yfinance download.
---
Fallback: Well-Known Groupings
If the screener is unavailable or rate-limited, use well-known benchmarks:
- Mag 7: AAPL, MSFT, GOOGL, AMZN, META, NVDA, TSLA
- Major indices: SPY (S&P 500), QQQ (Nasdaq 100), DIA (Dow 30), IWM (Russell 2000)
- Sector ETFs: XLK, XLF, XLE, XLV, XLI, XLP, XLU, XLY, XLC, XLRE, XLB
These ETFs are useful as correlation benchmarks — comparing a stock's correlation to sector ETFs quickly reveals its primary driver.
Related skills
How it compares
Pick stock-correlation over generic data-science skills when the workflow is equity-specific co-movement, sector peers, and pair-trade screening from price histories.
FAQ
What data source does stock-correlation use?
Historical price data from Yahoo Finance via the yfinance Python library with configurable lookback and daily intervals.
When should I use stock-correlation?
When analyzing correlated stocks, sector peers, pair relationships, correlation matrices, or regime-dependent co-movement.
Is stock-correlation safe to install?
Review the Security Audits panel on this page before installing in production.