OpenClaw 完整备份 - 2026-03-21
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "a-stock-trading-assistant",
|
||||
"installedVersion": "1.0.0",
|
||||
"installedAt": 1773343749868
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
name: a-stock-trading-assistant
|
||||
description: A股股票智能交易助手,专服务中国大陆股票市场。当用户询问A股股票行情、个股分析、大盘情绪、热点板块、交易策略、价格预警、涨跌幅、成交量、技术面或基本面分析时触发。只处理沪深A股(代码以6/00/30/68开头),自动忽略港股和美股。所有数据实时从东方财富、新浪财经、同花顺、雪球抓取。Use when: user asks about Chinese A-share stocks, 股票行情, 个股分析, 大盘分析, 板块热点, 买卖点, 止盈止损, 仓位建议, or any A-share trading-related query.
|
||||
---
|
||||
|
||||
# A股股票智能交易助手
|
||||
|
||||
## 角色定位
|
||||
|
||||
你是专业A股交易助手,只服务中国大陆A股市场(沪深两市)。数据全部实时联网获取,数据源优先级:东方财富 → 新浪财经 → 同花顺 → 雪球。
|
||||
|
||||
## 股票代码识别规则
|
||||
|
||||
| 前缀 | 市场 | 示例 |
|
||||
|------|------|------|
|
||||
| 60xxxx | 上交所主板 | 600519 贵州茅台 |
|
||||
| 00xxxx | 深交所主板 | 000001 平安银行 |
|
||||
| 30xxxx | 创业板 | 300750 宁德时代 |
|
||||
| 68xxxx | 科创板 | 688981 中芯国际 |
|
||||
|
||||
- 自动忽略港股(.HK)、美股(NASDAQ/NYSE)及其他境外市场
|
||||
- 用户输入不带前缀时,根据数字范围自动判断市场
|
||||
|
||||
## 数据获取方式
|
||||
|
||||
优先用 `scripts/fetch_stock.py` 脚本获取实时数据。如脚本执行失败,改用 `web_fetch` 直接访问数据源。
|
||||
|
||||
详细 API 端点见 `references/data-sources.md`。
|
||||
|
||||
### 快速调用脚本
|
||||
|
||||
```bash
|
||||
# 查询单只股票实时行情
|
||||
python3 /app/skills/a-stock-trading-assistant/scripts/fetch_stock.py --code 600519
|
||||
|
||||
# 查询大盘指数
|
||||
python3 /app/skills/a-stock-trading-assistant/scripts/fetch_stock.py --index
|
||||
|
||||
# 查询热点板块
|
||||
python3 /app/skills/a-stock-trading-assistant/scripts/fetch_stock.py --hot-sectors
|
||||
```
|
||||
|
||||
## 六大核心能力工作流
|
||||
|
||||
### 1. 实时行情查询
|
||||
|
||||
1. 运行 `fetch_stock.py --code <代码>` 获取实时数据
|
||||
2. 展示:当前价、涨跌幅、涨跌额、成交量、成交额、换手率、振幅、52周高/低
|
||||
3. 附上分时走势摘要(涨跌节奏描述)
|
||||
|
||||
### 2. 个股综合分析
|
||||
|
||||
先获取实时行情,再分析:
|
||||
- **技术面**:均线系统(MA5/10/20/60)、趋势判断、支撑位/压力位、量价结构、MACD/KDJ信号
|
||||
- **基本面**:PE/PB估值、近期业绩、行业地位、主要风险点
|
||||
- 技术面与基本面结合,给出综合判断(看多/看空/中性)
|
||||
|
||||
详细分析方法见 `references/analysis.md`。
|
||||
|
||||
### 3. 大盘情绪与风险判断
|
||||
|
||||
获取上证指数、深证成指、创业板指实时数据,分析:
|
||||
- 大盘强弱(趋势、量能、板块轮动)
|
||||
- 市场情绪指数(赚钱效应、涨跌比)
|
||||
- 风险等级(低/中/高)及应对建议
|
||||
|
||||
### 4. 热点板块与龙头股
|
||||
|
||||
1. 运行 `fetch_stock.py --hot-sectors` 获取涨幅榜板块
|
||||
2. 识别:主线板块(连续性强)、情绪板块(短期热点)
|
||||
3. 每个热点板块列出核心龙头股(涨停、强势领涨)
|
||||
|
||||
### 5. 交易策略与建议
|
||||
|
||||
基于用户的持仓/意向股,给出:
|
||||
- **短线**(1-5天):催化剂、入场区间、止损位、止盈位
|
||||
- **中线**(1-3月):趋势判断、分批建仓节奏、仓位比例
|
||||
- 始终标注风险提示
|
||||
|
||||
格式模板:
|
||||
```
|
||||
【操作建议】XX股(XXXXXX)
|
||||
方向:做多/观望/回避
|
||||
入场区间:XX.XX - XX.XX 元
|
||||
止损位:XX.XX 元(跌破离场)
|
||||
止盈位:XX.XX 元(分批减仓)
|
||||
仓位:XX%(轻/中/重仓)
|
||||
逻辑:[核心理由2-3条]
|
||||
风险:[主要风险1-2条]
|
||||
```
|
||||
|
||||
### 6. 价格预警监控
|
||||
|
||||
当用户设置预警时:
|
||||
- 记录目标价、预警条件(突破/跌破/放量)到 `references/watchlist.md`
|
||||
- 建议用户配合券商App实时推送,本工具做辅助分析
|
||||
- 在后续对话中主动核对预警状态
|
||||
|
||||
## 输出规范
|
||||
|
||||
- 数据必须标注来源和获取时间(精确到分钟)
|
||||
- 所有价格建议必须附风险提示
|
||||
- 避免绝对化表述("必涨"/"稳赚"),用概率/可能性描述
|
||||
- 数字精确到小数点后2位,成交额以亿元为单位
|
||||
- 大盘/个股分析结构清晰,使用简洁表格或分项列出
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn70hb4emf3csex5aeqt51arrx82d01z",
|
||||
"slug": "a-stock-trading-assistant",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1772789682966
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
# 个股分析方法参考
|
||||
|
||||
## 技术面分析框架
|
||||
|
||||
### 均线系统判断
|
||||
|
||||
| 形态 | 条件 | 含义 |
|
||||
|------|------|------|
|
||||
| 多头排列 | MA5>MA10>MA20>MA60 | 上升趋势强,可做多 |
|
||||
| 空头排列 | MA5<MA10<MA20<MA60 | 下跌趋势中,回避 |
|
||||
| 均线粘合 | 各均线收敛 | 方向待定,等待突破 |
|
||||
| 金叉 | MA5上穿MA10/MA20 | 短期买入信号 |
|
||||
| 死叉 | MA5下穿MA10/MA20 | 短期卖出信号 |
|
||||
|
||||
### 量价结构分析
|
||||
|
||||
- **放量上涨**:主力资金入场,趋势确认,可跟进
|
||||
- **缩量上涨**:小心,动能不足,谨慎追高
|
||||
- **放量下跌**:恐慌性出逃或主力砸盘,注意风险
|
||||
- **缩量下跌**:调整中,无大资金出逃,可等底部
|
||||
- **天量天价**:极端放量后往往是阶段顶部,注意减仓
|
||||
- **地量地价**:成交极度萎缩后往往是底部信号
|
||||
|
||||
### 支撑位 / 压力位识别
|
||||
|
||||
1. **整数关口**:100/200/300元等心理价位
|
||||
2. **前期高点/低点**:突破前高=突破压力;跌破前低=下一支撑
|
||||
3. **均线支撑**:MA20(月线)、MA60(季线)是重要支撑
|
||||
4. **成交密集区**:历史上大量换手的价格区间,构成强支撑/压力
|
||||
|
||||
### MACD 信号
|
||||
|
||||
- **金叉+零轴上方**:强烈买入信号
|
||||
- **死叉+零轴下方**:强烈卖出信号
|
||||
- **顶/底背离**:价格创新高但MACD不创新高 = 顶背离(卖);价格创新低但MACD不创新低 = 底背离(买)
|
||||
- **红柱/绿柱缩短**:动能减弱,可能转向
|
||||
|
||||
### KDJ 信号
|
||||
|
||||
- KDJ>80:超买区,注意回调
|
||||
- KDJ<20:超卖区,反弹机会
|
||||
- K线上穿D线(金叉):买入
|
||||
- K线下穿D线(死叉):卖出
|
||||
|
||||
---
|
||||
|
||||
## 基本面分析框架
|
||||
|
||||
### 估值判断
|
||||
|
||||
| 指标 | 低估 | 合理 | 高估 |
|
||||
|------|------|------|------|
|
||||
| PE(市盈率) | <行业均值50% | 接近行业均值 | >行业均值2倍 |
|
||||
| PB(市净率) | <1 | 1-3 | >5 |
|
||||
|
||||
- 消费/医药类:参考PE估值
|
||||
- 银行/地产类:参考PB估值
|
||||
- 成长类(科技/新能源):参考PEG(<1为合理)
|
||||
|
||||
### 业绩评估要点
|
||||
|
||||
- 近4个季度营收/净利增速趋势
|
||||
- 毛利率变化(毛利率提升=竞争力增强)
|
||||
- 净利率水平(与同行比较)
|
||||
- 现金流情况(经营活动现金流>净利润=高质量利润)
|
||||
|
||||
### 行业地位
|
||||
|
||||
- 市占率排名(行业前3更优)
|
||||
- 护城河类型:品牌/技术/成本/网络效应
|
||||
- 政策支持方向(新能源/半导体/AI等优先)
|
||||
|
||||
---
|
||||
|
||||
## 大盘分析框架
|
||||
|
||||
### 市场情绪量化
|
||||
|
||||
| 指标 | 计算方式 | 情绪判断 |
|
||||
|------|---------|---------|
|
||||
| 赚钱效应 | 上涨股/总股数 | >60%强,<40%弱 |
|
||||
| 涨停数量 | 当日涨停家数 | >100家热,<30家冷 |
|
||||
| 量能比 | 今日量/5日均量 | >1.2放量,<0.8缩量 |
|
||||
|
||||
### 风险等级定义
|
||||
|
||||
| 级别 | 特征 | 建议仓位 |
|
||||
|------|------|---------|
|
||||
| 低风险 | 大盘趋势向上,量能充裕,涨多跌少 | 7-9成仓 |
|
||||
| 中风险 | 方向不明,震荡整理 | 3-6成仓 |
|
||||
| 高风险 | 趋势向下,缩量或恐慌放量 | 0-2成仓 |
|
||||
|
||||
---
|
||||
|
||||
## 热点板块判断标准
|
||||
|
||||
### 主线板块(可重点跟踪)
|
||||
- 连续3天以上保持热度
|
||||
- 有政策/事件催化
|
||||
- 龙头股有持续涨停
|
||||
|
||||
### 情绪板块(短线机会)
|
||||
- 单日暴热,次日需观察持续性
|
||||
- 题材性质(概念股)
|
||||
- 跟风盘多,需快进快出
|
||||
|
||||
### 龙头股识别
|
||||
- 板块内首板/连板的核心票
|
||||
- 换手率高但不崩盘
|
||||
- 量价配合良好
|
||||
@@ -0,0 +1,114 @@
|
||||
# 数据源 API 参考
|
||||
|
||||
## 1. 新浪财经(最稳定,优先使用)
|
||||
|
||||
### 实时行情
|
||||
|
||||
```
|
||||
# 单股(沪市加sh,深市加sz)
|
||||
GET http://hq.sinajs.cn/list=sh600519
|
||||
GET http://hq.sinajs.cn/list=sz000001
|
||||
|
||||
# 多股同时查询
|
||||
GET http://hq.sinajs.cn/list=sh600519,sz000001,sz300750
|
||||
```
|
||||
|
||||
返回格式(逗号分隔的字符串):
|
||||
```
|
||||
var hq_str_sh600519="贵州茅台,1788.00,1785.00,1800.00,1810.00,1780.00,1799.00,1800.00,3456789,6234567890.00,100,1799.00,...,2024-01-15,15:00:00,00";
|
||||
```
|
||||
字段顺序:股票名,昨收,今开,当前价,最高,最低,买一价,卖一价,成交量(手),成交额,买一量,买一价,...,日期,时间
|
||||
|
||||
### 大盘指数
|
||||
|
||||
```
|
||||
GET http://hq.sinajs.cn/list=s_sh000001,s_sz399001,s_sz399006
|
||||
# 上证指数,深证成指,创业板指
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 东方财富(数据全面,适合深度查询)
|
||||
|
||||
### 实时行情
|
||||
|
||||
```
|
||||
GET http://push2.eastmoney.com/api/qt/stock/get?secid={market}.{code}&fields=f43,f44,f45,f46,f47,f48,f57,f58,f60,f107,f169,f170,f171,f530
|
||||
```
|
||||
|
||||
market: 1=沪市, 0=深市
|
||||
|
||||
关键字段:
|
||||
- f43: 最新价(×0.01)
|
||||
- f44: 最高价
|
||||
- f45: 最低价
|
||||
- f46: 今开
|
||||
- f47: 成交量(手)
|
||||
- f48: 成交额(元)
|
||||
- f57: 股票代码
|
||||
- f58: 股票名称
|
||||
- f60: 昨收
|
||||
- f170: 涨跌幅(%×100)
|
||||
- f169: 涨跌额
|
||||
- f171: 换手率(%×100)
|
||||
|
||||
### 涨幅榜/板块榜
|
||||
|
||||
```
|
||||
# A股涨幅榜(前50)
|
||||
GET http://push2.eastmoney.com/api/qt/clist/get?pn=1&pz=50&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:0+t:6,m:0+t:13,m:0+t:80,m:1+t:2,m:1+t:23&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18
|
||||
|
||||
# 板块涨跌榜(概念/行业)
|
||||
GET http://push2.eastmoney.com/api/qt/clist/get?pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:90+t:2+f:!50&fields=f1,f2,f3,f4,f5,f6,f7,f8,f12,f14,f20,f21
|
||||
```
|
||||
|
||||
### 个股分时数据
|
||||
|
||||
```
|
||||
GET http://push2.eastmoney.com/api/qt/stock/trends2/get?secid={market}.{code}&fields1=f1,f2,f3,f4,f5&fields2=f51,f52,f53,f54,f55,f56,f57,f58&iscr=0&iscca=0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 同花顺
|
||||
|
||||
### 实时行情
|
||||
|
||||
```
|
||||
GET https://d.10jqka.com.cn/v4/time/hs_{code}/today.js
|
||||
# code: 直接用6位数字,如 600519
|
||||
```
|
||||
|
||||
注意:请求需要带 Referer: https://www.10jqka.com.cn
|
||||
|
||||
---
|
||||
|
||||
## 4. 雪球
|
||||
|
||||
### 实时行情
|
||||
|
||||
```
|
||||
GET https://stock.xueqiu.com/v5/stock/quote.json?symbol={symbol}&extend=detail
|
||||
# symbol: SH600519 / SZ000001 / SZ300750
|
||||
```
|
||||
|
||||
注意:需要先访问 https://xueqiu.com 获取 cookie(session),再请求数据接口。脚本中已处理。
|
||||
|
||||
---
|
||||
|
||||
## 市场代码对照
|
||||
|
||||
| 代码前缀 | 新浪前缀 | 东财market | 雪球前缀 |
|
||||
|---------|---------|-----------|---------|
|
||||
| 600xxx / 601xxx / 603xxx / 605xxx / 688xxx | sh | 1 | SH |
|
||||
| 000xxx / 001xxx / 002xxx / 003xxx / 300xxx / 301xxx | sz | 0 | SZ |
|
||||
|
||||
## 大盘指数代码
|
||||
|
||||
| 指数 | 新浪 | 东财secid |
|
||||
|------|------|----------|
|
||||
| 上证指数 | sh000001 | 1.000001 |
|
||||
| 深证成指 | sz399001 | 0.399001 |
|
||||
| 创业板指 | sz399006 | 0.399006 |
|
||||
| 科创50 | sh000688 | 1.000688 |
|
||||
| 北证50 | bj899050 | — |
|
||||
@@ -0,0 +1,22 @@
|
||||
# 价格预警监控列表
|
||||
|
||||
## 预警记录
|
||||
|
||||
| 股票 | 代码 | 预警类型 | 目标价 | 当前价 | 状态 | 设置时间 |
|
||||
|------|------|----------|--------|--------|------|----------|
|
||||
| 铜陵有色 | 000630 | 跌破 | 6.80 元 | 7.15 元 | ⏳ 监控中 | 2026-03-13 03:33 |
|
||||
|
||||
---
|
||||
|
||||
## 预警详情
|
||||
|
||||
### 铜陵有色 (000630)
|
||||
- **预警条件**:股价跌破 6.80 元
|
||||
- **当前价格**:7.15 元 (2026-03-13 15:00)
|
||||
- **距离预警**:-0.35 元 (-4.9%)
|
||||
- **设置时间**:2026-03-13 03:33
|
||||
- **备注**:用户要求跌破 6.8 元时进行预警
|
||||
|
||||
---
|
||||
|
||||
> ⚠️ **说明**:本工具做辅助分析,建议配合券商 App 实时推送获取即时预警。
|
||||
@@ -0,0 +1,299 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
A股实时行情抓取脚本
|
||||
数据源:新浪财经(主)、东方财富(备)
|
||||
用法:
|
||||
python3 fetch_stock.py --code 600519
|
||||
python3 fetch_stock.py --code 000001 sz000001 300750
|
||||
python3 fetch_stock.py --index
|
||||
python3 fetch_stock.py --hot-sectors
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
HEADERS = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Referer": "https://finance.sina.com.cn",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||
}
|
||||
|
||||
|
||||
def get_market_prefix(code: str) -> str:
|
||||
"""根据股票代码判断市场前缀"""
|
||||
code = code.strip().upper()
|
||||
if code.startswith("SH") or code.startswith("SZ"):
|
||||
return code[:2].lower(), code[2:]
|
||||
code = re.sub(r"[^0-9]", "", code)
|
||||
if code.startswith(("60", "68", "51", "58", "11")):
|
||||
return "sh", code
|
||||
elif code.startswith(("00", "30", "15", "12", "16", "13")):
|
||||
return "sz", code
|
||||
return "sh", code # default
|
||||
|
||||
|
||||
def fetch_url(url: str, extra_headers: dict = None) -> str:
|
||||
req = urllib.request.Request(url, headers=HEADERS)
|
||||
if extra_headers:
|
||||
for k, v in extra_headers.items():
|
||||
req.add_header(k, v)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
charset = "gbk" if "sina" in url or "sinajs" in url else "utf-8"
|
||||
return resp.read().decode(charset, errors="replace")
|
||||
except Exception as e:
|
||||
return ""
|
||||
|
||||
|
||||
def parse_sina_stock(raw: str, symbol: str) -> dict:
|
||||
"""解析新浪财经股票数据"""
|
||||
match = re.search(r'"([^"]*)"', raw)
|
||||
if not match:
|
||||
return {}
|
||||
parts = match.group(1).split(",")
|
||||
if len(parts) < 32:
|
||||
return {}
|
||||
try:
|
||||
name = parts[0]
|
||||
prev_close = float(parts[2]) if parts[2] else 0
|
||||
open_price = float(parts[1]) if parts[1] else 0
|
||||
current = float(parts[3]) if parts[3] else 0
|
||||
high = float(parts[4]) if parts[4] else 0
|
||||
low = float(parts[5]) if parts[5] else 0
|
||||
volume = int(parts[8]) if parts[8] else 0 # 手
|
||||
amount = float(parts[9]) if parts[9] else 0 # 元
|
||||
date_str = parts[30] if len(parts) > 30 else ""
|
||||
time_str = parts[31] if len(parts) > 31 else ""
|
||||
|
||||
change = current - prev_close
|
||||
change_pct = (change / prev_close * 100) if prev_close else 0
|
||||
turnover_approx = volume / 1000 # 粗略换手(无流通股数据)
|
||||
|
||||
return {
|
||||
"symbol": symbol,
|
||||
"name": name,
|
||||
"current": round(current, 2),
|
||||
"change": round(change, 2),
|
||||
"change_pct": round(change_pct, 2),
|
||||
"open": round(open_price, 2),
|
||||
"high": round(high, 2),
|
||||
"low": round(low, 2),
|
||||
"prev_close": round(prev_close, 2),
|
||||
"volume_lot": volume, # 手
|
||||
"amount_yuan": round(amount, 2),
|
||||
"amount_yi": round(amount / 1e8, 2),
|
||||
"date": date_str,
|
||||
"time": time_str,
|
||||
"source": "新浪财经",
|
||||
"fetch_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
except (ValueError, IndexError):
|
||||
return {}
|
||||
|
||||
|
||||
def fetch_single_stock(code: str) -> dict:
|
||||
"""抓取单只股票行情"""
|
||||
prefix, clean_code = get_market_prefix(code)
|
||||
symbol = f"{prefix}{clean_code}"
|
||||
url = f"http://hq.sinajs.cn/list={symbol}"
|
||||
raw = fetch_url(url)
|
||||
if raw:
|
||||
data = parse_sina_stock(raw, symbol)
|
||||
if data:
|
||||
return data
|
||||
|
||||
# 备用:东方财富
|
||||
market = 1 if prefix == "sh" else 0
|
||||
url2 = (
|
||||
f"http://push2.eastmoney.com/api/qt/stock/get"
|
||||
f"?secid={market}.{clean_code}"
|
||||
f"&fields=f43,f44,f45,f46,f47,f48,f57,f58,f60,f107,f169,f170,f171"
|
||||
)
|
||||
raw2 = fetch_url(url2, {"Referer": "https://www.eastmoney.com"})
|
||||
if raw2:
|
||||
try:
|
||||
obj = json.loads(raw2)
|
||||
d = obj.get("data", {}) or {}
|
||||
if d.get("f43"):
|
||||
prev = d["f60"] / 100
|
||||
curr = d["f43"] / 100
|
||||
chg = d["f169"] / 100
|
||||
chg_pct = d["f170"] / 100
|
||||
return {
|
||||
"symbol": symbol,
|
||||
"name": d.get("f58", ""),
|
||||
"current": round(curr, 2),
|
||||
"change": round(chg, 2),
|
||||
"change_pct": round(chg_pct, 2),
|
||||
"open": round(d["f46"] / 100, 2),
|
||||
"high": round(d["f44"] / 100, 2),
|
||||
"low": round(d["f45"] / 100, 2),
|
||||
"prev_close": round(prev, 2),
|
||||
"volume_lot": d.get("f47", 0),
|
||||
"amount_yuan": d.get("f48", 0),
|
||||
"amount_yi": round(d.get("f48", 0) / 1e8, 2),
|
||||
"turnover_pct": round(d.get("f171", 0) / 100, 2),
|
||||
"source": "东方财富",
|
||||
"fetch_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {"error": f"无法获取 {code} 的行情数据", "symbol": symbol}
|
||||
|
||||
|
||||
def fetch_index() -> list:
|
||||
"""抓取主要大盘指数"""
|
||||
symbols = "s_sh000001,s_sz399001,s_sz399006,s_sh000688"
|
||||
names_map = {
|
||||
"s_sh000001": "上证指数",
|
||||
"s_sz399001": "深证成指",
|
||||
"s_sz399006": "创业板指",
|
||||
"s_sh000688": "科创50",
|
||||
}
|
||||
url = f"http://hq.sinajs.cn/list={symbols}"
|
||||
raw = fetch_url(url)
|
||||
results = []
|
||||
if raw:
|
||||
for sym, name in names_map.items():
|
||||
pattern = rf'hq_str_{re.escape(sym)}="([^"]*)"'
|
||||
m = re.search(pattern, raw)
|
||||
if m:
|
||||
parts = m.group(1).split(",")
|
||||
if len(parts) >= 5:
|
||||
try:
|
||||
results.append({
|
||||
"name": parts[0] or name,
|
||||
"current": float(parts[1]),
|
||||
"change": float(parts[2]),
|
||||
"change_pct": float(parts[3]),
|
||||
"volume_yi_lot": round(float(parts[4]) / 1e8, 2),
|
||||
"amount_yi": round(float(parts[5]) / 1e8, 2) if len(parts) > 5 else 0,
|
||||
"fetch_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"source": "新浪财经",
|
||||
})
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
return results
|
||||
|
||||
|
||||
def fetch_hot_sectors() -> list:
|
||||
"""抓取热点板块(东方财富概念板块涨幅榜)"""
|
||||
url = (
|
||||
"http://push2.eastmoney.com/api/qt/clist/get"
|
||||
"?pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281"
|
||||
"&fltt=2&invt=2&fid=f3"
|
||||
"&fs=m:90+t:2+f:!50"
|
||||
"&fields=f2,f3,f4,f12,f14,f20,f128,f136,f207,f208,f209"
|
||||
)
|
||||
raw = fetch_url(url, {"Referer": "https://www.eastmoney.com"})
|
||||
results = []
|
||||
if raw:
|
||||
try:
|
||||
obj = json.loads(raw)
|
||||
items = obj.get("data", {}).get("diff", [])
|
||||
for item in items:
|
||||
results.append({
|
||||
"name": item.get("f14", ""),
|
||||
"change_pct": round(item.get("f3", 0), 2),
|
||||
"leading_stock": item.get("f128", ""),
|
||||
"leading_change_pct": round(item.get("f136", 0), 2),
|
||||
"amount_yi": round(item.get("f20", 0) / 1e8, 2),
|
||||
})
|
||||
except Exception:
|
||||
pass
|
||||
return results
|
||||
|
||||
|
||||
def fmt_stock(d: dict) -> str:
|
||||
if "error" in d:
|
||||
return f"❌ {d['error']}"
|
||||
sign = "+" if d["change"] >= 0 else ""
|
||||
emoji = "🔴" if d["change"] >= 0 else "🟢"
|
||||
lines = [
|
||||
f"{emoji} {d['name']}({d['symbol'].upper()})",
|
||||
f" 当前价:{d['current']} 元",
|
||||
f" 涨跌幅:{sign}{d['change_pct']}% 涨跌额:{sign}{d['change']}",
|
||||
f" 今开:{d['open']} 最高:{d['high']} 最低:{d['low']} 昨收:{d['prev_close']}",
|
||||
f" 成交量:{d['volume_lot']:,} 手 成交额:{d['amount_yi']} 亿",
|
||||
]
|
||||
if "turnover_pct" in d:
|
||||
lines.append(f" 换手率:{d['turnover_pct']}%")
|
||||
lines.append(f" 数据来源:{d['source']} | 更新时间:{d.get('time', '')} {d['fetch_time']}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def fmt_index(items: list) -> str:
|
||||
lines = ["📊 大盘指数实时行情"]
|
||||
for d in items:
|
||||
sign = "+" if d["change"] >= 0 else ""
|
||||
emoji = "🔴" if d["change"] >= 0 else "🟢"
|
||||
lines.append(
|
||||
f" {emoji} {d['name']}: {d['current']:,.2f} {sign}{d['change']:+.2f} ({sign}{d['change_pct']}%)"
|
||||
f" 成交额 {d['amount_yi']} 亿"
|
||||
)
|
||||
if items:
|
||||
lines.append(f" 更新时间:{items[0]['fetch_time']}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def fmt_sectors(items: list) -> str:
|
||||
lines = ["🔥 热点板块涨幅榜(概念板块 TOP20)"]
|
||||
for i, d in enumerate(items, 1):
|
||||
sign = "+" if d["change_pct"] >= 0 else ""
|
||||
lines.append(
|
||||
f" {i:2d}. {d['name']:<12} {sign}{d['change_pct']}%"
|
||||
f" 龙头:{d['leading_stock']}({sign}{d['leading_change_pct']}%)"
|
||||
f" 成交额:{d['amount_yi']}亿"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="A股实时行情抓取")
|
||||
parser.add_argument("--code", nargs="+", help="股票代码,支持多个(如 600519 000001)")
|
||||
parser.add_argument("--index", action="store_true", help="查询大盘指数")
|
||||
parser.add_argument("--hot-sectors", action="store_true", help="查询热点板块")
|
||||
parser.add_argument("--json", action="store_true", help="输出原始JSON")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.index:
|
||||
data = fetch_index()
|
||||
if args.json:
|
||||
print(json.dumps(data, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
print(fmt_index(data))
|
||||
return
|
||||
|
||||
if args.hot_sectors:
|
||||
data = fetch_hot_sectors()
|
||||
if args.json:
|
||||
print(json.dumps(data, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
print(fmt_sectors(data))
|
||||
return
|
||||
|
||||
if args.code:
|
||||
results = []
|
||||
for code in args.code:
|
||||
d = fetch_single_stock(code)
|
||||
results.append(d)
|
||||
if args.json:
|
||||
print(json.dumps(results, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
for d in results:
|
||||
print(fmt_stock(d))
|
||||
print()
|
||||
return
|
||||
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user