stock-correlation by himself65/finance-skills
npx skills add https://github.com/himself65/finance-skills --skill stock-correlation包含 Shell 命令
此技能包含可能执行系统命令的 shell 命令指令(!command``)。安装前请仔细审查。
通过 yfinance 使用雅虎财经的历史价格数据查找并分析相关的股票。根据用户意图路由到专门的子技能。
重要提示:此技能仅用于研究和教育目的。不构成财务建议。yfinance 与 Yahoo, Inc. 无关。
当前环境状态:
!`python3 -c "import yfinance, pandas, numpy; print(f'yfinance={yfinance.__version__} pandas={pandas.__version__} numpy={numpy.__version__}')" 2>/dev/null || echo "DEPS_MISSING"`
如果输出 DEPS_MISSING,请在运行任何代码之前安装所需的包:
import subprocess, sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "yfinance", "pandas", "numpy"])
如果所有依赖项均已安装,请跳过安装步骤并直接继续。
对用户的请求进行分类,并跳转到下面匹配的子技能部分。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 用户请求 | 路由到 | 示例 |
|---|---|---|
| 单个股票代码,希望找到相关股票 | 子技能 A:联动发现 | "什么与 NVDA 相关","查找与 AMD 相关的股票","TSLA 的联动交易" |
| 两个或更多特定股票代码,希望了解关系详情 | 子技能 B:收益相关性 | "AMD 和 NVDA 之间的相关性","LITE 和 COHR 如何联动","比较 AAPL 和 MSFT" |
| 一组股票代码,希望了解结构/分组 | 子技能 C:板块聚类 | "FAANG 的相关性矩阵","对这些半导体股票进行聚类","AMD 的板块同行" |
| 希望了解随时间变化或有条件限制的相关性 | 子技能 D:已实现相关性 | "AMD NVDA 的滚动相关性","当 NVDA 下跌时还有什么下跌","相关性如何变化" |
如果请求不明确,对于单个股票代码默认使用 子技能 A(联动发现),对于两个股票代码默认使用 子技能 B(收益相关性)。
| 参数 | 默认值 |
|---|---|
| 回溯期 | 1y (1 年) |
| 数据间隔 | 1d (日线) |
| 相关性方法 | Pearson |
| 最小相关性阈值 | 0.60 |
| 结果数量 | 前 10 名 |
| 收益类型 | 日对数收益 |
| 滚动窗口 | 60 个交易日 |
目标:给定单个股票代码,查找与其联动的股票。
你需要 15-30 个候选股票。不要使用硬编码的股票代码列表 — 在运行时动态构建股票池。完整实现请参见 references/sector_universes.md。方法如下:
yf.screen() + yf.EquityQuery 查找与目标股票同行业的股票longBusinessSummary 并筛选 1-2 个相关行业(例如,半导体公司 → 同时筛选半导体设备)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)
# 提取收盘价 — yf.download 返回 MultiIndex (Price, Ticker) 列
closes = data["Close"].dropna(axis=1, thresh=max(60, len(data) // 2))
# 对数收益
returns = np.log(closes / closes.shift(1)).dropna()
corr_series = returns.corr()[target_ticker].drop(target_ticker, errors="ignore")
# 按绝对相关性排序
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
显示一个包含公司名称和板块(通过 yf.Ticker(t).info.get("shortName") 获取)的排名表:
| 排名 | 股票代码 | 公司 | 相关性 | 关联原因 |
|---|---|---|---|---|
| 1 | AMD | Advanced Micro Devices | 0.82 | 同行业 — GPU/CPU |
| 2 | AVGO | Broadcom | 0.78 | AI 基础设施同行 |
包含:
目标:深入分析两个(或少数几个)特定股票代码之间的关系。
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:A 每变动一个单位,B 变动多少
cov_matrix = returns.cov()
beta = cov_matrix.loc[ticker_b, ticker_a] / cov_matrix.loc[ticker_a, ticker_a]
# R 平方
r_squared = corr ** 2
# 用于稳定性的 60 日滚动相关性
rolling_corr = returns[ticker_a].rolling(60).corr(returns[ticker_b])
# 用于均值回归的价差(对数价格比)
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),
}
显示一个摘要卡片:
| 指标 | 值 |
|---|---|
| 皮尔逊相关性 | 0.82 |
| Beta (B 相对于 A) | 1.15 |
| R 平方 | 0.67 |
| 滚动相关性 (60 日均值) | 0.80 |
| 滚动相关性范围 | [0.55, 0.94] |
| 滚动相关性标准差 | 0.08 |
| 价差 Z 分数 (当前) | +1.2 |
| 观测数 | 250 |
解读指南:
目标:给定一组股票代码,显示完整的相关性结构并识别聚类。
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 返回 MultiIndex (Price, Ticker) 列
closes = data["Close"].dropna(axis=1, thresh=max(60, len(data) // 2))
returns = np.log(closes / closes.shift(1)).dropna()
corr_matrix = returns.corr()
# 层次聚类排序
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]
# 重新排序矩阵
clustered = corr_matrix.loc[ordered_tickers, ordered_tickers]
return clustered, returns
注意:如果 scipy 不可用,则回退到按平均相关性排序,而不是层次聚类。
完整相关性矩阵 — 格式化为表格。对于超过 8 个股票代码,显示为热力图描述或仅突出显示最强/最弱的相关对。
识别出的聚类 — 将具有高组内相关性的股票代码分组:
离群值 — 与组平均相关性较低的股票代码(潜在的分散投资工具)。
最强相关对 — 矩阵中相关性最高的前 5 对。
最弱相关对 — 相关性最低/负相关的前 5 对(对冲候选)。
目标:展示相关性如何随时间变化以及在不同市场条件下的表现。
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
def regime_correlation(returns, ticker_a, ticker_b, condition_ticker=None):
"""比较上涨/下跌/波动性不同机制下的相关性。"""
if condition_ticker is None:
condition_ticker = ticker_a
ret = returns[condition_ticker]
regimes = {
"所有交易日": pd.Series(True, index=returns.index),
"上涨日 (目标 > 0)": ret > 0,
"下跌日 (目标 < 0)": ret < 0,
"高波动 (前 25%)": ret.abs() > ret.abs().quantile(0.75),
"低波动 (后 25%)": ret.abs() < ret.abs().quantile(0.25),
"大幅回撤 (< -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
| 窗口 | 当前值 | 均值 | 最小值 | 最大值 | 标准差 |
|---|---|---|---|---|---|
| 20 日 | 0.88 | 0.76 | 0.32 | 0.95 | 0.12 |
| 60 日 | 0.82 | 0.78 | 0.55 | 0.92 | 0.08 |
| 120 日 | 0.80 | 0.79 | 0.68 | 0.88 | 0.05 |
| 机制 | 相关性 | 天数 |
|---|---|---|
| 所有交易日 | 0.82 | 250 |
| 上涨日 | 0.75 | 132 |
| 下跌日 | 0.87 | 118 |
| 高波动 (前 25%) | 0.90 | 63 |
| 大幅回撤 (< -2%) | 0.93 | 28 |
关键洞察:强调相关性是否在抛售期间增加(非常常见 — "危机中相关性趋近于 1")。这对风险管理至关重要。
趋势:相关性最近是高于还是低于其历史平均值?
运行适当的子技能后,清晰地呈现结果:
重要提示:切勿推荐具体交易。呈现数据,让用户自己得出结论。
references/sector_universes.md — 使用 yfinance Screener API 动态构建同行股票池当需要为给定股票代码构建同行股票池时,请阅读参考文件。
每周安装数
92
代码库
GitHub 星标数
420
首次出现
10 天前
安全审计
安装于
gemini-cli81
codex81
opencode80
cursor80
kimi-cli79
amp79
Contains Shell Commands
This skill contains shell command directives (!command``) that may execute system commands. Review carefully before installing.
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.
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.
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.
| 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 |
Goal : Given a single ticker, find stocks that move with it.
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:
yf.screen() + yf.EquityQuery to find stocks in the same industry as the targetlongBusinessSummary and screen 1-2 related industries (e.g., a semiconductor company → also screen semiconductor equipment)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
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:
Goal : Deep-dive into the relationship between two (or a few) specific tickers.
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),
}
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:
Goal : Given a group of tickers, show the full correlation structure and identify clusters.
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.
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:
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).
Goal : Show how correlation changes over time and under different market conditions.
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
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
| 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 | 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?
After running the appropriate sub-skill, present results clearly:
Important : Never recommend specific trades. Present data and let the user draw conclusions.
references/sector_universes.md — Dynamic peer universe construction using yfinance Screener APIRead the reference file when you need to build a peer universe for a given ticker.
Weekly Installs
92
Repository
GitHub Stars
420
First Seen
10 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
gemini-cli81
codex81
opencode80
cursor80
kimi-cli79
amp79
DOCX文件创建、编辑与分析完整指南 - 使用docx-js、Pandoc和Python脚本
51,800 周安装
Better Auth 安全最佳实践指南 | 身份验证安全技能与代码示例
7,200 周安装
antfu 编码规范与工具链配置指南:TypeScript、ESLint、pnpm 最佳实践
7,100 周安装
Google Workspace CLI 提示净化工具:Model Armor sanitize-prompt 安全过滤用户输入
7,300 周安装
Google Workspace CLI 技能:通过 Gmail 和 Google Chat 向团队发送公告 | 自动化办公
7,400 周安装
Google Workspace CLI 创建 Model Armor 模板命令指南 | gws modelarmor +create-template
7,400 周安装
Lark Approval CLI 工具:飞书审批自动化与API调用命令行解决方案
10,700 周安装