Install
openclaw skills install a-stock-individual-analysisA股个股深度分析 — 五模块框架(基本面/趋势量价/紫苏叶逻辑/近期消息/综合总结)。基于a-stock-data工具包的真实数据,覆盖订单可见度、毛利率方向、现金流匹配度、产能扩张动因、PE/PEG/EPS、均线量价、主力资金、技术壁垒、行业卡位、供需研判、近期新闻研报、解禁预警等维度。适用于个股深度研判、估值分析、买卖点判断。涉及"分析个股""深度研判""估值分析""紫苏叶""serenity""个股报告"时激活。
openclaw skills install a-stock-individual-analysis五模块分析框架,基于真实数据,参考白毛股神 Serenity 的紫苏叶方法论。
第一优先:a-stock-data 工具包(mootdx / 腾讯 / 新浪 / 东财 / 同花顺)
↓ 失败
第二优先:联网搜索(web_search)+ 公开 API 自行调用
↓ 失败
第三优先:标记「⚠️ 数据不可获取」
成功获取的数据源及调用方式必须沉淀到本 SKILL 的「已知可用端点」章节,未来直接复用。
| 数据 | 端点 | 方式 |
|---|---|---|
| 实时行情(PE/PB/市值等) | 腾讯财经 qt.gtimg.cn | urllib GBK |
| K线 + 均线 + RSI | mootdx TCP 7709 | Python (需重命名 datetime 列) |
| 一致预期 EPS | 同花顺 basic.10jqka.com.cn | requests + pd.read_html |
| 研报列表+评级+EPS预测 | 东财 reportapi.eastmoney.com | em_get 限流 |
| 板块归属(行业/概念) | 东财 push2 slist spt=3 | em_get 限流 |
| 限售解禁 | 东财 datacenter RPT_LIFT_STAGE | em_get 限流 |
| 龙虎榜 | 东财 datacenter RPT_DAILYBILLBOARD_DETAILSNEW | em_get 限流 |
| 资金流向(分钟级) | 东财 push2 fflow/kline | em_get 限流(仅交易时间) |
| 股东户数 | 东财 datacenter RPT_F10_FINANCE_HOLDERINFO | em_get 限流 |
| 新闻 | web_search 联网搜索 | 当东财 API 不可用时 |
| 财报明细(三表) | web_search 联网补充 | 当新浪 API 不可用时 |
| 行业对比/竞争格局 | web_search 联网搜索 | 补充分析 |
~/.agents/skills/a-stock-data/SKILL.md 确认端点"""A股个股深度分析 — 数据采集脚本 V1.1"""
import sys, json, time, random, requests, urllib.request, pandas as pd
from datetime import datetime, timedelta
from io import StringIO
CODE = sys.argv[1] if len(sys.argv) > 1 else "600519"
PREFIX_SH = CODE.startswith(("6", "9"))
PREFIX_BJ = CODE.startswith("8")
SECID = f"1.{CODE}" if PREFIX_SH else (f"0.{CODE}" if not PREFIX_BJ else f"2.{CODE}")
TODAY = datetime.now().strftime("%Y-%m-%d")
UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
# 东财防封
EM_SESSION = requests.Session()
EM_SESSION.headers.update({"User-Agent": UA})
EM_MIN_INTERVAL = 1.2
_em_last_call = [0.0]
def em_get(url, params=None, headers=None, timeout=15, **kwargs):
wait = EM_MIN_INTERVAL - (time.time() - _em_last_call[0])
if wait > 0: time.sleep(wait + random.uniform(0.1, 0.5))
try: return EM_SESSION.get(url, params=params, headers=headers, timeout=timeout, **kwargs)
finally: _em_last_call[0] = time.time()
def eastmoney_datacenter(report_name, columns="ALL", filter_str="", page_size=50, sort_columns="", sort_types="-1"):
params = {"reportName": report_name, "columns": columns, "filter": filter_str, "pageNumber": "1", "pageSize": str(page_size), "sortColumns": sort_columns, "sortTypes": sort_types, "source": "WEB", "client": "WEB"}
r = em_get("https://datacenter-web.eastmoney.com/api/data/v1/get", params=params)
d = r.json()
return d["result"]["data"] if d.get("result") and d["result"].get("data") else []
result = {"code": CODE, "分析时间": TODAY}
# ======================== 阶段1: 实时行情 ========================
print(">>> [1/7] 实时行情...", file=sys.stderr)
pfx = "sh" if PREFIX_SH else ("bj" if PREFIX_BJ else "sz")
try:
req = urllib.request.Request(f"https://qt.gtimg.cn/q={pfx}{CODE}")
req.add_header("User-Agent", "Mozilla/5.0")
resp = urllib.request.urlopen(req, timeout=10)
vals = resp.read().decode("gbk").split('"')[1].split("~")
if len(vals) >= 53:
result["实时行情"] = {
"名称": vals[1], "现价": float(vals[3] or 0), "昨收": float(vals[4] or 0),
"今开": float(vals[5] or 0), "最高": float(vals[33] or 0), "最低": float(vals[34] or 0),
"涨跌幅%": float(vals[32] or 0), "成交额_万": float(vals[37] or 0),
"换手率%": float(vals[38] or 0), "PE_TTM": float(vals[39] or 0),
"总市值_亿": float(vals[44] or 0), "流通市值_亿": float(vals[45] or 0),
"PB": float(vals[46] or 0), "涨停价": float(vals[47] or 0),
"跌停价": float(vals[48] or 0), "量比": float(vals[49] or 0), "PE_静": float(vals[52] or 0),
}
except Exception as e: result["实时行情"] = {"error": str(e)}
# ======================== 阶段2: K线技术(mootdx) ========================
print(">>> [2/7] K线技术...", file=sys.stderr)
try:
from mootdx.quotes import Quotes
client = Quotes.factory(market='std')
klines = client.bars(symbol=CODE, category=4, offset=250)
if klines is not None and len(klines) > 0:
df = pd.DataFrame(klines)
if 'datetime' in df.columns: df = df.rename(columns={'datetime': 'dt'})
df = df.sort_values("dt")
for ma in [5, 10, 20, 60, 120, 250]: df[f"MA{ma}"] = df["close"].rolling(ma).mean()
recent = df.tail(60)
last = df.iloc[-1]
delta = df["close"].diff()
gain = delta.where(delta > 0, 0).rolling(14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(14).mean()
rsi = 100 - (100 / (1 + gain / loss))
vol_ma20 = recent["vol"].rolling(20).mean().iloc[-1] if len(recent) >= 20 else recent["vol"].mean()
vol_ratio = last["vol"] / vol_ma20 if vol_ma20 > 0 else 0
mas = []
price = last["close"]
for m in [5, 10, 20, 60, 120, 250]:
v = last[f"MA{m}"]
if pd.notna(v): mas.append({"均线": f"MA{m}", "价格": round(float(v),2), "偏离%": round(float((price-v)/v*100),2)})
result["K线技术"] = {
"最新价": round(float(price), 2),
"均线": {f"MA{m}": round(float(last[f"MA{m}"]),2) if pd.notna(last[f"MA{m}"]) else None for m in [5,10,20,60,120,250]},
"RSI14": round(float(rsi.iloc[-1]), 2) if pd.notna(rsi.iloc[-1]) else None,
"量比": round(float(vol_ratio), 2),
"60日最高": round(float(recent["high"].max()), 2),
"60日最低": round(float(recent["low"].min()), 2),
"从高点回调%": round(float((price-recent["high"].max())/recent["high"].max()*100),2),
"60日涨跌幅%": round(float((price-recent.iloc[0]["close"])/recent.iloc[0]["close"]*100),2),
}
except Exception as e: result["K线技术"] = {"error": str(e)}
# ======================== 阶段3: 一致预期EPS ========================
print(">>> [3/7] 一致预期...", file=sys.stderr)
try:
r = requests.get(f"https://basic.10jqka.com.cn/new/{CODE}/worth.html", headers={"User-Agent": UA, "Referer": "https://basic.10jqka.com.cn/"}, timeout=15)
r.encoding = "gbk"
dfs = pd.read_html(StringIO(r.text))
for df in dfs:
cols = [str(c) for c in df.columns]
if any("每股收益" in c or "均值" in c for c in cols):
result["一致预期EPS"] = df.to_dict(orient="records")
break
except Exception as e: result["一致预期EPS"] = {"error": str(e)}
# ======================== 阶段4: 东财系(串行限流) ========================
print(">>> [4/7] 研报...", file=sys.stderr)
try:
reports = []
for page in range(1, 4):
params = {"industryCode": "*", "pageSize": "50", "industry": "*", "rating": "*", "ratingChange": "*", "beginTime": (datetime.now()-timedelta(days=180)).strftime("%Y-%m-%d"), "endTime": TODAY, "pageNo": str(page), "qType": "0", "orgCode": "", "code": CODE, "rcode": "", "p": str(page), "pageNum": str(page), "pageNumber": str(page)}
r = em_get("https://reportapi.eastmoney.com/report/list", params=params, headers={"Referer": "https://data.eastmoney.com/"}, timeout=30)
rows = (r.json().get("data") or [])
if not rows: break
for row in rows:
reports.append({"日期": (row.get("publishDate") or "")[:10], "机构": row.get("orgSName", ""), "标题": row.get("title", ""), "评级": row.get("emRatingName", ""), "今年EPS": row.get("predictThisYearEps", ""), "明年EPS": row.get("predictNextYearEps", ""), "后年EPS": row.get("predictNextTwoYearEps", "")})
if page >= (r.json().get("TotalPage", 1) or 1): break
result["研报"] = reports[:15]
except Exception as e: result["研报"] = {"error": str(e)}
print(">>> [5/7] 解禁+龙虎榜...", file=sys.stderr)
try:
end_d = (datetime.now()+timedelta(days=90)).strftime("%Y-%m-%d")
data = eastmoney_datacenter("RPT_LIFT_STAGE", filter_str=f"(SECURITY_CODE=\"{CODE}\")(FREE_DATE>='{TODAY}')(FREE_DATE<='{end_d}')", page_size=10, sort_columns="FREE_DATE", sort_types="1")
result["解禁"] = [{"日期": str(r.get("FREE_DATE",""))[:10], "类型": r.get("LIMITED_STOCK_TYPE",""), "占比%": r.get("FREE_RATIO",0)} for r in data]
except Exception as e: result["解禁"] = {"error": str(e)}
try:
start_lh = (datetime.now()-timedelta(days=30)).strftime("%Y-%m-%d")
data = eastmoney_datacenter("RPT_DAILYBILLBOARD_DETAILSNEW", filter_str=f"(TRADE_DATE>='{start_lh}')(TRADE_DATE<='{TODAY}')(SECURITY_CODE=\"{CODE}\")", page_size=20, sort_columns="TRADE_DATE", sort_types="-1")
result["龙虎榜"] = [{"日期": str(r.get("TRADE_DATE",""))[:10], "原因": r.get("EXPLANATION",""), "净买_万": round((r.get("BILLBOARD_NET_AMT") or 0)/10000,1)} for r in data]
except Exception as e: result["龙虎榜"] = {"error": str(e)}
print(">>> [6/7] 板块归属...", file=sys.stderr)
try:
mc = 1 if PREFIX_SH else 0
params = {"fltt": "2", "invt": "2", "secid": f"{mc}.{CODE}", "spt": "3", "pi": "0", "pz": "200", "po": "1", "fields": "f12,f14,f3,f128"}
r = em_get("https://push2.eastmoney.com/api/qt/slist/get", params=params, headers={"Referer": "https://quote.eastmoney.com/"}, timeout=15)
diff = (r.json().get("data") or {}).get("diff") or {}
items = diff.values() if isinstance(diff, dict) else diff
result["板块归属"] = [{"板块": it.get("f14",""), "BK码": it.get("f12",""), "涨跌幅%": it.get("f3",""), "龙头": it.get("f128","")} for it in items]
except Exception as e: result["板块归属"] = {"error": str(e)}
# ======================== 阶段7: 资金流向(仅交易时间) ========================
print(">>> [7/7] 资金流向...", file=sys.stderr)
try:
params = {"secid": SECID, "klt": 1, "fields1": "f1,f2,f3,f7", "fields2": "f51,f52,f53,f54,f55,f56,f57"}
r = em_get("https://push2.eastmoney.com/api/qt/stock/fflow/kline/get", params=params, headers={"Referer": "https://quote.eastmoney.com/"}, timeout=10)
rows = [l.split(",") for l in r.json().get("data",{}).get("klines",[])]
total = sum(float(p[1]) for p in rows if len(p)>=6)
result["资金流向"] = {"主力累计_万元": round(total/10000,1), "方向": "流入" if total>0 else "流出"}
except Exception as e: result["资金流向"] = {"error": str(e), "note": "非交易时间或接口不可用"}
print(json.dumps(result, ensure_ascii=False, indent=2, default=str))
数据采集完成后,按以下模板撰写分析报告。
分析时间:{时间} | 当前价:{现价}元 | 总市值:{总市值}亿 | PE(TTM):{PE} | PB:{PB}
从预收账款/合同负债趋势、营收增速、公告大单等维度分析:
分析毛利率趋势:
综合订单可见度、毛利率方向、现金流质量、产能动因四个维度,基本面整体打分(1-5): {得分}/5
| 指标 | 数值 |
|---|---|
| PE(TTM) | {x} |
| 26/27/28 年一致预期 EPS | {x} / {x} / {x} |
| 26/27 年前向 PE | {x}x / {x}x |
| PEG(27年EPS增速) | {x} |
估值判断: (基于前向 PE 和 PEG 的合理区间判断)
现价 vs 各均线关系 + RSI 超买超卖 + 量价配合 + 支撑/压力位
(仅当数据可获取时纳入。不可获取 → 本小节不出现)
参考白毛股神 Serenity 的分析框架,从商业模式本质出发,研判该标的是否具备"紫苏叶"属性——即拥有难以复制的竞争壁垒 + 占据产业链不可替代的位置 + 受益于持续紧张的供需格局。
核心研判维度(不限于以下,以 Serenity 框架为准):
综合研判该标的是否属于紫苏叶——即「好生意 + 好位置 + 好时机」三重共振
数据获取优先使用 a-stock-data;失败则通过 web_search 联网搜索补充。仍无法获取 → 标注。
基于技术面(均线/RSI/量价)和近期催化剂,给出方向判断和关键价位。
基于基本面 + 紫苏叶逻辑 + 行业景气度,给出估值目标价区间。
目标价推算:
| 情景 | PE | 目标价 | 逻辑 |
|---|---|---|---|
| 保守 | {x}x | {x}元 | |
| 基准 | {x}x | {x}元 | |
| 乐观 | {x}x | {x}元 |
| 维度 | 判断 |
|---|---|
| 当前估值 | 偏贵 / 合理 / 低估 |
| 短期支撑/压力 | {x}元 / {x}元 |
| 长期目标区间 | {x} - {x}元 |
🦞 用 2-3 句话概括该标的核心逻辑:它是什么 / 为什么值得关注 / 当前处于什么位置 / 关键催化剂是什么。
⚠️ 免责声明: 本报告基于公开数据和量化分析框架,不构成任何投资建议。股市有风险,投资需谨慎。所有估值目标价均为模型测算,实际走势受多重因素影响。
~/.agents/skills/a-stock-data/SKILL.md 确认端点python3 /tmp/stock_analysis.py <代码>当 a-stock-data 接口不可用时,按以下优先级尝试:
"{股票名称} 最新消息"、"{股票名称} 研报"、"{股票名称} 财务数据"