Stock Analysis v6.1 Analyze US stocks and cryptocurrencies with 8-dimension analysis, portfolio management, watchlists, alerts, dividend analysis, and viral trend detection . What's New in v6.2 - 🔮 Rumor Scanner — Early signals before mainstream news - M&A rumors and takeover bids - Insider buying/selling activity - Analyst upgrades/downgrades - Twitter/X "hearing that...", "sources say..." detection - 🎯 Impact Scoring — Rumors ranked by potential market impact What's in v6.1 - 🔥 Hot Scanner — Find viral stocks & crypto across multiple sources - 🐦 Twitter/X Integration — Social sentiment…

,\n '\"sources say\" stock OR company',\n '\"rumor\" merger OR acquisition',\n 'insider buying stock',\n '\"upgrade\" OR \"downgrade\" stock tomorrow',\n '$AAPL OR $TSLA OR $NVDA rumor',\n '\"breaking\" stock market',\n 'M&A rumor',\n ]\n \n load_env()\n \n for query in queries[:4]: # Limit to avoid rate limits\n try:\n cmd = [BIRD_CLI, 'search', query, '-n', '10', '--json']\n env = os.environ.copy()\n \n result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, env=env)\n \n if result.returncode == 0 and result.stdout:\n try:\n tweets = json.loads(result.stdout)\n for tweet in tweets:\n text = tweet.get('text', '')\n # Filter for actual rumors/signals\n if any(kw in text.lower() for kw in ['hearing', 'rumor', 'source', 'insider', 'upgrade', 'downgrade', 'breaking', 'M&A', 'merger', 'acquisition']):\n results.append({\n 'source': 'twitter',\n 'type': 'rumor',\n 'text': text[:300],\n 'author': tweet.get('author', {}).get('username', 'unknown'),\n 'likes': tweet.get('likes', 0),\n 'retweets': tweet.get('retweets', 0),\n 'query': query\n })\n except json.JSONDecodeError:\n pass\n except Exception as e:\n pass\n \n # Dedupe by text similarity\n seen = set()\n unique = []\n for r in results:\n key = r['text'][:100]\n if key not in seen:\n seen.add(key)\n unique.append(r)\n \n return unique\n\ndef search_twitter_buzz():\n \"\"\"Search Twitter for general stock buzz - what are people talking about?\"\"\"\n results = []\n \n queries = [\n '$SPY OR $QQQ',\n 'stock to buy',\n 'calls OR puts expiring',\n 'earnings play',\n 'short squeeze',\n ]\n \n load_env()\n \n for query in queries[:3]:\n try:\n cmd = [BIRD_CLI, 'search', query, '-n', '15', '--json']\n env = os.environ.copy()\n \n result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, env=env)\n \n if result.returncode == 0 and result.stdout:\n try:\n tweets = json.loads(result.stdout)\n for tweet in tweets:\n text = tweet.get('text', '')\n # Extract stock symbols\n symbols = re.findall(r'\\$([A-Z]{1,5})\\b', text)\n if symbols:\n results.append({\n 'source': 'twitter',\n 'type': 'buzz',\n 'text': text[:300],\n 'symbols': symbols,\n 'author': tweet.get('author', {}).get('username', 'unknown'),\n 'engagement': tweet.get('likes', 0) + tweet.get('retweets', 0) * 2\n })\n except json.JSONDecodeError:\n pass\n except Exception as e:\n pass\n \n # Sort by engagement\n results.sort(key=lambda x: x.get('engagement', 0), reverse=True)\n return results[:20]\n\ndef search_news_rumors():\n \"\"\"Search Google News for M&A, insider, upgrade news.\"\"\"\n results = []\n \n queries = [\n 'merger acquisition rumor',\n 'insider buying stock',\n 'analyst upgrade stock',\n 'takeover bid company',\n 'SEC investigation company',\n ]\n \n for query in queries:\n url = f\"https://news.google.com/rss/search?q={quote_plus(query)}&hl=en-US&gl=US&ceid=US:en\"\n content = fetch_url(url)\n \n if content:\n import xml.etree.ElementTree as ET\n try:\n root = ET.fromstring(content)\n for item in root.findall('.//item')[:5]:\n title = item.find('title')\n link = item.find('link')\n pub_date = item.find('pubDate')\n \n if title is not None:\n title_text = title.text or ''\n # Extract company names or symbols\n results.append({\n 'source': 'google_news',\n 'type': 'news_rumor',\n 'title': title_text,\n 'link': link.text if link is not None else '',\n 'date': pub_date.text if pub_date is not None else '',\n 'query': query\n })\n except ET.ParseError:\n pass\n \n return results\n\ndef extract_symbols_from_text(text):\n \"\"\"Extract stock symbols from text.\"\"\"\n # $SYMBOL pattern\n dollar_symbols = re.findall(r'\\$([A-Z]{1,5})\\b', text)\n \n # Common company name to symbol mapping\n company_map = {\n 'apple': 'AAPL', 'tesla': 'TSLA', 'nvidia': 'NVDA', 'microsoft': 'MSFT',\n 'google': 'GOOGL', 'amazon': 'AMZN', 'meta': 'META', 'netflix': 'NFLX',\n 'coinbase': 'COIN', 'robinhood': 'HOOD', 'disney': 'DIS', 'intel': 'INTC',\n 'amd': 'AMD', 'palantir': 'PLTR', 'gamestop': 'GME', 'amc': 'AMC',\n }\n \n text_lower = text.lower()\n company_symbols = [sym for name, sym in company_map.items() if name in text_lower]\n \n return list(set(dollar_symbols + company_symbols))\n\ndef calculate_rumor_score(item):\n \"\"\"Score a rumor by potential impact.\"\"\"\n score = 0\n text = (item.get('text', '') + item.get('title', '')).lower()\n \n # High impact keywords\n if any(kw in text for kw in ['merger', 'acquisition', 'takeover', 'buyout']):\n score += 5\n if any(kw in text for kw in ['insider', 'ceo buying', 'director buying']):\n score += 4\n if any(kw in text for kw in ['upgrade', 'price target raised']):\n score += 3\n if any(kw in text for kw in ['downgrade', 'sec investigation', 'fraud']):\n score += 3\n if any(kw in text for kw in ['hearing', 'sources say', 'rumor']):\n score += 2\n if any(kw in text for kw in ['breaking', 'just in', 'alert']):\n score += 2\n \n # Engagement boost\n if item.get('engagement', 0) > 100:\n score += 2\n if item.get('likes', 0) > 50:\n score += 1\n \n return score\n\ndef main():\n print(\"=\" * 60)\n print(\"🔮 RUMOR & BUZZ SCANNER\")\n print(f\"📅 {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} UTC\")\n print(\"=\" * 60)\n print()\n print(\"🔍 Scanning for early signals...\")\n print()\n \n all_rumors = []\n all_buzz = []\n \n # Twitter Rumors\n print(\" 🐦 Twitter rumors...\")\n rumors = search_twitter_rumors()\n print(f\" ✅ {len(rumors)} potential rumors\")\n all_rumors.extend(rumors)\n \n # Twitter Buzz\n print(\" 🐦 Twitter buzz...\")\n buzz = search_twitter_buzz()\n print(f\" ✅ {len(buzz)} buzz items\")\n all_buzz.extend(buzz)\n \n # News Rumors\n print(\" 📰 News rumors...\")\n news = search_news_rumors()\n print(f\" ✅ {len(news)} news items\")\n all_rumors.extend(news)\n \n # Score and sort rumors\n for item in all_rumors:\n item['score'] = calculate_rumor_score(item)\n item['symbols'] = extract_symbols_from_text(item.get('text', '') + item.get('title', ''))\n \n all_rumors.sort(key=lambda x: x['score'], reverse=True)\n \n # Count symbol mentions in buzz\n symbol_counts = {}\n for item in all_buzz:\n for sym in item.get('symbols', []):\n symbol_counts[sym] = symbol_counts.get(sym, 0) + 1\n \n # Output\n print()\n print(\"=\" * 60)\n print(\"🔮 RESULTS\")\n print(\"=\" * 60)\n print()\n \n # Top Rumors\n print(\"🚨 TOP RUMORS (by potential impact):\")\n print()\n for item in all_rumors[:10]:\n if item['score'] > 0:\n source = item['source']\n symbols = ', '.join(item.get('symbols', [])) or 'N/A'\n text = item.get('text', item.get('title', ''))[:80]\n print(f\" [{item['score']}] [{source}] {symbols}\")\n print(f\" {text}...\")\n print()\n \n # Buzz Leaderboard\n print(\"📊 BUZZ LEADERBOARD (most discussed):\")\n print()\n sorted_symbols = sorted(symbol_counts.items(), key=lambda x: x[1], reverse=True)\n for symbol, count in sorted_symbols[:15]:\n bar = \"█\" * min(count, 20)\n print(f\" ${symbol:5} {bar} ({count})\")\n \n print()\n \n # Recent Buzz Snippets\n print(\"💬 WHAT PEOPLE ARE SAYING:\")\n print()\n for item in all_buzz[:8]:\n author = item.get('author', 'anon')\n text = item.get('text', '')[:120]\n engagement = item.get('engagement', 0)\n print(f\" @{author} ({engagement}♥): {text}...\")\n print()\n \n # Save results\n output = {\n 'timestamp': datetime.now(timezone.utc).isoformat(),\n 'rumors': all_rumors[:20],\n 'buzz': all_buzz[:30],\n 'symbol_counts': symbol_counts,\n }\n \n output_file = CACHE_DIR / 'rumor_scan_latest.json'\n output_file.write_text(json.dumps(output, indent=2, default=str))\n print(f\"💾 Saved: {output_file}\")\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":11578,"content_sha256":"315360567ac98f7edae0c9e448360ee4bdecfe3463b07954481a95c17c12dd5a"},{"filename":"scripts/test_stock_analysis.py","content":"#!/usr/bin/env python3\n# /// script\n# requires-python = \">=3.10\"\n# dependencies = [\n# \"pytest>=8.0.0\",\n# \"yfinance>=0.2.40\",\n# \"pandas>=2.0.0\",\n# ]\n# ///\n\"\"\"\nTests for Stock Analysis Skill v6.0\n\nRun with: uv run pytest test_stock_analysis.py -v\n\"\"\"\n\nimport json\nimport pytest\nfrom unittest.mock import Mock, patch, MagicMock\nfrom datetime import datetime, timezone\nimport pandas as pd\n\n# Import modules to test\nfrom analyze_stock import (\n detect_asset_type,\n calculate_rsi,\n fetch_stock_data,\n analyze_earnings_surprise,\n analyze_fundamentals,\n analyze_momentum,\n synthesize_signal,\n EarningsSurprise,\n Fundamentals,\n MomentumAnalysis,\n MarketContext,\n StockData,\n)\nfrom dividends import analyze_dividends\nfrom watchlist import (\n add_to_watchlist,\n remove_from_watchlist,\n list_watchlist,\n WatchlistItem,\n)\nfrom portfolio import PortfolioStore\n\n\nclass TestAssetTypeDetection:\n \"\"\"Test asset type detection.\"\"\"\n \n def test_stock_detection(self):\n assert detect_asset_type(\"AAPL\") == \"stock\"\n assert detect_asset_type(\"MSFT\") == \"stock\"\n assert detect_asset_type(\"googl\") == \"stock\"\n \n def test_crypto_detection(self):\n assert detect_asset_type(\"BTC-USD\") == \"crypto\"\n assert detect_asset_type(\"ETH-USD\") == \"crypto\"\n assert detect_asset_type(\"sol-usd\") == \"crypto\"\n \n def test_edge_cases(self):\n # Ticker ending in USD but not crypto format\n assert detect_asset_type(\"MUSD\") == \"stock\"\n # Numbers in ticker\n assert detect_asset_type(\"BRK.B\") == \"stock\"\n\n\nclass TestRSICalculation:\n \"\"\"Test RSI calculation.\"\"\"\n \n def test_rsi_overbought(self):\n \"\"\"Test RSI > 70 (overbought).\"\"\"\n # Create rising prices\n prices = pd.Series([100 + i * 2 for i in range(20)])\n rsi = calculate_rsi(prices, period=14)\n assert rsi is not None\n assert rsi > 70\n \n def test_rsi_oversold(self):\n \"\"\"Test RSI \u003c 30 (oversold).\"\"\"\n # Create falling prices\n prices = pd.Series([100 - i * 2 for i in range(20)])\n rsi = calculate_rsi(prices, period=14)\n assert rsi is not None\n assert rsi \u003c 30\n \n def test_rsi_insufficient_data(self):\n \"\"\"Test RSI with insufficient data.\"\"\"\n prices = pd.Series([100, 101, 102]) # Too few points\n rsi = calculate_rsi(prices, period=14)\n assert rsi is None\n\n\nclass TestEarningsSurprise:\n \"\"\"Test earnings surprise analysis.\"\"\"\n \n def test_earnings_beat(self):\n \"\"\"Test positive earnings surprise.\"\"\"\n # Mock StockData with earnings beat\n mock_earnings = pd.DataFrame({\n \"Reported EPS\": [1.50],\n \"EPS Estimate\": [1.20],\n }, index=[pd.Timestamp(\"2024-01-15\")])\n \n mock_data = Mock(spec=StockData)\n mock_data.earnings_history = mock_earnings\n \n result = analyze_earnings_surprise(mock_data)\n \n assert result is not None\n assert result.score > 0\n assert result.surprise_pct > 0\n assert \"Beat\" in result.explanation\n \n def test_earnings_miss(self):\n \"\"\"Test negative earnings surprise.\"\"\"\n mock_earnings = pd.DataFrame({\n \"Reported EPS\": [0.80],\n \"EPS Estimate\": [1.00],\n }, index=[pd.Timestamp(\"2024-01-15\")])\n \n mock_data = Mock(spec=StockData)\n mock_data.earnings_history = mock_earnings\n \n result = analyze_earnings_surprise(mock_data)\n \n assert result is not None\n assert result.score \u003c 0\n assert result.surprise_pct \u003c 0\n assert \"Missed\" in result.explanation\n\n\nclass TestFundamentals:\n \"\"\"Test fundamentals analysis.\"\"\"\n \n def test_strong_fundamentals(self):\n \"\"\"Test stock with strong fundamentals.\"\"\"\n mock_data = Mock(spec=StockData)\n mock_data.info = {\n \"trailingPE\": 15,\n \"operatingMargins\": 0.25,\n \"revenueGrowth\": 0.30,\n \"debtToEquity\": 30,\n }\n \n result = analyze_fundamentals(mock_data)\n \n assert result is not None\n assert result.score > 0\n assert \"pe_ratio\" in result.key_metrics\n \n def test_weak_fundamentals(self):\n \"\"\"Test stock with weak fundamentals.\"\"\"\n mock_data = Mock(spec=StockData)\n mock_data.info = {\n \"trailingPE\": 50,\n \"operatingMargins\": 0.02,\n \"revenueGrowth\": -0.10,\n \"debtToEquity\": 300,\n }\n \n result = analyze_fundamentals(mock_data)\n \n assert result is not None\n assert result.score \u003c 0\n\n\nclass TestMomentum:\n \"\"\"Test momentum analysis.\"\"\"\n \n def test_overbought_momentum(self):\n \"\"\"Test overbought conditions.\"\"\"\n # Create mock price history with rising prices near 52w high\n dates = pd.date_range(end=datetime.now(), periods=100)\n prices = pd.DataFrame({\n \"Close\": [100 + i * 0.5 for i in range(100)],\n \"Volume\": [1000000] * 100,\n }, index=dates)\n \n mock_data = Mock(spec=StockData)\n mock_data.price_history = prices\n mock_data.info = {\n \"fiftyTwoWeekHigh\": 150,\n \"fiftyTwoWeekLow\": 80,\n \"regularMarketPrice\": 148,\n }\n \n result = analyze_momentum(mock_data)\n \n assert result is not None\n assert result.rsi_status == \"overbought\"\n assert result.near_52w_high == True\n assert result.score \u003c 0 # Overbought = negative score\n\n\nclass TestSignalSynthesis:\n \"\"\"Test signal synthesis.\"\"\"\n \n def test_buy_signal(self):\n \"\"\"Test BUY recommendation synthesis.\"\"\"\n earnings = EarningsSurprise(score=0.8, explanation=\"Beat by 20%\", actual_eps=1.2, expected_eps=1.0, surprise_pct=20)\n fundamentals = Fundamentals(score=0.6, key_metrics={\"pe_ratio\": 15}, explanation=\"Strong margins\")\n \n signal = synthesize_signal(\n ticker=\"TEST\",\n company_name=\"Test Corp\",\n earnings=earnings,\n fundamentals=fundamentals,\n analysts=None,\n historical=None,\n market_context=None,\n sector=None,\n earnings_timing=None,\n momentum=None,\n sentiment=None,\n )\n \n assert signal.recommendation == \"BUY\"\n assert signal.confidence > 0.5\n \n def test_sell_signal(self):\n \"\"\"Test SELL recommendation synthesis.\"\"\"\n earnings = EarningsSurprise(score=-0.8, explanation=\"Missed by 20%\", actual_eps=0.8, expected_eps=1.0, surprise_pct=-20)\n fundamentals = Fundamentals(score=-0.6, key_metrics={\"pe_ratio\": 50}, explanation=\"Weak margins\")\n \n signal = synthesize_signal(\n ticker=\"TEST\",\n company_name=\"Test Corp\",\n earnings=earnings,\n fundamentals=fundamentals,\n analysts=None,\n historical=None,\n market_context=None,\n sector=None,\n earnings_timing=None,\n momentum=None,\n sentiment=None,\n )\n \n assert signal.recommendation == \"SELL\"\n \n def test_risk_off_penalty(self):\n \"\"\"Test risk-off mode reduces BUY confidence.\"\"\"\n earnings = EarningsSurprise(score=0.8, explanation=\"Beat\", actual_eps=1.2, expected_eps=1.0, surprise_pct=20)\n fundamentals = Fundamentals(score=0.6, key_metrics={}, explanation=\"Strong\")\n market = MarketContext(\n vix_level=25,\n vix_status=\"elevated\",\n spy_trend_10d=2.0,\n qqq_trend_10d=1.5,\n market_regime=\"choppy\",\n score=-0.2,\n explanation=\"Risk-off\",\n gld_change_5d=3.0,\n tlt_change_5d=2.0,\n uup_change_5d=1.5,\n risk_off_detected=True,\n )\n \n signal = synthesize_signal(\n ticker=\"TEST\",\n company_name=\"Test Corp\",\n earnings=earnings,\n fundamentals=fundamentals,\n analysts=None,\n historical=None,\n market_context=market,\n sector=None,\n earnings_timing=None,\n momentum=None,\n sentiment=None,\n )\n \n # Should still be BUY but with reduced confidence\n assert signal.recommendation in [\"BUY\", \"HOLD\"]\n assert any(\"RISK-OFF\" in c for c in signal.caveats)\n\n\nclass TestWatchlist:\n \"\"\"Test watchlist functionality.\"\"\"\n \n @patch('watchlist.get_current_price')\n @patch('watchlist.save_watchlist')\n @patch('watchlist.load_watchlist')\n def test_add_to_watchlist(self, mock_load, mock_save, mock_price):\n \"\"\"Test adding ticker to watchlist.\"\"\"\n mock_load.return_value = []\n mock_price.return_value = 150.0\n mock_save.return_value = None\n \n result = add_to_watchlist(\"AAPL\", target_price=200.0)\n \n assert result[\"success\"] == True\n assert result[\"action\"] == \"added\"\n assert result[\"ticker\"] == \"AAPL\"\n assert result[\"target_price\"] == 200.0\n \n @patch('watchlist.save_watchlist')\n @patch('watchlist.load_watchlist')\n def test_remove_from_watchlist(self, mock_load, mock_save):\n \"\"\"Test removing ticker from watchlist.\"\"\"\n mock_load.return_value = [\n WatchlistItem(ticker=\"AAPL\", added_at=\"2024-01-01T00:00:00+00:00\")\n ]\n mock_save.return_value = None\n \n result = remove_from_watchlist(\"AAPL\")\n \n assert result[\"success\"] == True\n assert result[\"removed\"] == \"AAPL\"\n\n\nclass TestDividendAnalysis:\n \"\"\"Test dividend analysis.\"\"\"\n \n @patch('yfinance.Ticker')\n def test_dividend_stock(self, mock_ticker):\n \"\"\"Test analysis of dividend-paying stock.\"\"\"\n mock_stock = Mock()\n mock_stock.info = {\n \"longName\": \"Johnson & Johnson\",\n \"regularMarketPrice\": 160.0,\n \"dividendYield\": 0.03,\n \"dividendRate\": 4.80,\n \"trailingEps\": 6.00,\n }\n mock_stock.dividends = pd.Series(\n [1.2, 1.2, 1.2, 1.2] * 5, # 5 years of quarterly dividends\n index=pd.date_range(start=\"2019-01-01\", periods=20, freq=\"Q\")\n )\n mock_ticker.return_value = mock_stock\n \n result = analyze_dividends(\"JNJ\")\n \n assert result is not None\n assert result.dividend_yield == 3.0\n assert result.payout_ratio == 80.0\n assert result.income_rating != \"no_dividend\"\n \n @patch('yfinance.Ticker')\n def test_no_dividend_stock(self, mock_ticker):\n \"\"\"Test analysis of non-dividend stock.\"\"\"\n mock_stock = Mock()\n mock_stock.info = {\n \"longName\": \"Amazon\",\n \"regularMarketPrice\": 180.0,\n \"dividendYield\": None,\n \"dividendRate\": None,\n }\n mock_ticker.return_value = mock_stock\n \n result = analyze_dividends(\"AMZN\")\n \n assert result is not None\n assert result.income_rating == \"no_dividend\"\n\n\nclass TestIntegration:\n \"\"\"Integration tests (require network).\"\"\"\n \n @pytest.mark.integration\n def test_real_stock_analysis(self):\n \"\"\"Test real stock analysis (AAPL).\"\"\"\n data = fetch_stock_data(\"AAPL\", verbose=False)\n \n assert data is not None\n assert data.ticker == \"AAPL\"\n assert data.info is not None\n assert \"regularMarketPrice\" in data.info\n \n @pytest.mark.integration\n def test_real_crypto_analysis(self):\n \"\"\"Test real crypto analysis (BTC-USD).\"\"\"\n data = fetch_stock_data(\"BTC-USD\", verbose=False)\n \n assert data is not None\n assert data.asset_type == \"crypto\"\n\n\n# Run tests\nif __name__ == \"__main__\":\n pytest.main([__file__, \"-v\", \"--ignore-glob=*integration*\"])\n","content_type":"text/x-python; charset=utf-8","language":"python","size":11958,"content_sha256":"2fe52876bdc2aa5f8dda67a7230b3b798ebdb0ccbc426c9aa959237310fe255c"},{"filename":"scripts/watchlist.py","content":"#!/usr/bin/env python3\n# /// script\n# requires-python = \">=3.10\"\n# dependencies = [\n# \"yfinance>=0.2.40\",\n# ]\n# ///\n\"\"\"\nStock Watchlist with Price Alerts.\n\nUsage:\n uv run watchlist.py add AAPL # Add to watchlist\n uv run watchlist.py add AAPL --target 200 # With price target\n uv run watchlist.py add AAPL --stop 150 # With stop loss\n uv run watchlist.py add AAPL --alert-on signal # Alert on signal change\n uv run watchlist.py remove AAPL # Remove from watchlist\n uv run watchlist.py list # Show watchlist\n uv run watchlist.py check # Check for triggered alerts\n uv run watchlist.py check --notify # Check and format for notification\n\"\"\"\n\nimport argparse\nimport json\nimport sys\nfrom dataclasses import dataclass, asdict\nfrom datetime import datetime, timezone\nfrom pathlib import Path\nfrom typing import Literal\n\nimport yfinance as yf\n\n# Storage\nWATCHLIST_DIR = Path.home() / \".clawdbot\" / \"skills\" / \"stock-analysis\"\nWATCHLIST_FILE = WATCHLIST_DIR / \"watchlist.json\"\n\n\n@dataclass\nclass WatchlistItem:\n ticker: str\n added_at: str\n price_at_add: float | None = None\n target_price: float | None = None # Alert when price >= target\n stop_price: float | None = None # Alert when price \u003c= stop\n alert_on_signal: bool = False # Alert when recommendation changes\n last_signal: str | None = None # BUY/HOLD/SELL\n last_check: str | None = None\n notes: str | None = None\n\n\n@dataclass\nclass Alert:\n ticker: str\n alert_type: Literal[\"target_hit\", \"stop_hit\", \"signal_change\"]\n message: str\n current_price: float\n trigger_value: float | str\n timestamp: str\n\n\ndef ensure_dirs():\n \"\"\"Create storage directories.\"\"\"\n WATCHLIST_DIR.mkdir(parents=True, exist_ok=True)\n\n\ndef load_watchlist() -> list[WatchlistItem]:\n \"\"\"Load watchlist from file.\"\"\"\n if WATCHLIST_FILE.exists():\n data = json.loads(WATCHLIST_FILE.read_text())\n return [WatchlistItem(**item) for item in data]\n return []\n\n\ndef save_watchlist(items: list[WatchlistItem]):\n \"\"\"Save watchlist to file.\"\"\"\n ensure_dirs()\n data = [asdict(item) for item in items]\n WATCHLIST_FILE.write_text(json.dumps(data, indent=2))\n\n\ndef get_current_price(ticker: str) -> float | None:\n \"\"\"Get current price for a ticker.\"\"\"\n try:\n stock = yf.Ticker(ticker)\n price = stock.info.get(\"regularMarketPrice\") or stock.info.get(\"currentPrice\")\n return float(price) if price else None\n except Exception:\n return None\n\n\ndef add_to_watchlist(\n ticker: str,\n target_price: float | None = None,\n stop_price: float | None = None,\n alert_on_signal: bool = False,\n notes: str | None = None,\n) -> dict:\n \"\"\"Add ticker to watchlist.\"\"\"\n ticker = ticker.upper()\n \n # Validate ticker\n current_price = get_current_price(ticker)\n if current_price is None:\n return {\"success\": False, \"error\": f\"Invalid ticker: {ticker}\"}\n \n # Load existing watchlist\n watchlist = load_watchlist()\n \n # Check if already exists\n for item in watchlist:\n if item.ticker == ticker:\n # Update existing\n item.target_price = target_price or item.target_price\n item.stop_price = stop_price or item.stop_price\n item.alert_on_signal = alert_on_signal or item.alert_on_signal\n item.notes = notes or item.notes\n save_watchlist(watchlist)\n return {\n \"success\": True,\n \"action\": \"updated\",\n \"ticker\": ticker,\n \"current_price\": current_price,\n \"target_price\": item.target_price,\n \"stop_price\": item.stop_price,\n \"alert_on_signal\": item.alert_on_signal,\n }\n \n # Add new\n item = WatchlistItem(\n ticker=ticker,\n added_at=datetime.now(timezone.utc).isoformat(),\n price_at_add=current_price,\n target_price=target_price,\n stop_price=stop_price,\n alert_on_signal=alert_on_signal,\n notes=notes,\n )\n watchlist.append(item)\n save_watchlist(watchlist)\n \n return {\n \"success\": True,\n \"action\": \"added\",\n \"ticker\": ticker,\n \"current_price\": current_price,\n \"target_price\": target_price,\n \"stop_price\": stop_price,\n \"alert_on_signal\": alert_on_signal,\n }\n\n\ndef remove_from_watchlist(ticker: str) -> dict:\n \"\"\"Remove ticker from watchlist.\"\"\"\n ticker = ticker.upper()\n watchlist = load_watchlist()\n \n original_len = len(watchlist)\n watchlist = [item for item in watchlist if item.ticker != ticker]\n \n if len(watchlist) == original_len:\n return {\"success\": False, \"error\": f\"{ticker} not in watchlist\"}\n \n save_watchlist(watchlist)\n return {\"success\": True, \"removed\": ticker}\n\n\ndef list_watchlist() -> dict:\n \"\"\"List all watchlist items with current prices.\"\"\"\n watchlist = load_watchlist()\n \n if not watchlist:\n return {\"success\": True, \"items\": [], \"count\": 0}\n \n items = []\n for item in watchlist:\n current_price = get_current_price(item.ticker)\n \n # Calculate change since added\n change_pct = None\n if current_price and item.price_at_add:\n change_pct = ((current_price - item.price_at_add) / item.price_at_add) * 100\n \n # Distance to target/stop\n to_target = None\n to_stop = None\n if current_price:\n if item.target_price:\n to_target = ((item.target_price - current_price) / current_price) * 100\n if item.stop_price:\n to_stop = ((item.stop_price - current_price) / current_price) * 100\n \n items.append({\n \"ticker\": item.ticker,\n \"current_price\": current_price,\n \"price_at_add\": item.price_at_add,\n \"change_pct\": round(change_pct, 2) if change_pct else None,\n \"target_price\": item.target_price,\n \"to_target_pct\": round(to_target, 2) if to_target else None,\n \"stop_price\": item.stop_price,\n \"to_stop_pct\": round(to_stop, 2) if to_stop else None,\n \"alert_on_signal\": item.alert_on_signal,\n \"last_signal\": item.last_signal,\n \"added_at\": item.added_at[:10],\n \"notes\": item.notes,\n })\n \n return {\"success\": True, \"items\": items, \"count\": len(items)}\n\n\ndef check_alerts(notify_format: bool = False) -> dict:\n \"\"\"Check watchlist for triggered alerts.\"\"\"\n watchlist = load_watchlist()\n alerts: list[Alert] = []\n now = datetime.now(timezone.utc).isoformat()\n \n for item in watchlist:\n current_price = get_current_price(item.ticker)\n if current_price is None:\n continue\n \n # Check target price\n if item.target_price and current_price >= item.target_price:\n alerts.append(Alert(\n ticker=item.ticker,\n alert_type=\"target_hit\",\n message=f\"🎯 {item.ticker} hit target! ${current_price:.2f} >= ${item.target_price:.2f}\",\n current_price=current_price,\n trigger_value=item.target_price,\n timestamp=now,\n ))\n \n # Check stop price\n if item.stop_price and current_price \u003c= item.stop_price:\n alerts.append(Alert(\n ticker=item.ticker,\n alert_type=\"stop_hit\",\n message=f\"🛑 {item.ticker} hit stop! ${current_price:.2f} \u003c= ${item.stop_price:.2f}\",\n current_price=current_price,\n trigger_value=item.stop_price,\n timestamp=now,\n ))\n \n # Check signal change (requires running analyze_stock)\n if item.alert_on_signal:\n try:\n import subprocess\n result = subprocess.run(\n [\"uv\", \"run\", str(Path(__file__).parent / \"analyze_stock.py\"), item.ticker, \"--output\", \"json\"],\n capture_output=True,\n text=True,\n timeout=60,\n )\n if result.returncode == 0:\n analysis = json.loads(result.stdout)\n new_signal = analysis.get(\"recommendation\")\n \n if item.last_signal and new_signal and new_signal != item.last_signal:\n alerts.append(Alert(\n ticker=item.ticker,\n alert_type=\"signal_change\",\n message=f\"📊 {item.ticker} signal changed: {item.last_signal} → {new_signal}\",\n current_price=current_price,\n trigger_value=f\"{item.last_signal} → {new_signal}\",\n timestamp=now,\n ))\n \n # Update last signal\n item.last_signal = new_signal\n except Exception:\n pass\n \n item.last_check = now\n \n # Save updated watchlist (with last_signal updates)\n save_watchlist(watchlist)\n \n # Format output\n if notify_format and alerts:\n # Format for Telegram notification\n lines = [\"📢 **Stock Alerts**\\n\"]\n for alert in alerts:\n lines.append(alert.message)\n return {\"success\": True, \"alerts\": [asdict(a) for a in alerts], \"notification\": \"\\n\".join(lines)}\n \n return {\"success\": True, \"alerts\": [asdict(a) for a in alerts], \"count\": len(alerts)}\n\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Stock Watchlist with Alerts\")\n subparsers = parser.add_subparsers(dest=\"command\", required=True)\n \n # Add\n add_parser = subparsers.add_parser(\"add\", help=\"Add ticker to watchlist\")\n add_parser.add_argument(\"ticker\", help=\"Stock ticker\")\n add_parser.add_argument(\"--target\", type=float, help=\"Target price for alert\")\n add_parser.add_argument(\"--stop\", type=float, help=\"Stop loss price for alert\")\n add_parser.add_argument(\"--alert-on\", choices=[\"signal\"], help=\"Alert on signal change\")\n add_parser.add_argument(\"--notes\", help=\"Notes\")\n \n # Remove\n remove_parser = subparsers.add_parser(\"remove\", help=\"Remove ticker from watchlist\")\n remove_parser.add_argument(\"ticker\", help=\"Stock ticker\")\n \n # List\n subparsers.add_parser(\"list\", help=\"List watchlist\")\n \n # Check\n check_parser = subparsers.add_parser(\"check\", help=\"Check for triggered alerts\")\n check_parser.add_argument(\"--notify\", action=\"store_true\", help=\"Format for notification\")\n \n args = parser.parse_args()\n \n if args.command == \"add\":\n result = add_to_watchlist(\n args.ticker,\n target_price=args.target,\n stop_price=args.stop,\n alert_on_signal=(args.alert_on == \"signal\"),\n notes=args.notes,\n )\n print(json.dumps(result, indent=2))\n \n elif args.command == \"remove\":\n result = remove_from_watchlist(args.ticker)\n print(json.dumps(result, indent=2))\n \n elif args.command == \"list\":\n result = list_watchlist()\n print(json.dumps(result, indent=2))\n \n elif args.command == \"check\":\n result = check_alerts(notify_format=args.notify)\n print(json.dumps(result, indent=2))\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":11542,"content_sha256":"342730d649fb27e3a179adebd8842b236658c4cf706cccf32e42c3c133c42dac"},{"filename":"TODO.md","content":"# Stock Analysis - Future Enhancements\n\n## Roadmap Overview\n\n### v4.0.0 (Current) - Geopolitical Risk & News Sentiment\n✅ 8 analysis dimensions with Fear/Greed, short interest, VIX structure, put/call ratio\n✅ Safe-haven indicators (GLD, TLT, UUP) with risk-off detection\n✅ Breaking news alerts via Google News RSS\n✅ Geopolitical risk mapping (Taiwan, China, Russia, Middle East, Banking)\n✅ Sector-specific crisis flagging with confidence penalties\n✅ 1h caching for shared indicators (Fear/Greed, VIX structure, breaking news)\n✅ Async parallel sentiment fetching (5 indicators with 10s timeouts)\n\n### v5.0.0 (Current) - Portfolio & Crypto\n✅ Portfolio management (create, add, remove, show assets)\n✅ Cryptocurrency support (Top 20 by market cap)\n✅ Portfolio analysis with --portfolio flag\n✅ Periodic returns (--period daily/weekly/monthly/quarterly/yearly)\n✅ Concentration warnings (>30% single asset)\n✅ Crypto fundamentals (market cap, category, BTC correlation)\n\n### v4.1.0 - Performance & Completeness\n✅ Full insider trading parsing via edgartools (Task #1)\n✅ Market context caching with 1h TTL (Task #3b)\n🔧 SEC EDGAR rate limit monitoring (Task #4 - low priority)\n\n### Future (v6.0+)\n💡 Research phase: Social sentiment, fund flows, on-chain metrics\n\n---\n\n## Sentiment Analysis Improvements\n\n### 1. Implement Full Insider Trading Parsing\n**Status**: ✅ DONE\n**Priority**: Medium\n**Effort**: 2-3 hours\n\n**Current State**:\n- ✅ `get_insider_activity()` fetches Form 4 filings via edgartools\n- ✅ SEC identity configured (`[email protected]`)\n- ✅ Aggregates buys/sells over 90-day window\n- ✅ Scoring logic: strong buying (+0.8), moderate (+0.4), neutral (0), moderate selling (-0.4), strong (-0.8)\n\n**Tasks**:\n- [ ] Research edgartools API for Form 4 parsing\n- [ ] Implement transaction aggregation (90-day window)\n- [ ] Calculate net shares bought/sold\n- [ ] Calculate net value in millions USD\n- [ ] Apply scoring logic:\n - Strong buying (>100K shares or >$1M): +0.8\n - Moderate buying (>10K shares or >$0.1M): +0.4\n - Neutral: 0\n - Moderate selling: -0.4\n - Strong selling: -0.8\n- [ ] Add error handling for missing/incomplete filings\n- [ ] Test with multiple tickers (BAC, TSLA, AAPL)\n- [ ] Verify SEC rate limit compliance (10 req/s)\n\n**Expected Impact**:\n- Insider activity detection for 4th sentiment indicator\n- Increase from 3/5 to 4/5 indicators typically available\n\n---\n\n### 2. Add Parallel Async Fetching\n**Status**: ✅ DONE (sentiment indicators)\n**Priority**: High\n**Effort**: 4-6 hours\n\n**Current State**:\n- ✅ Sentiment indicators fetched in parallel via `asyncio.gather()`\n- ✅ 10s timeout per indicator\n- Main data fetches (yfinance) still sequential (acceptable)\n\n**Tasks**:\n- [ ] Convert sentiment helper functions to async\n - [ ] `async def get_fear_greed_index()`\n - [ ] `async def get_short_interest(data)`\n - [ ] `async def get_vix_term_structure()`\n - [ ] `async def get_insider_activity(ticker)`\n - [ ] `async def get_put_call_ratio(data)`\n- [ ] Update `analyze_sentiment()` to use `asyncio.gather()`\n- [ ] Handle yfinance thread safety (may need locks)\n- [ ] Add timeout per indicator (10s max)\n- [ ] Test with multiple stocks in sequence\n- [ ] Measure actual runtime improvement\n- [ ] Update SKILL.md with new runtime (target: 3-4s)\n\n**Expected Impact**:\n- Reduce runtime from 6-10s to 3-4s per stock\n- Better user experience for multi-stock analysis\n\n---\n\n### 3. Add Caching for Shared Indicators\n**Status**: ✅ DONE (sentiment + breaking news)\n**Priority**: Medium\n**Effort**: 2-3 hours\n\n**Current State**:\n- ✅ Fear & Greed Index cached (1h TTL)\n- ✅ VIX term structure cached (1h TTL)\n- ✅ Breaking news cached (1h TTL)\n- ✅ Market context (VIX/SPY/QQQ/GLD/TLT/UUP) cached (1h TTL)\n\n**Tasks**:\n- [ ] Design cache structure (simple dict or functools.lru_cache)\n- [ ] Implement TTL (time-to-live):\n - Fear & Greed: 1 hour\n - VIX structure: 1 hour\n - Short interest: No cache (per-stock)\n - Insider activity: No cache (per-stock)\n - Put/Call ratio: No cache (per-stock)\n- [ ] Add cache invalidation logic\n- [ ] Add verbose logging for cache hits/misses\n- [ ] Test multi-stock analysis (e.g., `BAC TSLA AAPL`)\n- [ ] Measure performance improvement\n- [ ] Document caching behavior in SKILL.md\n\n**Expected Impact**:\n- Multi-stock analysis faster (e.g., 3 stocks: 18-30s → 10-15s)\n- Reduced API calls to Fear/Greed and VIX data sources\n- Same-session analysis efficiency\n\n---\n\n### 4. Monitor SEC EDGAR Rate Limits\n**Status**: Not Started\n**Priority**: Low (until insider trading implemented)\n**Effort**: 1-2 hours\n\n**Current State**:\n- SEC EDGAR API has 10 requests/second rate limit\n- No rate limit tracking or logging\n- edgartools may handle rate limiting internally\n\n**Tasks**:\n- [ ] Research edgartools rate limit handling\n- [ ] Add request counter/tracker if needed\n- [ ] Implement exponential backoff on 429 errors\n- [ ] Add logging for rate limit hits\n- [ ] Test with high-volume scenarios (10+ stocks in quick succession)\n- [ ] Document rate limit behavior\n- [ ] Add error message if rate limited: \"SEC API rate limited, try again in 1 minute\"\n\n**Expected Impact**:\n- Robust handling of SEC API limits in production\n- Clear user feedback if limits hit\n- Prevent API blocking/banning\n\n---\n\n## Stock Analysis 4.0: Geopolitical Risk & News Sentiment\n\n### What's Currently Missing\n\nThe current implementation captures:\n- ✅ VIX (general market fear)\n- ✅ SPY/QQQ trends (market direction)\n- ✅ Sector performance\n\nWhat we **don't** have yet:\n- ❌ Geopolitical risk indicators\n- ❌ News sentiment analysis\n- ❌ Sector-specific crisis flags\n\n---\n\n### 7. Geopolitical Risk Index\n**Status**: ✅ DONE (keyword-based)\n**Priority**: High\n**Effort**: 8-12 hours\n\n**Proposed Approach**:\nOption A: Use GPRD (Geopolitical Risk Daily Index) from policyuncertainty.com\nOption B: Scan news APIs (NewsAPI, GDELT) for geopolitical keywords\n\n**Tasks**:\n- [ ] Research free geopolitical risk data sources\n - [ ] Check policyuncertainty.com API availability\n - [ ] Evaluate NewsAPI free tier limits\n - [ ] Consider GDELT Project (free, comprehensive)\n- [ ] Design risk scoring system (0-100 scale)\n- [ ] Implement data fetching with caching (4-hour TTL)\n- [ ] Map risk levels to sentiment scores:\n - Low risk (0-30): +0.2 (bullish)\n - Moderate risk (30-60): 0 (neutral)\n - High risk (60-80): -0.3 (caution)\n - Extreme risk (80-100): -0.5 (bearish)\n- [ ] Add to sentiment analysis as 6th indicator\n- [ ] Test with historical crisis periods\n- [ ] Update SKILL.md with geopolitical indicator\n\n**Expected Impact**:\n- Early warning for market-wide risk events\n- Better context for earnings-season volatility\n- Complement to VIX (VIX is reactive, geopolitical is predictive)\n\n**Example Output**:\n```\n⚠️ GEOPOLITICAL RISK: HIGH (72/100)\n Context: Elevated Taiwan tensions detected\n Market Impact: Risk-off sentiment likely\n```\n\n---\n\n### 8. Sector-Specific Crisis Mapping\n**Status**: ✅ DONE\n**Priority**: High\n**Effort**: 6-8 hours\n\n**Current Gap**:\n- No mapping between geopolitical events and affected sectors\n- No automatic flagging of at-risk holdings\n\n**Proposed Risk Mapping**:\n\n| Geopolitical Event | Affected Sectors | Example Tickers |\n|-------------------|------------------|-----------------|\n| Taiwan conflict | Semiconductors | NVDA, AMD, TSM, INTC |\n| Russia-Ukraine | Energy, Agriculture | XLE, MOS, CF, NTR |\n| Middle East escalation | Oil, Defense | XOM, CVX, LMT, RTX |\n| China tensions | Tech supply chain, Retail | AAPL, QCOM, NKE, SBUX |\n| Banking crisis | Financials | JPM, BAC, WFC, C |\n\n**Tasks**:\n- [ ] Build event → sector → ticker mapping database\n- [ ] Implement keyword detection in news feeds:\n - \"Taiwan\" + \"military\" → Semiconductors ⚠️\n - \"Russia\" + \"sanctions\" → Energy ⚠️\n - \"Iran\" + \"attack\" → Oil, Defense ⚠️\n - \"China\" + \"tariffs\" → Tech, Consumer ⚠️\n- [ ] Add sector exposure check to analysis\n- [ ] Generate automatic warnings in output\n- [ ] Apply confidence penalty for high-risk sectors\n- [ ] Test with historical crisis events\n- [ ] Document in SKILL.md\n\n**Expected Impact**:\n- Automatic detection of sector-specific risks\n- Clear warnings for exposed holdings\n- Reduced false positives (only flag relevant sectors)\n\n**Example Output**:\n```\n⚠️ SECTOR RISK ALERT: Semiconductors\n Event: Taiwan military exercises (elevated tensions)\n Impact: NVDA HIGH RISK - supply chain exposure\n Recommendation: HOLD → downgraded from BUY\n```\n\n---\n\n### 9. Breaking News Check\n**Status**: ✅ DONE\n**Priority**: Medium\n**Effort**: 4-6 hours\n\n**Current Gap**:\n- No real-time news scanning before analysis\n- User might get stale recommendation during breaking events\n\n**Proposed Solution**:\n- Scan Google News or Reuters RSS before analysis\n- Flag high-impact keywords within last 24 hours\n\n**Tasks**:\n- [ ] Choose news source (Google News RSS, Reuters API, or NewsAPI)\n- [ ] Implement news fetching with 24-hour lookback\n- [ ] Define crisis keywords:\n - **War/Conflict**: \"war\", \"invasion\", \"military strike\", \"attack\"\n - **Economic**: \"recession\", \"crisis\", \"collapse\", \"default\"\n - **Regulatory**: \"sanctions\", \"embargo\", \"ban\", \"investigation\"\n - **Natural disaster**: \"earthquake\", \"hurricane\", \"pandemic\"\n- [ ] Add ticker-specific news check (company name + keywords)\n- [ ] Generate automatic caveat in output\n- [ ] Cache news check results (1 hour TTL)\n- [ ] Add `--skip-news` flag for offline mode\n- [ ] Test with historical crisis dates\n- [ ] Document in SKILL.md\n\n**Expected Impact**:\n- Real-time awareness of breaking events\n- Automatic caveats during high volatility\n- User protection from stale recommendations\n\n**Example Output**:\n```\n⚠️ BREAKING NEWS ALERT (last 6 hours):\n \"Fed announces emergency rate hike\"\n Impact: Market-wide volatility expected\n Caveat: Analysis may be outdated - rerun in 24h\n```\n\n---\n\n### 10. Safe-Haven Indicators\n**Status**: ✅ DONE\n**Priority**: Medium\n**Effort**: 3-4 hours\n\n**Current Gap**:\n- No detection of \"risk-off\" market regime\n- VIX alone is insufficient (measures implied volatility, not capital flows)\n\n**Proposed Indicators**:\n- Gold (GLD) - Flight to safety\n- US Treasuries (TLT) - Bond market fear\n- USD Index (UUP) - Dollar strength during crisis\n\n**Risk-Off Detection Logic**:\n```\nIF GLD +2% AND TLT +1% AND UUP +1% (all rising together)\nTHEN Market Regime = RISK-OFF\n```\n\n**Tasks**:\n- [ ] Fetch GLD, TLT, UUP price data (5-day change)\n- [ ] Implement risk-off detection algorithm\n- [ ] Add to market context analysis\n- [ ] Apply broad risk penalty:\n - Risk-off detected → Reduce all BUY confidence by 30%\n - Add caveat: \"Market in risk-off mode - defensive positioning recommended\"\n- [ ] Test with historical crisis periods (2008, 2020, 2022)\n- [ ] Add verbose output for safe-haven movements\n- [ ] Document in SKILL.md\n\n**Expected Impact**:\n- Detect market-wide flight to safety\n- Automatic risk reduction during panics\n- Complement geopolitical risk scoring\n\n**Example Output**:\n```\n🛡️ SAFE-HAVEN ALERT: Risk-off mode detected\n - Gold (GLD): +3.2% (5d)\n - Treasuries (TLT): +2.1% (5d)\n - USD Index: +1.8% (5d)\n Recommendation: Reduce equity exposure, favor defensives\n```\n\n---\n\n## General Improvements\n\n### 11. Add Social Sentiment (Future Phase)\n**Status**: Deferred\n**Priority**: Low\n**Effort**: 8-12 hours\n\n**Notes**:\n- Requires free API (Twitter/Reddit alternatives?)\n- Most sentiment APIs are paid (StockTwits, etc.)\n- Research needed for viable free sources\n\n### 12. Add Fund Flows (Future Phase)\n**Status**: Deferred\n**Priority**: Low\n**Effort**: 6-8 hours\n\n**Notes**:\n- Requires ETF flow data\n- May need paid data source\n- Research free alternatives\n\n---\n\n## Implementation Priorities\n\n### v4.1.0 Complete\n- ✅ Task #1 - Insider trading parsing via edgartools\n- ✅ Task #3b - Market context caching (1h TTL)\n- 🔧 Task #4 - SEC EDGAR rate limits (low priority, only if hitting limits)\n\n### Completed in v4.0.0\n- ✅ Task #2 - Async parallel fetching (sentiment)\n- ✅ Task #3 - Caching for shared indicators (sentiment + news)\n- ✅ Task #7 - Geopolitical risk (keyword-based)\n- ✅ Task #8 - Sector-specific crisis mapping\n- ✅ Task #9 - Breaking news check\n- ✅ Task #10 - Safe-haven indicators\n\n---\n\n## Version History\n\n- **v5.0.0** (2026-01-16): Portfolio management, cryptocurrency support (Top 20), periodic analysis\n- **v4.1.0** (2026-01-16): Full insider trading parsing via edgartools, market context caching\n- **v4.0.0** (2026-01-15): Geopolitical risk, breaking news, safe-haven detection, sector crisis mapping\n- **v3.0.0** (2026-01-15): Sentiment analysis added with 5 indicators (3-4 typically working)\n- **v2.0.0**: Market context, sector performance, earnings timing, momentum\n- **v1.0.0**: Initial release with earnings, fundamentals, analysts, historical\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12848,"content_sha256":"3e3cc7022797587ee8298e1a0503bebf4a3494c9ebda15a9f951799a7b310682"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Stock Analysis v6.1","type":"text"}]},{"type":"paragraph","content":[{"text":"Analyze US stocks and cryptocurrencies with 8-dimension analysis, portfolio management, watchlists, alerts, dividend analysis, and ","type":"text"},{"text":"viral trend detection","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"What's New in v6.2","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🔮 ","type":"text"},{"text":"Rumor Scanner","type":"text","marks":[{"type":"strong"}]},{"text":" — Early signals before mainstream news","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"M&A rumors and takeover bids","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Insider buying/selling activity","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Analyst upgrades/downgrades","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Twitter/X \"hearing that...\", \"sources say...\" detection","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🎯 ","type":"text"},{"text":"Impact Scoring","type":"text","marks":[{"type":"strong"}]},{"text":" — Rumors ranked by potential market impact","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"What's in v6.1","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🔥 ","type":"text"},{"text":"Hot Scanner","type":"text","marks":[{"type":"strong"}]},{"text":" — Find viral stocks & crypto across multiple sources","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🐦 ","type":"text"},{"text":"Twitter/X Integration","type":"text","marks":[{"type":"strong"}]},{"text":" — Social sentiment via bird CLI","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📰 ","type":"text"},{"text":"Multi-Source Aggregation","type":"text","marks":[{"type":"strong"}]},{"text":" — CoinGecko, Google News, Yahoo Finance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⏰ ","type":"text"},{"text":"Cron Support","type":"text","marks":[{"type":"strong"}]},{"text":" — Daily trend reports","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"What's in v6.0","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🆕 ","type":"text"},{"text":"Watchlist + Alerts","type":"text","marks":[{"type":"strong"}]},{"text":" — Price targets, stop losses, signal changes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🆕 ","type":"text"},{"text":"Dividend Analysis","type":"text","marks":[{"type":"strong"}]},{"text":" — Yield, payout ratio, growth, safety score","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🆕 ","type":"text"},{"text":"Fast Mode","type":"text","marks":[{"type":"strong"}]},{"text":" — ","type":"text"},{"text":"--fast","type":"text","marks":[{"type":"code_inline"}]},{"text":" skips slow analyses (insider, news)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🆕 ","type":"text"},{"text":"Improved Performance","type":"text","marks":[{"type":"strong"}]},{"text":" — ","type":"text"},{"text":"--no-insider","type":"text","marks":[{"type":"code_inline"}]},{"text":" for faster runs","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Commands","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stock Analysis","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Basic analysis\nuv run {baseDir}/scripts/analyze_stock.py AAPL\n\n# Fast mode (skips insider trading & breaking news)\nuv run {baseDir}/scripts/analyze_stock.py AAPL --fast\n\n# Compare multiple\nuv run {baseDir}/scripts/analyze_stock.py AAPL MSFT GOOGL\n\n# Crypto\nuv run {baseDir}/scripts/analyze_stock.py BTC-USD ETH-USD","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Dividend Analysis (NEW v6.0)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Analyze dividends\nuv run {baseDir}/scripts/dividends.py JNJ\n\n# Compare dividend stocks\nuv run {baseDir}/scripts/dividends.py JNJ PG KO MCD --output json","type":"text"}]},{"type":"paragraph","content":[{"text":"Dividend Metrics:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Dividend Yield & Annual Payout","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Payout Ratio (safe/moderate/high/unsustainable)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"5-Year Dividend Growth (CAGR)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Consecutive Years of Increases","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Safety Score (0-100)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Income Rating (excellent/good/moderate/poor)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Watchlist + Alerts (NEW v6.0)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Add to watchlist\nuv run {baseDir}/scripts/watchlist.py add AAPL\n\n# With price target alert\nuv run {baseDir}/scripts/watchlist.py add AAPL --target 200\n\n# With stop loss alert\nuv run {baseDir}/scripts/watchlist.py add AAPL --stop 150\n\n# Alert on signal change (BUY→SELL)\nuv run {baseDir}/scripts/watchlist.py add AAPL --alert-on signal\n\n# View watchlist\nuv run {baseDir}/scripts/watchlist.py list\n\n# Check for triggered alerts\nuv run {baseDir}/scripts/watchlist.py check\nuv run {baseDir}/scripts/watchlist.py check --notify # Telegram format\n\n# Remove from watchlist\nuv run {baseDir}/scripts/watchlist.py remove AAPL","type":"text"}]},{"type":"paragraph","content":[{"text":"Alert Types:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🎯 ","type":"text"},{"text":"Target Hit","type":"text","marks":[{"type":"strong"}]},{"text":" — Price >= target","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🛑 ","type":"text"},{"text":"Stop Hit","type":"text","marks":[{"type":"strong"}]},{"text":" — Price \u003c= stop","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📊 ","type":"text"},{"text":"Signal Change","type":"text","marks":[{"type":"strong"}]},{"text":" — BUY/HOLD/SELL changed","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Portfolio Management","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Create portfolio\nuv run {baseDir}/scripts/portfolio.py create \"Tech Portfolio\"\n\n# Add assets\nuv run {baseDir}/scripts/portfolio.py add AAPL --quantity 100 --cost 150\nuv run {baseDir}/scripts/portfolio.py add BTC-USD --quantity 0.5 --cost 40000\n\n# View portfolio\nuv run {baseDir}/scripts/portfolio.py show\n\n# Analyze with period returns\nuv run {baseDir}/scripts/analyze_stock.py --portfolio \"Tech Portfolio\" --period weekly","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"🔥 Hot Scanner (NEW v6.1)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Full scan - find what's trending NOW\npython3 {baseDir}/scripts/hot_scanner.py\n\n# Fast scan (skip social media)\npython3 {baseDir}/scripts/hot_scanner.py --no-social\n\n# JSON output for automation\npython3 {baseDir}/scripts/hot_scanner.py --json","type":"text"}]},{"type":"paragraph","content":[{"text":"Data Sources:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📊 CoinGecko Trending — Top 15 trending coins","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📈 CoinGecko Movers — Biggest gainers/losers","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📰 Google News — Finance & crypto headlines","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📉 Yahoo Finance — Gainers, losers, most active","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🐦 Twitter/X — Social sentiment (requires auth)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Output:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Top trending by mention count","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Crypto highlights with 24h changes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Stock movers by category","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Breaking news with tickers","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Twitter Setup (Optional):","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Install bird: ","type":"text"},{"text":"npm install -g @steipete/bird","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Login to x.com in Safari/Chrome","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create ","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":" with ","type":"text"},{"text":"AUTH_TOKEN","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"CT0","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"🔮 Rumor Scanner (NEW v6.2)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Find early signals, M&A rumors, insider activity\npython3 {baseDir}/scripts/rumor_scanner.py","type":"text"}]},{"type":"paragraph","content":[{"text":"What it finds:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🏢 ","type":"text"},{"text":"M&A Rumors","type":"text","marks":[{"type":"strong"}]},{"text":" — Merger, acquisition, takeover bids","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"👔 ","type":"text"},{"text":"Insider Activity","type":"text","marks":[{"type":"strong"}]},{"text":" — CEO/Director buying/selling","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📊 ","type":"text"},{"text":"Analyst Actions","type":"text","marks":[{"type":"strong"}]},{"text":" — Upgrades, downgrades, price target changes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🐦 ","type":"text"},{"text":"Twitter Whispers","type":"text","marks":[{"type":"strong"}]},{"text":" — \"hearing that...\", \"sources say...\", \"rumor\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚖️ ","type":"text"},{"text":"SEC Activity","type":"text","marks":[{"type":"strong"}]},{"text":" — Investigations, filings","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Impact Scoring:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Each rumor is scored by potential market impact (1-10)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"M&A/Takeover: +5 points","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Insider buying: +4 points","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Upgrade/Downgrade: +3 points","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Hearing\"/\"Sources say\": +2 points","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"High engagement: +2 bonus","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Best Practice:","type":"text","marks":[{"type":"strong"}]},{"text":" Run at 07:00 before US market open to catch pre-market signals.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Analysis Dimensions (8 for stocks, 3 for crypto)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stocks","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dimension","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Weight","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Earnings Surprise","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"30%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"EPS beat/miss","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fundamentals","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"20%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"P/E, margins, growth","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Analyst Sentiment","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"20%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Ratings, price targets","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Historical","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Past earnings reactions","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Market Context","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"VIX, SPY/QQQ trends","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sector","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"15%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Relative strength","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Momentum","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"15%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"RSI, 52-week range","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sentiment","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fear/Greed, shorts, insiders","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Crypto","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Market Cap & Category","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"BTC Correlation (30-day)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Momentum (RSI, range)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Sentiment Sub-Indicators","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Indicator","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Source","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Signal","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fear & Greed","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CNN","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Contrarian (fear=buy)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Short Interest","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Yahoo","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Squeeze potential","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"VIX Structure","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Futures","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Stress detection","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Insider Trades","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SEC EDGAR","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Smart money","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Put/Call Ratio","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Options","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sentiment extreme","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Risk Detection","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"Pre-Earnings","type":"text","marks":[{"type":"strong"}]},{"text":" — Warns if \u003c 14 days to earnings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"Post-Spike","type":"text","marks":[{"type":"strong"}]},{"text":" — Flags if up >15% in 5 days","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"Overbought","type":"text","marks":[{"type":"strong"}]},{"text":" — RSI >70 + near 52w high","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"Risk-Off","type":"text","marks":[{"type":"strong"}]},{"text":" — GLD/TLT/UUP rising together","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"Geopolitical","type":"text","marks":[{"type":"strong"}]},{"text":" — Taiwan, China, Russia, Middle East keywords","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"Breaking News","type":"text","marks":[{"type":"strong"}]},{"text":" — Crisis keywords in last 24h","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Performance Options","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Flag","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Effect","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Speed","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"(default)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Full analysis","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5-10s","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--no-insider","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Skip SEC EDGAR","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3-5s","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--fast","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Skip insider + news","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2-3s","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Supported Cryptos (Top 20)","type":"text"}]},{"type":"paragraph","content":[{"text":"BTC, ETH, BNB, SOL, XRP, ADA, DOGE, AVAX, DOT, MATIC, LINK, ATOM, UNI, LTC, BCH, XLM, ALGO, VET, FIL, NEAR","type":"text"}]},{"type":"paragraph","content":[{"text":"(Use ","type":"text"},{"text":"-USD","type":"text","marks":[{"type":"code_inline"}]},{"text":" suffix: ","type":"text"},{"text":"BTC-USD","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"ETH-USD","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Data Storage","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"File","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Location","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Portfolios","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.clawdbot/skills/stock-analysis/portfolios.json","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Watchlist","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.clawdbot/skills/stock-analysis/watchlist.json","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Limitations","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Yahoo Finance may lag 15-20 minutes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Short interest lags ~2 weeks (FINRA)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Insider trades lag 2-3 days (SEC filing)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"US markets only (non-US incomplete)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Breaking news: 1h cache, keyword-based","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Disclaimer","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"⚠️ ","type":"text"},{"text":"NOT FINANCIAL ADVICE.","type":"text","marks":[{"type":"strong"}]},{"text":" For informational purposes only. Consult a licensed financial advisor before making investment decisions.","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"stock-analysis","author":"@skillopedia","source":{"stars":2012,"repo_name":"openclaw-master-skills","origin_url":"https://github.com/leoyeai/openclaw-master-skills/blob/HEAD/skills/stock-analysis/SKILL.md","repo_owner":"leoyeai","body_sha256":"522d24f119f0f9a1f732bc304ac8e0d2df31c36128dfecea6b7993b1478befcb","cluster_key":"a215b3bf2f7091b019ef87565ba48af90639a2c07d4b143645a7f536a6e80f59","clean_bundle":{"format":"clean-skill-bundle-v1","source":"leoyeai/openclaw-master-skills/skills/stock-analysis/SKILL.md","attachments":[{"id":"280806b4-9d4f-5f93-b3ad-b5880adf918b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/280806b4-9d4f-5f93-b3ad-b5880adf918b/attachment.md","path":"App-Plan.md","size":14708,"sha256":"98276ba3eb8d91373827e7941abf66e3b1affb684fc8dc758721ba49d50d9f31","contentType":"text/markdown; charset=utf-8"},{"id":"19aa0ef6-0661-5b03-8382-ab5a40a040e8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/19aa0ef6-0661-5b03-8382-ab5a40a040e8/attachment.md","path":"README.md","size":6390,"sha256":"899b51e9272962824c9f789f493224410fed6b87f2df7dbdf3f05d0d1edc617c","contentType":"text/markdown; charset=utf-8"},{"id":"225a128f-ffa1-57b3-9468-4ce0b5e9d90f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/225a128f-ffa1-57b3-9468-4ce0b5e9d90f/attachment.md","path":"TODO.md","size":12848,"sha256":"3e3cc7022797587ee8298e1a0503bebf4a3494c9ebda15a9f951799a7b310682","contentType":"text/markdown; charset=utf-8"},{"id":"d4372cbe-3ec3-5125-ba17-4c6760b361ba","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d4372cbe-3ec3-5125-ba17-4c6760b361ba/attachment.md","path":"docs/ARCHITECTURE.md","size":16594,"sha256":"b2a86717592fd7f719cbc1022711cd03af4f5dcfd709c738d049f7c0de0b3856","contentType":"text/markdown; charset=utf-8"},{"id":"84065227-3d1b-560c-a8c2-5a2776d69981","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/84065227-3d1b-560c-a8c2-5a2776d69981/attachment.md","path":"docs/CONCEPT.md","size":9101,"sha256":"3df36f8710cb6e64d3f0bc3c091b1c70e7eac979ba352f46fa4ac09b865c5517","contentType":"text/markdown; charset=utf-8"},{"id":"86034625-6dbe-5ef4-99a2-3c0a7e6ef94d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/86034625-6dbe-5ef4-99a2-3c0a7e6ef94d/attachment.md","path":"docs/HOT_SCANNER.md","size":5865,"sha256":"0c42df93f631b30f834d3eff27805650965b62afdf855e7e40d950415dc2666b","contentType":"text/markdown; charset=utf-8"},{"id":"50318d36-a1d7-595f-a516-eab6361e6c84","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/50318d36-a1d7-595f-a516-eab6361e6c84/attachment.md","path":"docs/README.md","size":2405,"sha256":"86c36fdce36c7c9ebb52f70966b16bdfe17016a54a4861932fc01d4b8c711912","contentType":"text/markdown; charset=utf-8"},{"id":"e4a4924b-fef5-55da-904b-7766d1f42aaa","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e4a4924b-fef5-55da-904b-7766d1f42aaa/attachment.md","path":"docs/USAGE.md","size":8898,"sha256":"9cc1aada593ae985ea755003eafed3a8f564f1af77853501c89ac48439cf9174","contentType":"text/markdown; charset=utf-8"},{"id":"a275a211-4314-5989-9c90-4db64538e9b6","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a275a211-4314-5989-9c90-4db64538e9b6/attachment.py","path":"scripts/analyze_stock.py","size":89930,"sha256":"24e05932926903ccee7e8fb5c621da5d354ae01857a020e26e77bdcb37df345a","contentType":"text/x-python; charset=utf-8"},{"id":"202f41b4-b4b1-5e70-aca0-ccb60021a660","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/202f41b4-b4b1-5e70-aca0-ccb60021a660/attachment.py","path":"scripts/dividends.py","size":13130,"sha256":"f7345eda9b5eb164502cd770fedf6230bdc9eaabc2d949d9b48b1ab02d4f4169","contentType":"text/x-python; charset=utf-8"},{"id":"02114fd8-37d8-51bf-955f-864a32f9d76f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/02114fd8-37d8-51bf-955f-864a32f9d76f/attachment.py","path":"scripts/hot_scanner.py","size":24620,"sha256":"9a0f9d57a2cc919b351e210072a061b58deaca47294b0ce67dc5bbb7839741f5","contentType":"text/x-python; charset=utf-8"},{"id":"777e6560-2728-5cb7-b1c5-f1ce45c56900","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/777e6560-2728-5cb7-b1c5-f1ce45c56900/attachment.py","path":"scripts/portfolio.py","size":18897,"sha256":"2ef732f6c0a0a9bff4ed016d75007c44d2ddd43a52bd5e25ca8716a56355523a","contentType":"text/x-python; charset=utf-8"},{"id":"85538a0e-e575-58aa-ac33-6c9811ef909c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/85538a0e-e575-58aa-ac33-6c9811ef909c/attachment.py","path":"scripts/rumor_scanner.py","size":11578,"sha256":"315360567ac98f7edae0c9e448360ee4bdecfe3463b07954481a95c17c12dd5a","contentType":"text/x-python; charset=utf-8"},{"id":"6f988e36-2471-50d3-a7e7-970746332fc8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6f988e36-2471-50d3-a7e7-970746332fc8/attachment.py","path":"scripts/test_stock_analysis.py","size":11958,"sha256":"2fe52876bdc2aa5f8dda67a7230b3b798ebdb0ccbc426c9aa959237310fe255c","contentType":"text/x-python; charset=utf-8"},{"id":"fc0c7362-3c2d-5a66-bcb8-d97bcc3bd309","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fc0c7362-3c2d-5a66-bcb8-d97bcc3bd309/attachment.py","path":"scripts/watchlist.py","size":11542,"sha256":"342730d649fb27e3a179adebd8842b236658c4cf706cccf32e42c3c133c42dac","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"19ec63105e3c8b51b6d32d5a5bca3c6cc3a47e482a86732327068fa2150fe855","attachment_count":15,"text_attachments":15,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":2,"skill_md_path":"skills/stock-analysis/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"finance-legal-compliance","category_label":"Finance"},"exact_dupes_collapsed_into_this":1},"version":"v1","category":"finance-legal-compliance","commands":["/stock - Analyze a stock or crypto (e.g., /stock AAPL)","/stock_compare - Compare multiple tickers","/stock_dividend - Analyze dividend metrics","/stock_watch - Add/remove from watchlist","/stock_alerts - Check triggered alerts","/stock_hot - Find trending stocks & crypto (Hot Scanner)","/stock_rumors - Find early signals, M&A rumors, insider activity (Rumor Scanner)","/portfolio - Show portfolio summary","/portfolio_add - Add asset to portfolio"],"homepage":"https://finance.yahoo.com","metadata":{"clawdbot":{"emoji":"📈","install":[{"id":"uv-brew","bins":["uv"],"kind":"brew","label":"Install uv (brew)","formula":"uv"}],"requires":{"env":[],"bins":["uv"]}}},"import_tag":"clean-skills-v1","description":"Analyze stocks and cryptocurrencies using Yahoo Finance data. Supports portfolio management, watchlists with alerts, dividend analysis, 8-dimension stock scoring, viral trend detection (Hot Scanner), and rumor/early signal detection. Use for stock analysis, portfolio tracking, earnings reactions, crypto monitoring, trending stocks, or finding rumors before they hit mainstream."}},"renderedAt":1782982109647}

Stock Analysis v6.1 Analyze US stocks and cryptocurrencies with 8-dimension analysis, portfolio management, watchlists, alerts, dividend analysis, and viral trend detection . What's New in v6.2 - 🔮 Rumor Scanner — Early signals before mainstream news - M&A rumors and takeover bids - Insider buying/selling activity - Analyst upgrades/downgrades - Twitter/X "hearing that...", "sources say..." detection - 🎯 Impact Scoring — Rumors ranked by potential market impact What's in v6.1 - 🔥 Hot Scanner — Find viral stocks & crypto across multiple sources - 🐦 Twitter/X Integration — Social sentiment…