概述

Stock Analysis是一个用于分析股票和加密货币的OpenClaw技能,支持8维度股票分析、加密货币分析、投资组合管理、观察列表、股息分析、热门扫描和谣言扫描功能。该技能整合了Yahoo Finance、CoinGecko、CNN Fear & Greed Index、SEC EDGAR等多个数据源,能够为用户提供清晰的BUY/HOLD/SELL投资建议,并附带详细的支持点和风险提示,帮助用户做出更明智的投资决策。

该技能特别适合两类场景:一类是你要做"快评内容",另一类是你要做"结构化研究笔记",把零散信息收敛成可复用的判断。

技能信息

  • 名称:stock-analysis
  • 描述:使用Yahoo Finance数据分析股票和加密货币,支持投资组合管理、带警报的观察列表、股息分析、8维度股票评分、热门趋势检测(Hot Scanner)和谣言/早期信号检测(Rumor Scanner)。可用于股票分析、投资组合跟踪、收益反应分析、加密货币监控、热门股票发现,或在主流新闻之前找到市场谣言。
  • 版本:6.2.0
  • 作者:udiedrichsen
  • 主页https://finance.yahoo.com
  • 依赖
    • Python 3.10+
    • yfinance>=0.2.40
    • pandas>=2.0.0
    • fear-and-greed>=0.4
    • edgartools>=2.0.0
    • feedparser>=6.0.0
  • 安装命令npx clawhub@latest install stock-analysis
  • 支持的命令
    • /stock - 分析股票或加密货币(例如:/stock AAPL)
    • /stock_compare - 比较多个代码
    • /stock_dividend - 分析股息指标
    • /stock_watch - 添加/移除观察列表
    • /stock_alerts - 检查触发的警报
    • /stock_hot - 查找热门股票和加密货币(Hot Scanner)
    • /stock_rumors - 查找早期信号、并购谣言、内幕交易活动(Rumor Scanner)
    • /portfolio - 显示投资组合摘要
    • /portfolio_add - 向投资组合添加资产

👤 作者:udiedrichsen
🦞 官方地址:https://clawhub.ai/udiedrichsen/stock-analysis
👉 Skills 下载地址:stock-analysis-6.2.0.zip

快速开始

股票分析


  1. ## 基本分析
  2. uv run scripts/analyze_stock.py AAPL
  3. ## 快速模式(跳过内幕交易和突发新闻)
  4. uv run scripts/analyze_stock.py AAPL --fast
  5. ## 比较多个股票
  6. uv run scripts/analyze_stock.py AAPL MSFT GOOGL
  7. ## 加密货币分析
  8. uv run scripts/analyze_stock.py BTC-USD ETH-USD

股息分析


  1. ## 分析股息
  2. uv run scripts/dividends.py JNJ
  3. ## 比较股息股票
  4. uv run scripts/dividends.py JNJ PG KO MCD --output json

观察列表与警报


  1. ## 添加到观察列表
  2. uv run scripts/watchlist.py add AAPL
  3. ## 带价格目标警报
  4. uv run scripts/watchlist.py add AAPL --target 200
  5. ## 带止损警报
  6. uv run scripts/watchlist.py add AAPL --stop 150
  7. ## 信号变化警报
  8. uv run scripts/watchlist.py add AAPL --alert-on signal
  9. ## 查看观察列表
  10. uv run scripts/watchlist.py list
  11. ## 检查触发的警报
  12. uv run scripts/watchlist.py check
  13. ## 移除观察列表
  14. uv run scripts/watchlist.py remove AAPL

投资组合管理


  1. ## 创建投资组合
  2. uv run scripts/portfolio.py create "Tech Portfolio"
  3. ## 添加资产
  4. uv run scripts/portfolio.py add AAPL --quantity 100 --cost 150
  5. uv run scripts/portfolio.py add BTC-USD --quantity 0.5 --cost 40000
  6. ## 查看投资组合
  7. uv run scripts/portfolio.py show
  8. ## 分析投资组合
  9. uv run scripts/analyze_stock.py --portfolio "Tech Portfolio" --period weekly

热门扫描


  1. ## 完整扫描
  2. python3 scripts/hot_scanner.py
  3. ## 快速扫描(跳过社交媒体)
  4. python3 scripts/hot_scanner.py --no-social
  5. ## JSON输出
  6. python3 scripts/hot_scanner.py --json

谣言扫描


  1. ## 查找早期信号、并购谣言、内幕交易活动
  2. python3 scripts/rumor_scanner.py

功能详解

1. 股票分析

股票分析功能提供8维度的全面分析,包括:

  • 收益惊喜(30%权重):EPS超出/低于预期的情况
  • 基本面(20%权重):市盈率、利润率、增长率等
  • 分析师情绪(20%权重):评级和目标价格
  • 历史模式(10%权重):过去的收益反应
  • 市场环境(10%权重):VIX指数、SPY/QQQ趋势
  • 行业表现(15%权重):相对行业强度
  • 动量(15%权重):RSI、52周区间
  • 情绪(10%权重):恐惧/贪婪指数、空头头寸、内幕交易

分析结果会生成清晰的BUY/HOLD/SELL建议,并附带支持点和风险提示。

2. 加密货币分析

加密货币分析提供3维度的分析,包括:

  • 市值与分类:加密货币的市值排名和分类
  • BTC相关性:30天内与比特币的相关性
  • 动量:RSI和价格区间

3. 股息分析

股息分析功能提供以下指标:

  • 股息收益率:年度股息/价格
  • 派息率:股息/EPS
  • 5年增长率:股息的复合年增长率
  • 连续增长年数:连续增加股息的年数
  • 安全评分:0-100的综合评分
  • 收入评级:优秀/良好/中等/较差

4. 投资组合管理

投资组合管理功能允许用户创建和管理多个投资组合,跟踪持仓、盈亏和集中度警告,支持股票和加密货币资产。

5. 观察列表与警报

观察列表功能允许用户添加股票和加密货币,并设置价格目标、止损和信号变化警报,当触发警报时会通知用户。

6. 热门扫描

热门扫描功能聚合多个数据源,实时查找热门股票和加密货币,数据源包括:

  • CoinGecko(热门加密货币、最大涨跌幅)
  • Google News(财经和加密货币头条)
  • Yahoo Finance(涨幅榜、跌幅榜、最活跃股票)
  • Twitter/X(社交情绪,可选)
  • Reddit(r/wallstreetbets和r/cryptocurrency,可选)

7. 谣言扫描

谣言扫描功能查找早期信号、并购谣言和内幕交易活动,数据源包括:

  • Twitter/X:"hearing that"、"sources say"等关键词
  • Google News:并购、内幕交易、分析师升级/降级新闻
  • 异常关键词检测

分析维度

股票(8维度)

维度 权重 描述
收益惊喜 30% EPS超出/低于预期的情况
基本面 20% 市盈率、利润率、增长率、债务等
分析师情绪 20% 分析师评级和目标价格
历史模式 10% 过去的收益反应模式
市场环境 10% VIX指数、SPY/QQQ趋势
行业表现 15% 相对行业强度
动量 15% RSI、52周区间、成交量
情绪 10% 恐惧/贪婪指数、空头头寸、内幕交易、看跌/看涨比率

加密货币(3维度)

  • 市值与分类:加密货币的市值排名和分类(如智能合约L1、DeFi等)
  • BTC相关性:30天内与比特币的相关性
  • 动量:RSI和价格区间

风险检测

该技能会检测以下风险:

  • 收益前风险:距离收益发布少于14天,预期高波动性
  • 收益后飙升:5天内涨幅超过15%,收益可能已被定价
  • 超买:RSI>70且接近52周高点,高风险入场
  • 风险规避模式:GLD/TLT/UUP同时上涨,资金流向避险资产
  • 地缘政治风险:检测台湾、中国、俄罗斯、中东等地缘政治关键词
  • 突发新闻风险:过去24小时内的危机关键词

带中文注释的核心代码

1. analyze_stock.py(股票分析主脚本核心代码)


  1. #!/usr/bin/env python3
  2. """
  3. 股票分析主脚本,使用Yahoo Finance数据进行8维度股票分析和加密货币分析
  4. """
  5. import argparse
  6. import asyncio
  7. import json
  8. import sys
  9. import time
  10. from dataclasses import dataclass, asdict
  11. from datetime import datetime, timedelta
  12. from typing import Literal, Optional, Tuple, List, Dict
  13. import yfinance as yf
  14. import pandas as pd
  15. from fear_and_greed import FearAndGreed
  16. @dataclass
  17. class StockData:
  18. """股票数据类,存储从Yahoo Finance获取的所有数据"""
  19. ticker: str
  20. asset_type: Literal["stock", "crypto"]
  21. info: Dict
  22. earnings_history: Optional[pd.DataFrame]
  23. analyst_info: Optional[Dict]
  24. price_history: Optional[pd.DataFrame]
  25. @dataclass
  26. class EarningsSurprise:
  27. """收益惊喜分析结果"""
  28. score: float
  29. explanation: str
  30. actual_eps: Optional[float]
  31. expected_eps: Optional[float]
  32. surprise_pct: Optional[float]
  33. def fetch_stock_data(ticker: str, verbose: bool = False) -> Optional[StockData]:
  34. """
  35. 从Yahoo Finance获取股票数据,带重试逻辑
  36. Args:
  37. ticker: 股票代码
  38. verbose: 是否打印调试信息
  39. Returns:
  40. StockData对象或None
  41. """
  42. max_retries = 3
  43. for attempt in range(max_retries):
  44. try:
  45. if verbose:
  46. print(f"正在获取 {ticker} 的数据...", file=sys.stderr)
  47. stock = yf.Ticker(ticker)
  48. info = stock.info
  49. # 检测资产类型
  50. asset_type = "crypto" if ticker.endswith("-USD") else "stock"
  51. # 获取收益历史
  52. earnings_history = stock.earnings if hasattr(stock, 'earnings') else None
  53. # 获取分析师信息
  54. analyst_info = stock.recommendations if hasattr(stock, 'recommendations') else None
  55. # 获取价格历史
  56. price_history = stock.history(period="1y")
  57. return StockData(
  58. ticker=ticker,
  59. asset_type=asset_type,
  60. info=info,
  61. earnings_history=earnings_history,
  62. analyst_info=analyst_info,
  63. price_history=price_history
  64. )
  65. except Exception as e:
  66. if verbose:
  67. print(f"获取 {ticker} 数据失败 (尝试 {attempt+1}/{max_retries}): {e}", file=sys.stderr)
  68. if attempt < max_retries - 1:
  69. wait_time = 2 ** attempt # 指数退避
  70. time.sleep(wait_time)
  71. return None
  72. def analyze_earnings_surprise(data: StockData) -> Optional[EarningsSurprise]:
  73. """
  74. 分析收益惊喜情况
  75. Args:
  76. data: StockData对象
  77. Returns:
  78. EarningsSurprise对象或None
  79. """
  80. if not data.earnings_history or data.earnings_history.empty:
  81. return None
  82. # 获取最近的收益数据
  83. latest_earnings = data.earnings_history.iloc[-1]
  84. actual_eps = latest_earnings.get("Reported EPS")
  85. expected_eps = latest_earnings.get("EPS Estimate")
  86. if actual_eps is None or expected_eps is None:
  87. return None
  88. # 计算惊喜百分比
  89. surprise_pct = ((actual_eps - expected_eps) / abs(expected_eps)) * 100
  90. # 计算分数
  91. score = surprise_pct / 100 # 标准化分数
  92. # 生成解释
  93. if surprise_pct > 0:
  94. explanation = f"超出预期 {surprise_pct:.1f}% - EPS ${actual_eps:.2f} 对比预期 ${expected_eps:.2f}"
  95. else:
  96. explanation = f"低于预期 {abs(surprise_pct):.1f}% - EPS ${actual_eps:.2f} 对比预期 ${expected_eps:.2f}"
  97. return EarningsSurprise(
  98. score=score,
  99. explanation=explanation,
  100. actual_eps=actual_eps,
  101. expected_eps=expected_eps,
  102. surprise_pct=surprise_pct
  103. )
  104. def main():
  105. """主函数,处理命令行参数并执行分析"""
  106. parser = argparse.ArgumentParser(description="股票和加密货币分析工具")
  107. parser.add_argument("tickers", nargs="+", help="股票或加密货币代码")
  108. parser.add_argument("--output", choices=["text", "json"], default="text", help="输出格式")
  109. parser.add_argument("--verbose", "-v", action="store_true", help="显示详细信息")
  110. parser.add_argument("--fast", action="store_true", help="快速模式,跳过慢速分析")
  111. parser.add_argument("--no-insider", action="store_true", help="跳过内幕交易分析")
  112. parser.add_argument("--portfolio", help="分析投资组合")
  113. parser.add_argument("--period", choices=["daily", "weekly", "monthly"], default="daily", help="分析周期")
  114. args = parser.parse_args()
  115. # 处理投资组合模式
  116. if args.portfolio:
  117. # 加载投资组合
  118. try:
  119. from portfolio import PortfolioStore
  120. store = PortfolioStore()
  121. portfolio = store.get_portfolio(args.portfolio)
  122. if not portfolio:
  123. print(f"错误:投资组合 '{args.portfolio}' 不存在", file=sys.stderr)
  124. sys.exit(1)
  125. if not portfolio.assets:
  126. print(f"投资组合 '{args.portfolio}' 没有资产", file=sys.stderr)
  127. sys.exit(1)
  128. args.tickers = [asset.ticker for asset in portfolio.assets]
  129. if args.verbose:
  130. print(f"正在分析投资组合: {args.portfolio} ({len(args.tickers)} 个资产)", file=sys.stderr)
  131. except ImportError:
  132. print("错误:无法导入portfolio模块", file=sys.stderr)
  133. sys.exit(1)
  134. # 分析每个代码
  135. results = []
  136. for ticker in args.tickers:
  137. data = fetch_stock_data(ticker.upper(), verbose=args.verbose)
  138. if not data:
  139. print(f"错误:无法获取 {ticker} 的数据", file=sys.stderr)
  140. continue
  141. # 分析各个维度
  142. earnings = analyze_earnings_surprise(data)
  143. # 其他分析函数...
  144. # 合成信号
  145. # signal = synthesize_signal(...)
  146. # results.append(signal)
  147. # 输出结果
  148. if args.output == "json":
  149. print(json.dumps([asdict(r) for r in results], indent=2, default=str))
  150. else:
  151. for signal in results:
  152. print(f"{'='*77}")
  153. print(f"股票分析: {signal.ticker} ({signal.company_name})")
  154. print(f"生成时间: {signal.timestamp}")
  155. print(f"{'='*77}")
  156. print(f"建议: {signal.recommendation} (置信度: {signal.confidence:.1%})")
  157. print("\n支持点:")
  158. for point in signal.supporting_points:
  159. print(f"• {point}")
  160. if signal.caveats:
  161. print("\n风险提示:")
  162. for caveat in signal.caveats:
  163. print(f"• {caveat}")
  164. print(f"\n{'='*77}")
  165. print("免责声明:不构成财务建议。")
  166. print(f"{'='*77}\n")
  167. if __name__ == "__main__":
  168. main()

2. portfolio.py(投资组合管理脚本核心代码)


  1. #!/usr/bin/env python3
  2. """
  3. 投资组合管理脚本
  4. """
  5. import argparse
  6. import json
  7. import sys
  8. from dataclasses import dataclass, asdict
  9. from datetime import datetime
  10. from pathlib import Path
  11. import yfinance as yf
  12. @dataclass
  13. class Asset:
  14. """资产类,存储投资组合中的资产信息"""
  15. ticker: str
  16. type: str # "stock" or "crypto"
  17. quantity: float
  18. cost_basis: float
  19. added_at: str
  20. @dataclass
  21. class Portfolio:
  22. """投资组合类,存储投资组合信息"""
  23. name: str
  24. created_at: str
  25. updated_at: str
  26. assets: list[Asset]
  27. class PortfolioStore:
  28. """投资组合存储管理类,处理投资组合的持久化"""
  29. def __init__(self, path: Optional[Path] = None):
  30. """初始化存储路径"""
  31. self.path = path or Path.home() / ".clawdbot" / "skills" / "stock-analysis" / "portfolios.json"
  32. self._data: Optional[Dict] = None
  33. def _load(self) -> Dict:
  34. """从磁盘加载投资组合数据"""
  35. if self._data is not None:
  36. return self._data
  37. try:
  38. if self.path.exists():
  39. with open(self.path, "r", encoding="utf-8") as f:
  40. self._data = json.load(f)
  41. return self._data
  42. except (json.JSONDecodeError, IOError):
  43. pass
  44. # 如果加载失败,初始化空数据
  45. self._data = {"version": 1, "portfolios": {}}
  46. return self._data
  47. def _save(self) -> None:
  48. """将投资组合数据保存到磁盘(原子写入)"""
  49. if self._data is None:
  50. return
  51. # 确保目录存在
  52. self.path.parent.mkdir(parents=True, exist_ok=True)
  53. # 原子写入:先写入临时文件,然后重命名
  54. tmp_path = self.path.with_suffix(".tmp")
  55. try:
  56. with open(tmp_path, "w", encoding="utf-8") as f:
  57. json.dump(self._data, f, indent=2)
  58. tmp_path.replace(self.path)
  59. except Exception:
  60. if tmp_path.exists():
  61. tmp_path.unlink()
  62. raise
  63. def create_portfolio(self, name: str) -> Portfolio:
  64. """创建新投资组合"""
  65. data = self._load()
  66. key = name.lower().replace(" ", "-")
  67. if key in data["portfolios"]:
  68. raise ValueError(f"投资组合 '{name}' 已存在")
  69. now = datetime.now().isoformat()
  70. portfolio = {
  71. "name": name,
  72. "created_at": now,
  73. "updated_at": now,
  74. "assets": [],
  75. }
  76. data["portfolios"][key] = portfolio
  77. self._save()
  78. return Portfolio(name=name, created_at=now, updated_at=now, assets=[])
  79. def add_asset(
  80. self,
  81. portfolio_name: str,
  82. ticker: str,
  83. quantity: float,
  84. cost_basis: float,
  85. ) -> Asset:
  86. """向投资组合添加资产"""
  87. data = self._load()
  88. key = portfolio_name.lower().replace(" ", "-")
  89. # 查找投资组合
  90. if key not in data["portfolios"]:
  91. raise ValueError(f"投资组合 '{portfolio_name}' 不存在")
  92. portfolio = data["portfolios"][key]
  93. ticker = ticker.upper()
  94. # 检查资产是否已存在
  95. for asset in portfolio["assets"]:
  96. if asset["ticker"] == ticker:
  97. raise ValueError(f"资产 '{ticker}' 已在投资组合中。使用 'update' 来修改。")
  98. # 验证代码
  99. asset_type = "crypto" if ticker.endswith("-USD") else "stock"
  100. try:
  101. stock = yf.Ticker(ticker)
  102. info = stock.info
  103. if "regularMarketPrice" not in info:
  104. raise ValueError(f"无效代码: {ticker}")
  105. except Exception as e:
  106. raise ValueError(f"无法验证代码 '{ticker}': {e}")
  107. now = datetime.now().isoformat()
  108. asset = {
  109. "ticker": ticker,
  110. "type": asset_type,
  111. "quantity": quantity,
  112. "cost_basis": cost_basis,
  113. "added_at": now,
  114. }
  115. portfolio["assets"].append(asset)
  116. portfolio["updated_at"] = now
  117. self._save()
  118. return Asset(**asset)
  119. def main():
  120. """主函数,处理命令行参数"""
  121. parser = argparse.ArgumentParser(description="投资组合管理工具")
  122. subparsers = parser.add_subparsers(dest="command", help="命令")
  123. # create
  124. create_parser = subparsers.add_parser("create", help="创建新投资组合")
  125. create_parser.add_argument("name", help="投资组合名称")
  126. # add
  127. add_parser = subparsers.add_parser("add", help="向投资组合添加资产")
  128. add_parser.add_argument("ticker", help="股票/加密货币代码(例如:AAPL, BTC-USD)")
  129. add_parser.add_argument("--quantity", "-q", type=float, required=True, help="数量")
  130. add_parser.add_argument("--cost", "-c", type=float, required=True, help="单位成本")
  131. add_parser.add_argument("--portfolio", "-p", help="投资组合名称(默认:第一个投资组合)")
  132. # 其他命令...
  133. args = parser.parse_args()
  134. if not args.command:
  135. parser.print_help()
  136. sys.exit(1)
  137. store = PortfolioStore()
  138. try:
  139. if args.command == "create":
  140. portfolio = store.create_portfolio(args.name)
  141. print(f"创建投资组合: {portfolio.name}")
  142. elif args.command == "add":
  143. portfolio_name = args.portfolio or store.get_default_portfolio_name()
  144. if not portfolio_name:
  145. print("没有找到投资组合。先使用 'create' 命令创建一个。")
  146. sys.exit(1)
  147. asset = store.add_asset(portfolio_name, args.ticker, args.quantity, args.cost)
  148. print(f"已向 {portfolio_name} 添加 {asset.ticker} ({asset.type}): "
  149. f"{asset.quantity} 单位 @ ${asset.cost_basis:.2f}")
  150. # 其他命令处理...
  151. except ValueError as e:
  152. print(f"错误: {e}")
  153. sys.exit(1)
  154. except Exception as e:
  155. print(f"意外错误: {e}")
  156. sys.exit(1)
  157. if __name__ == "__main__":
  158. main()

元数据信息

该技能的元数据信息如下:


  1. {
  2. "ownerId": "kn77fv9851hjcqe52zqx0bhhbx7z680h",
  3. "slug": "stock-analysis",
  4. "version": "6.2.0",
  5. "publishedAt": 1770041353575
  6. }
Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐