Stock Correlation
Alex YangCommunityCreated by Alex Yang
- Skill
- Research and analysis
- Data and AI
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Stock Correlation provides a framework for analyzing how financial assets move in relation to one another. By leveraging historical price data from Yahoo Finance, it enables users to identify correlated peers, calculate beta and spread, perform sector clustering, and evaluate how correlations shift during different market regimes. The skill is designed for research and educational purposes, helping users understand relationships between tickers, identify potential sympathy plays, and assess portfolio diversification or hedging opportunities.
What it does
- Identifies correlated peers for a single stock using dynamic sector screening.
- Calculates correlation, beta, and R-squared between specific ticker pairs.
- Generates correlation matrices for groups of stocks to identify clusters.
- Tracks rolling correlation to monitor relationship stability over time.
- Analyzes regime-dependent correlation to see how assets behave during market stress.
- Provides statistical insights into spread divergence for potential mean-reversion analysis.
When to use it
- When you need to find stocks that move in sympathy with a specific ticker.
- When comparing the relationship between two assets for pair trading or hedging.
- When you want to visualize the correlation structure of a sector or group of stocks.
- When investigating how asset correlations change during market sell-offs or high volatility.
- When assessing the diversification benefits of adding a new asset to a portfolio.
Advantages
- Uses dynamic peer universe construction to ensure relevant and current comparisons.
- Supports both simple correlation checks and advanced regime-based analysis.
- Provides clear statistical metrics like beta and Z-scores for deeper insight.
- Includes built-in safeguards to handle data gaps and ensure robust calculations.
- Offers actionable context for risk management and portfolio construction.
Usage examples
- “What stocks move most closely with NVDA?”
- The agent will screen the semiconductor sector, calculate the correlation of daily log returns, and present a ranked list of the top 10 most correlated peers.
- “Calculate the correlation and beta between AMD and Intel.”
- The agent will compute the Pearson correlation, beta, R-squared, and current spread Z-score to evaluate the strength and stability of their relationship.
- “Show me a correlation matrix for the Mag 7 stocks.”
- The agent will download historical data for the group, perform hierarchical clustering, and display a correlation matrix highlighting the strongest and weakest pairs.
- “How does the correlation between SPY and TLT change during market drawdowns?”
- The agent will perform a regime-conditional analysis to compare correlation during 'All Days' versus 'Large Drawdown' periods.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/himself65/stock-correlation/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip stock-correlation.zip -d .agents/skills
Documentation by Alex Yang
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. 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:
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:
Screen same-industry stocks using
yf.screen()+yf.EquityQueryto find stocks in the same industry as the targetBroaden to sector if the industry screen returns fewer than 10 peers
Add thematic/adjacent industries — read the target's
longBusinessSummaryand screen 1-2 related industries (e.g., a semiconductor company → also screen semiconductor equipment)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")). 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
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
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
Full correlation matrix — formatted as a table. For more than 8 tickers, show as a heatmap description or highlight only the strongest/weakest pairs.
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
Outliers — tickers with low average correlation to the group (potential diversifiers).
Strongest pairs — top 5 highest-correlation pairs in the matrix.
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
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 |
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 |
Key insight: Highlight whether correlation increases during sell-offs (very common — "correlations go to 1 in a crisis"). This is critical for risk management.
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.
Files
- ATTRIBUTION.mdAdded by AutoGineer895 B
- LICENSELicence file added by AutoGineer1.0 KiB
- README.md2.1 KiB
- SKILL.md13.4 KiB
- references/sector_universes.md3.7 KiB
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Alex Yang
- Publisher
- Alex Yang (Community)
- Source
- himself65/finance-skills · plugins/market-analysis/skills/stock-correlation · commit a085078
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Alex Yang or Alex Yang.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download stock-correlation.zip