$npx -y skills add himself65/finance-skills --skill stock-correlationAnalyze stock correlations to find related companies and trading pairs. Use when the user asks about correlated stocks, related companies, sector peers, trading pairs, or how two or more stocks move together. Triggers: "what correlates with NVDA", "find stocks related to AMD", "c
| 1 | # Stock Correlation Analysis Skill |
| 2 | |
| 3 | 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. |
| 4 | |
| 5 | **Important**: This is for research and educational purposes only. Not financial advice. yfinance is not affiliated with Yahoo, Inc. |
| 6 | |
| 7 | --- |
| 8 | |
| 9 | ## Step 1: Ensure Dependencies Are Available |
| 10 | |
| 11 | **Current environment status:** |
| 12 | |
| 13 | ``` |
| 14 | !`python3 -c "import yfinance, pandas, numpy; print(f'yfinance={yfinance.__version__} pandas={pandas.__version__} numpy={numpy.__version__}')" 2>/dev/null || echo "DEPS_MISSING"` |
| 15 | ``` |
| 16 | |
| 17 | If `DEPS_MISSING`, install required packages before running any code: |
| 18 | |
| 19 | ```python |
| 20 | import subprocess, sys |
| 21 | subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "yfinance", "pandas", "numpy"]) |
| 22 | ``` |
| 23 | |
| 24 | If all dependencies are already installed, skip the install step and proceed directly. |
| 25 | |
| 26 | --- |
| 27 | |
| 28 | ## Step 2: Route to the Correct Sub-Skill |
| 29 | |
| 30 | Classify the user's request and jump to the matching sub-skill section below. |
| 31 | |
| 32 | | User Request | Route To | Examples | |
| 33 | |---|---|---| |
| 34 | | 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" | |
| 35 | | 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" | |
| 36 | | Group of tickers, wants structure/grouping | **Sub-Skill C: Sector Clustering** | "correlation matrix for FAANG", "cluster these semiconductor stocks", "sector peers for AMD" | |
| 37 | | 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" | |
| 38 | |
| 39 | If ambiguous, default to **Sub-Skill A** (Co-movement Discovery) for single tickers, or **Sub-Skill B** (Return Correlation) for two tickers. |
| 40 | |
| 41 | ### Defaults for all sub-skills |
| 42 | |
| 43 | | Parameter | Default | |
| 44 | |---|---| |
| 45 | | Lookback period | `1y` (1 year) | |
| 46 | | Data interval | `1d` (daily) | |
| 47 | | Correlation method | Pearson | |
| 48 | | Minimum correlation threshold | 0.60 | |
| 49 | | Number of results | Top 10 | |
| 50 | | Return type | Daily log returns | |
| 51 | | Rolling window | 60 trading days | |
| 52 | |
| 53 | --- |
| 54 | |
| 55 | ## Sub-Skill A: Co-movement Discovery |
| 56 | |
| 57 | **Goal**: Given a single ticker, find stocks that move with it. |
| 58 | |
| 59 | ### A1: Build the peer universe |
| 60 | |
| 61 | 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: |
| 62 | |
| 63 | 1. **Screen same-industry stocks** using `yf.screen()` + `yf.EquityQuery` to find stocks in the same industry as the target |
| 64 | 2. **Broaden to sector** if the industry screen returns fewer than 10 peers |
| 65 | 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) |
| 66 | 4. **Combine, deduplicate, remove target ticker** |
| 67 | |
| 68 | ### A2: Compute correlations |
| 69 | |
| 70 | ```python |
| 71 | import yfinance as yf |
| 72 | import pandas as pd |
| 73 | import numpy as np |
| 74 | |
| 75 | def discover_comovement(target_ticker, peer_tickers, period="1y"): |
| 76 | all_tickers = [target_ticker] + [t for t in peer_tickers if t != target_ticker] |
| 77 | data = yf.download(all_tickers, period=period, auto_adjust=True, progress=False) |
| 78 | |
| 79 | # Extract close prices — yf.download returns MultiIndex (Price, Ticker) columns |
| 80 | closes = data["Close"].dropna(axis=1, thresh=max(60, len(data) // 2)) |
| 81 | |
| 82 | # Log returns |
| 83 | returns = np.log(closes / closes.shift(1)).dropna() |
| 84 | corr_series = returns.corr()[target_ticker].drop(target_ticker, errors="ignore") |
| 85 | |
| 86 | # Rank by absolute correlation |
| 87 | ranked = corr_series.abs().sort_values(ascending=False) |
| 88 | |
| 89 | result = pd.DataFrame({ |
| 90 | "Ticker": ranked.index, |
| 91 | "Correlation": [round(corr_series[t], 4) for t in ranked.index], |
| 92 | }) |
| 93 | return result, returns |
| 94 | ``` |
| 95 | |
| 96 | ### A3: Present results |
| 97 | |
| 98 | Show a rank |