每日备份 2026-03-27
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "a-stock-trading-assistant",
|
||||
"installedVersion": "1.0.0",
|
||||
"installedAt": 1773343749868
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
---
|
||||
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位,成交额以亿元为单位
|
||||
- 大盘/个股分析结构清晰,使用简洁表格或分项列出
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"ownerId": "kn70hb4emf3csex5aeqt51arrx82d01z",
|
||||
"slug": "a-stock-trading-assistant",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1772789682966
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
# 个股分析方法参考
|
||||
|
||||
## 技术面分析框架
|
||||
|
||||
### 均线系统判断
|
||||
|
||||
| 形态 | 条件 | 含义 |
|
||||
|------|------|------|
|
||||
| 多头排列 | 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天以上保持热度
|
||||
- 有政策/事件催化
|
||||
- 龙头股有持续涨停
|
||||
|
||||
### 情绪板块(短线机会)
|
||||
- 单日暴热,次日需观察持续性
|
||||
- 题材性质(概念股)
|
||||
- 跟风盘多,需快进快出
|
||||
|
||||
### 龙头股识别
|
||||
- 板块内首板/连板的核心票
|
||||
- 换手率高但不崩盘
|
||||
- 量价配合良好
|
||||
@@ -1,114 +0,0 @@
|
||||
# 数据源 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 | — |
|
||||
@@ -1,22 +0,0 @@
|
||||
# 价格预警监控列表
|
||||
|
||||
## 预警记录
|
||||
|
||||
| 股票 | 代码 | 预警类型 | 目标价 | 当前价 | 状态 | 设置时间 |
|
||||
|------|------|----------|--------|--------|------|----------|
|
||||
| 铜陵有色 | 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 实时推送获取即时预警。
|
||||
@@ -1,299 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "content-collector-skill",
|
||||
"installedVersion": "0.1.0",
|
||||
"installedAt": 1773515645180
|
||||
}
|
||||
@@ -1,800 +0,0 @@
|
||||
---
|
||||
name: content-collector
|
||||
description: Automatically collect and archive content from shared links in group chats. When a user shares a link (WeChat articles, Feishu docs, web pages, etc.) in any group chat and asks to archive/collect/save it, this skill triggers to fetch the content, create a Feishu document, and update the knowledge base table. Use when: (1) User shares a link and asks to "收录/转存/保存" content, (2) Need to archive web content to Feishu docs, (3) Building a personal knowledge base from shared links, (4) Organizing learning materials from various sources.
|
||||
---
|
||||
|
||||
# Content Collector - 链接内容自动收录技能
|
||||
|
||||
## Overview
|
||||
|
||||
This skill enables automatic collection and archiving of content from shared links into a structured knowledge base.
|
||||
|
||||
**Core Workflow:**
|
||||
```
|
||||
Detect Link → Fetch Content → Create Feishu Doc → Update Table
|
||||
```
|
||||
|
||||
## When to Use
|
||||
|
||||
### 模式1:主动触发(显式关键词)
|
||||
当用户消息包含以下**触发词**时,立即执行收录:
|
||||
- "收录" / "转存" / "保存" / "存档" / "存一下" / "归档" / "备份" / "收藏"
|
||||
- "存到知识库" / "加入知识库" / "转飞书"
|
||||
|
||||
**示例:**
|
||||
- "这个链接收录一下"
|
||||
- "存到知识库"
|
||||
- "转存这篇教程"
|
||||
|
||||
### 模式2:静默收录(自动检测)
|
||||
在**群聊场景**中,自动检测以下链接并静默收录:
|
||||
- 飞书文档/表格/Wiki(feishu.cn)
|
||||
- 微信公众号文章(mp.weixin.qq.com)
|
||||
- 技术博客/教程站点
|
||||
- 知识分享类链接
|
||||
|
||||
**静默收录条件:**
|
||||
1. 消息来自群聊(非私聊)
|
||||
2. 消息包含可识别的知识类链接
|
||||
3. 用户没有明确拒绝的意图
|
||||
|
||||
**两种模式优先级:**
|
||||
```
|
||||
检测到主动触发词 → 立即收录(显式模式)
|
||||
未检测到触发词但检测到链接 → 静默收录(隐式模式)
|
||||
```
|
||||
|
||||
## Supported Link Types
|
||||
|
||||
| Type | Example | Fetch Method |
|
||||
|------|---------|--------------|
|
||||
| WeChat Article | `https://mp.weixin.qq.com/s/xxx` | kimi_fetch |
|
||||
| Feishu Doc | `https://xxx.feishu.cn/docx/xxx` | feishu_fetch_doc |
|
||||
| Feishu Wiki | `https://xxx.feishu.cn/wiki/xxx` | feishu_fetch_doc |
|
||||
| Web Page | General URLs | kimi_fetch / web_fetch |
|
||||
|
||||
## Global Availability (全局可用配置)
|
||||
|
||||
**生效范围:所有用户、所有群聊**
|
||||
|
||||
本技能已配置为全局可用,支持以下对象:
|
||||
|
||||
| 对象类型 | 支持状态 | 说明 |
|
||||
|---------|---------|------|
|
||||
| **所有用户** | ✅ 可用 | 任何用户分享的链接均可被收录 |
|
||||
| **所有群聊** | ✅ 可用 | 支持技能中心群、养虾群、学习群等所有群组 |
|
||||
| **私聊消息** | ✅ 可用 | 用户私信分享链接也可触发收录 |
|
||||
| **多渠道** | ✅ 可用 | 飞书、其他渠道统一支持 |
|
||||
|
||||
**权限说明:**
|
||||
- 任何用户均可触发收录(无需管理员权限)
|
||||
- 收录的文档统一存储到指定的知识库目录
|
||||
- 所有用户均可查看已收录的文档
|
||||
|
||||
---
|
||||
|
||||
## Installation & Permission Check (安装与权限检查)
|
||||
|
||||
在正式使用本技能前,系统必须自动或引导用户完成以下权限校验,以确保流程不中断:
|
||||
|
||||
### 1. 飞书权限清单
|
||||
| 权限项 | 验证工具 | 目的 |
|
||||
|-------|---------|------|
|
||||
| **OAuth 授权** | `feishu_oauth` | 获取操作飞书文档和表格的用户凭证 |
|
||||
| **知识库写入权限** | `feishu_create_doc` | 确保能在指定的 Space ID 下创建节点 |
|
||||
| **多维表格编辑权限** | `feishu_bitable_app_table_record` | 确保能向指定的 app_token 写入记录 |
|
||||
| **图片上传权限** | `feishu_im_bot_upload` | 允许将本地图片同步至飞书素材库 |
|
||||
|
||||
### 2. 预检流程 (Pre-flight Check)
|
||||
每次“安装”或配置更新后,执行以下检查:
|
||||
1. **验证 Space ID 可访问性**:尝试在指定目录下获取节点列表。
|
||||
2. **验证 Table 结构**:检查 `关键词`、`原链接` 等必需字段是否存在。
|
||||
3. **静默测试**:如果权限不足,立即通过 `feishu_oauth` 弹出授权引导,而非在执行收录时报错。
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Before using, ensure these are configured in MEMORY.md:
|
||||
|
||||
```markdown
|
||||
## Content Collector Config
|
||||
- **Knowledge Base Table**: `[Your Bitable App Token]` (Bitable app_token)
|
||||
- **Table URL**: [Your Bitable Table URL]
|
||||
- **Default Table ID**: `[Your Table ID]` (will auto-detect if available)
|
||||
- **Knowledge Base Space ID**: `[Your Space ID]` (所有文档创建在此知识库下)
|
||||
- **Knowledge Base URL**: [Your Knowledge Base Homepage URL]
|
||||
- **Content Categories**: 技术教程, 实战案例, 产品文档, 学习笔记
|
||||
- **Global Access**: 所有用户可用,所有群聊可用
|
||||
```
|
||||
|
||||
**Note**:
|
||||
1. This skill updates ONLY the configured knowledge base table. Do not create or update any other tables.
|
||||
2. **All created documents must be saved under the designated Knowledge Base** using wiki_node parameter.
|
||||
3. **Global Access**: 所有用户、所有群聊均可使用本技能,收录的文档对全员可见。
|
||||
|
||||
---
|
||||
|
||||
## 📚 知识库文档存储规则(必遵守)
|
||||
|
||||
所有收录的文档必须按照以下规则分类存储到知识库对应目录:
|
||||
|
||||
### 知识库目录结构
|
||||
|
||||
请参考各项目或团队定义的知识库标准目录结构进行存储。收录的文档通常存放在“素材”或“归档”类目录下。
|
||||
|
||||
### 文档分类映射规则
|
||||
|
||||
| 内容分类 | 存储目录 (wiki_node) | 命名前缀 | 示例 |
|
||||
|----------|---------------------|----------|------|
|
||||
| 技术教程 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 📖 | 📖 [标题] |
|
||||
| 实战案例 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 🛠️ | 🛠️ [标题] |
|
||||
| 产品文档 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 📄 | 📄 [标题] |
|
||||
| 学习笔记 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 💡 | 💡 [标题] |
|
||||
| 热点资讯 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 🔥 | 🔥 [标题] |
|
||||
| 设计技能 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 🎨 | 🎨 [标题] |
|
||||
| 工具推荐 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 🔧 | 🔧 [标题] |
|
||||
| 训练营 | `F9pFw9dxTiXmpsk5bNlco704nag` (内容文档) | 🎓 | 🎓 [标题] |
|
||||
|
||||
### 文档命名规范
|
||||
|
||||
```
|
||||
[Emoji前缀] [原标题] | 收录日期
|
||||
|
||||
示例:
|
||||
📖 OpenClaw保姆级教程 | 2026-03-08
|
||||
🛠️ 火山方舟自动化报表案例 | 2026-03-08
|
||||
🔥 GPT-5.4发布解读 | 2026-03-08
|
||||
```
|
||||
|
||||
### 文档模板
|
||||
|
||||
```markdown
|
||||
# [Emoji] [原标题]
|
||||
|
||||
> 📌 **元信息**
|
||||
> - 来源:[原始来源]
|
||||
> - 原文链接:[原始URL]
|
||||
> - 收录时间:YYYY-MM-DD
|
||||
> - 内容分类:[技术教程/实战案例/产品文档/学习笔记/热点资讯/设计技能/工具推荐/训练营]
|
||||
> - 关键词:[关键词1, 关键词2, 关键词3]
|
||||
|
||||
---
|
||||
|
||||
## 📋 核心要点
|
||||
|
||||
[3-5条核心内容摘要]
|
||||
|
||||
---
|
||||
|
||||
## 📝 正文内容
|
||||
|
||||
[完整的转存内容]
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
- 原文链接:[原始URL]
|
||||
- 知识库索引:[素材池文档索引链接]
|
||||
|
||||
---
|
||||
|
||||
📚 **收录时间**:YYYY-MM-DD
|
||||
🏷️ **分类**:[分类名]
|
||||
🔖 **关键词**:[关键词]
|
||||
```
|
||||
|
||||
### 自动更新素材索引
|
||||
|
||||
每次收录完成后,必须:
|
||||
|
||||
1. **更新多维表格** - 添加新记录到素材池表格
|
||||
2. **更新素材索引文档** - 在「📚 内容素材池文档索引」中添加条目
|
||||
3. **更新分类统计** - 更新各分类的文档数量和占比
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Detect and Parse Link
|
||||
|
||||
Extract URL from user message using regex or direct extraction.
|
||||
|
||||
### Step 2: Fetch Content
|
||||
|
||||
Choose appropriate fetch method based on URL pattern:
|
||||
|
||||
**For WeChat articles:**
|
||||
```python
|
||||
kimi_fetch(url="https://mp.weixin.qq.com/s/xxx")
|
||||
```
|
||||
|
||||
**For Feishu docs:**
|
||||
```python
|
||||
feishu_fetch_doc(doc_id="https://xxx.feishu.cn/docx/xxx")
|
||||
```
|
||||
|
||||
**For general web pages:**
|
||||
```python
|
||||
kimi_fetch(url="https://example.com/article")
|
||||
# or
|
||||
web_fetch(url="https://example.com/article")
|
||||
```
|
||||
|
||||
### Step 3: Analyze and Categorize
|
||||
|
||||
**智能分类判断:**
|
||||
根据内容特征自动判断分类:
|
||||
|
||||
| 判断依据 | 分类 |
|
||||
|----------|------|
|
||||
| 包含"安装/配置/部署/教程"等词 | 📖 技术教程 |
|
||||
| 包含"案例/实战/项目/演示"等词 | 🛠️ 实战案例 |
|
||||
| 包含"安全/公告/版本/功能"等词 | 📄 产品文档 |
|
||||
| 包含"学习/成长/指南/笔记"等词 | 💡 学习笔记 |
|
||||
| 包含"发布/新功能/热点"等词 | 🔥 热点资讯 |
|
||||
| 包含"设计/Prompt/美学"等词 | 🎨 设计技能 |
|
||||
| 包含"工具/CLI/插件"等词 | 🔧 工具推荐 |
|
||||
| 包含"训练营/课程/教学"等词 | 🎓 训练营 |
|
||||
|
||||
### Step 4: Process Images (图片处理)
|
||||
|
||||
When content contains images, download and upload them to Feishu:
|
||||
|
||||
**Image Processing Workflow:**
|
||||
```python
|
||||
# 1. Extract image URLs from markdown
|
||||
import re
|
||||
image_urls = re.findall(r'!\[.*?\]\((https?://[^\)]+)\)', markdown_content)
|
||||
|
||||
# 2. Download and upload each image
|
||||
for img_url in image_urls:
|
||||
try:
|
||||
# Download image
|
||||
local_path = f"/tmp/img_{hash(img_url)}.jpg"
|
||||
download_image(img_url, local_path)
|
||||
|
||||
# Upload to Feishu
|
||||
upload_result = feishu_im_bot_upload(
|
||||
action="upload_image",
|
||||
file_path=local_path
|
||||
)
|
||||
|
||||
# Replace URL in markdown
|
||||
new_url = upload_result.get("image_key") or img_url
|
||||
markdown_content = markdown_content.replace(img_url, new_url)
|
||||
|
||||
except Exception as e:
|
||||
# Keep original URL if upload fails
|
||||
print(f"Failed to process image {img_url}: {e}")
|
||||
continue
|
||||
```
|
||||
|
||||
**Fallback Strategy:**
|
||||
- If image upload fails, keep original URL
|
||||
- Add warning note in document
|
||||
- Include original source link for reference
|
||||
|
||||
### Step 5: Create Feishu Document (按知识库规则存储)
|
||||
|
||||
Convert processed markdown to Feishu document with proper organization:
|
||||
|
||||
```python
|
||||
# 1. 确定分类和参数
|
||||
content_category = classify_content(markdown_content) # 📖/🛠️/📄/💡/🔥/🎨/🔧/🎓
|
||||
emoji_prefix = get_emoji_prefix(content_category) # 根据分类获取emoji
|
||||
wiki_node = get_wiki_node_by_category(content_category) # 获取存储目录
|
||||
|
||||
# 2. 生成文档标题
|
||||
doc_title = f"{emoji_prefix} {original_title} | {today_date}"
|
||||
|
||||
# 3. 生成文档内容(使用标准模板)
|
||||
doc_content = f"""# {emoji_prefix} {original_title}
|
||||
|
||||
> 📌 **元信息**
|
||||
> - 来源:{source_name}
|
||||
> - 原文链接:{original_url}
|
||||
> - 收录时间:{today_date}
|
||||
> - 内容分类:{content_category}
|
||||
> - 关键词:{keywords}
|
||||
|
||||
---
|
||||
|
||||
## 📋 核心要点
|
||||
|
||||
{extract_key_points(markdown_content, 5)}
|
||||
|
||||
---
|
||||
|
||||
## 📝 正文内容
|
||||
|
||||
{processed_markdown_content}
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
- 原文链接:{original_url}
|
||||
- 知识库索引:[Your Index Document URL]
|
||||
|
||||
---
|
||||
|
||||
📅 **收录时间**:{today_date}
|
||||
🏷️ **分类**:{content_category}
|
||||
🔖 **关键词**:{keywords}
|
||||
"""
|
||||
|
||||
# 4. 创建文档到知识库对应目录
|
||||
feishu_create_doc(
|
||||
title=doc_title,
|
||||
markdown=doc_content,
|
||||
wiki_node=wiki_node # 必须指定存储目录
|
||||
)
|
||||
```
|
||||
|
||||
**存储目录映射:**
|
||||
| 分类 | wiki_node | 目录名 |
|
||||
|------|-----------|--------|
|
||||
| 所有素材 | `F9pFw9dxTiXmpsk5bNlco704nag` | 04-内容素材 |
|
||||
|
||||
**IMPORTANT**:
|
||||
1. All documents MUST be created under the designated Knowledge Base using wiki_node parameter.
|
||||
2. Documents must follow the naming convention: `[Emoji] [Title] | [Date]`
|
||||
3. Documents must use the standard template with metadata section.
|
||||
|
||||
### Step 6: Update Knowledge Base Table
|
||||
|
||||
Add record to the Bitable knowledge base (ONLY update this specific table):
|
||||
|
||||
```python
|
||||
feishu_bitable_app_table_record(
|
||||
action="create",
|
||||
app_token="[Your App Token]", # Configured in MEMORY.md
|
||||
table_id="[Your Table ID]", # Will use correct table ID from the base
|
||||
fields={
|
||||
"关键词": keywords,
|
||||
"内容分类": content_category,
|
||||
"文档标题": [{"text": original_title, "type": "text"}],
|
||||
"来源": [{"text": source_name, "type": "text"}],
|
||||
"核心要点": [{"text": key_points, "type": "text"}],
|
||||
"飞书文档链接": {"link": new_doc_url, "text": "飞书文档", "type": "url"},
|
||||
"原链接": {"link": original_url, "text": "原文链接", "type": "url"} # 新增:存储原始链接
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
**Table Fields:**
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| 关键词 | Text | Search keywords for the content |
|
||||
| 内容分类 | Single Select | Category: 📖技术教程/🛠️实战案例/📄产品文档/💡学习笔记/🔥热点资讯/🎨设计技能/🔧工具推荐/🎓训练营 |
|
||||
| 文档标题 | Text | Title of the archived document |
|
||||
| 来源 | Text | Original source name |
|
||||
| 核心要点 | Text | Key points summary (3-5 items) |
|
||||
| 飞书文档链接 | URL | Link to the created Feishu document |
|
||||
| 原链接 | URL | **Original source URL** - 新增字段,存储采集的原始链接 |
|
||||
|
||||
**IMPORTANT**: Only update the configured knowledge base table. Never create or modify other tables.
|
||||
|
||||
### Step 7: Update Content Index Document
|
||||
|
||||
After creating the document and updating the table, MUST update the index document:
|
||||
|
||||
```python
|
||||
# 1. 获取当前索引文档内容
|
||||
index_doc = feishu_fetch_doc(doc_id="[Your Index Doc ID]")
|
||||
|
||||
# 2. 在对应分类表格中添加新行
|
||||
new_index_entry = f"| {original_title} | {source_name} | [查看]({new_doc_url}) |\n"
|
||||
|
||||
# 3. 更新分类统计
|
||||
update_category_stats(content_category)
|
||||
|
||||
# 4. 更新总计数
|
||||
update_total_count()
|
||||
```
|
||||
|
||||
**或者直接追加到索引文档的末尾:**
|
||||
```python
|
||||
feishu_update_doc(
|
||||
doc_id="[Your Index Doc ID]",
|
||||
mode="append",
|
||||
markdown=f"""
|
||||
| {original_title} | {source_name} | [查看]({new_doc_url}) |
|
||||
"""
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Content Categorization Guide
|
||||
|
||||
| Category | Emoji | Description | Examples |
|
||||
|----------|-------|-------------|----------|
|
||||
| **技术教程** | 📖 | Step-by-step technical guides | Installation, configuration, API usage |
|
||||
| **实战案例** | 🛠️ | Real-world implementation examples | Case studies, project demos |
|
||||
| **产品文档** | 📄 | Product features, security notices | Release notes, security advisories |
|
||||
| **学习笔记** | 💡 | Conceptual knowledge, methodologies | Best practices, architecture guides |
|
||||
| **热点资讯** | 🔥 | Breaking news, releases | GPT-5.4, new features |
|
||||
| **设计技能** | 🎨 | Design, prompts, aesthetics | AJ's prompts, design guides |
|
||||
| **工具推荐** | 🔧 | Tools, CLI, plugins | gws, trae, autotools |
|
||||
| **训练营** | 🎓 | Courses, bootcamps, tutorials | OpenClaw bootcamp |
|
||||
|
||||
**分类判断优先级:**
|
||||
1. 优先根据用户指定分类
|
||||
2. 其次根据标题关键词
|
||||
3. 最后根据内容特征自动判断
|
||||
4. 不确定时标记为"待分类",请用户确认
|
||||
|
||||
## Delete Record Process
|
||||
|
||||
When user replies "删除" or "删除 [keyword]":
|
||||
|
||||
```python
|
||||
# 1. Search records by keyword
|
||||
feishu_bitable_app_table_record(
|
||||
action="list",
|
||||
app_token="[Your App Token]",
|
||||
table_id="[Your Table ID]",
|
||||
filter={
|
||||
"conjunction": "and",
|
||||
"conditions": [
|
||||
{"field_name": "关键词", "operator": "contains", "value": [keyword]}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
# 2. Confirm deletion
|
||||
# If multiple found → list for user to select
|
||||
# If single found → ask for confirmation
|
||||
|
||||
# 3. Execute deletion
|
||||
feishu_bitable_app_table_record(
|
||||
action="delete",
|
||||
app_token="[Your App Token]",
|
||||
table_id="[Your Table ID]",
|
||||
record_id="record_id_to_delete"
|
||||
)
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Issues
|
||||
|
||||
| Error | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Fetch timeout | Network issue or heavy content | Retry with longer timeout, or use alternative fetch method |
|
||||
| Unauthenticated | OAuth token expired or not authed | Trigger `feishu_oauth` to refresh user credentials |
|
||||
| Permission denied | No write access to Space/Table | Check if user/bot has 'Editor' role in Feishu |
|
||||
| Content too long | Exceeds API limits | Truncate or split into multiple documents |
|
||||
| Table update failed | Wrong app_token or table_id | Verify configuration in MEMORY.md |
|
||||
| Field Missing | "原链接" field not in table | Add the field to Bitable manually or via API |
|
||||
|
||||
### Recovery Steps
|
||||
|
||||
1. If fetch fails → Try alternative method (kimi_fetch → web_fetch)
|
||||
2. If Feishu doc creation fails → Check OAuth status
|
||||
3. If table update fails → Verify table structure and field names
|
||||
4. Always report partial success (doc created but table not updated)
|
||||
|
||||
## Response Template
|
||||
|
||||
### 收录成功响应(流式Post格式)
|
||||
|
||||
```json
|
||||
{
|
||||
"msg_type": "post",
|
||||
"content": {
|
||||
"post": {
|
||||
"zh_cn": {
|
||||
"title": "✅ 收录完成",
|
||||
"content": [
|
||||
[
|
||||
{"tag": "text", "text": "📄 "},
|
||||
{"tag": "text", "text": "{emoji} {原标题} | {日期}", "style": {"bold": true}}
|
||||
],
|
||||
[{"tag": "text", "text": ""}],
|
||||
[
|
||||
{"tag": "text", "text": "💡 文档亮点:", "style": {"bold": true}}
|
||||
],
|
||||
[
|
||||
{"tag": "text", "text": "• {亮点1}"}
|
||||
],
|
||||
[
|
||||
{"tag": "text", "text": "• {亮点2}"}
|
||||
],
|
||||
[
|
||||
{"tag": "text", "text": "• {亮点3}"}
|
||||
],
|
||||
[{"tag": "text", "text": ""}],
|
||||
[
|
||||
{"tag": "text", "text": "🔗 "},
|
||||
{"tag": "a", "text": "查看飞书文档", "href": "{文档URL}"}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**简洁输出示例:**
|
||||
```
|
||||
✅ 收录完成
|
||||
|
||||
📄 📖 OpenClaw配置指南 | 2026-03-08
|
||||
|
||||
💡 文档亮点:
|
||||
• 完整配置示例,含9大模块详解
|
||||
• 多Agent扩展配置方案
|
||||
• 生产环境安全配置建议
|
||||
|
||||
🔗 查看飞书文档 → [点击打开](https://xxx.feishu.cn/docx/xxx)
|
||||
```
|
||||
|
||||
### 静默收录响应(流式Post格式)
|
||||
|
||||
```json
|
||||
{
|
||||
"msg_type": "post",
|
||||
"content": {
|
||||
"post": {
|
||||
"zh_cn": {
|
||||
"title": "✅ 已自动收录",
|
||||
"content": [
|
||||
[
|
||||
{"tag": "text", "text": "📄 "},
|
||||
{"tag": "text", "text": "{emoji} {原标题}", "style": {"bold": true}}
|
||||
],
|
||||
[{"tag": "text", "text": ""}],
|
||||
[
|
||||
{"tag": "text", "text": "💡 亮点:{亮点摘要}"}
|
||||
],
|
||||
[{"tag": "text", "text": ""}],
|
||||
[
|
||||
{"tag": "a", "text": "📎 查看文档", "href": "{文档URL}"}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 批量收录响应(流式Post格式)
|
||||
|
||||
```json
|
||||
{
|
||||
"msg_type": "post",
|
||||
"content": {
|
||||
"post": {
|
||||
"zh_cn": {
|
||||
"title": "✅ 批量收录完成({N}份)",
|
||||
"content": [
|
||||
[
|
||||
{"tag": "text", "text": "📄 {emoji1} {标题1}", "style": {"bold": true}}
|
||||
],
|
||||
[
|
||||
{"tag": "text", "text": " 💡 {亮点1}"}
|
||||
],
|
||||
[
|
||||
{"tag": "a", "text": " 🔗 查看", "href": "{链接1}"}
|
||||
],
|
||||
[{"tag": "text", "text": ""}],
|
||||
[
|
||||
{"tag": "text", "text": "📄 {emoji2} {标题2}", "style": {"bold": true}}
|
||||
],
|
||||
[
|
||||
{"tag": "text", "text": " 💡 {亮点2}"}
|
||||
],
|
||||
[
|
||||
{"tag": "a", "text": " 🔗 查看", "href": "{链接2}"}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**输出原则:**
|
||||
1. **必须流式Post格式** - 使用 msg_type: post
|
||||
2. **只包含3个核心要素:**
|
||||
- 文件名称(📄 Emoji + 标题 + 日期)
|
||||
- 文档亮点(💡 3-5条核心要点)
|
||||
- 飞书链接(🔗 点击查看)
|
||||
3. **不输出其他信息** - 不显示分类、不显示表格更新、不显示统计
|
||||
4. **保持简洁** - 每份文档3-5行内容
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always verify content was fetched correctly** before creating documents
|
||||
2. **Extract key insights** from the content for the summary
|
||||
3. **Use appropriate category** based on content nature
|
||||
4. **Generate relevant keywords** for better searchability
|
||||
5. **Keep source attribution** clear for copyright respect
|
||||
6. **Handle partial failures gracefully** - document what succeeded and what failed
|
||||
7. **Update index document** - Every new document must be added to the index
|
||||
8. **Follow naming convention** - Use [Emoji] [Title] | [Date] format
|
||||
9. **Store in correct directory** - Use wiki_node to place in right category
|
||||
|
||||
## 收录完成检查清单 (Checklist)
|
||||
|
||||
每次收录必须完成以下所有步骤:
|
||||
|
||||
- [ ] **执行权限预检**(验证 OAuth 及 Space/Table 写入权限)
|
||||
- [ ] 获取并处理原始内容(含图片)
|
||||
- [ ] 智能分类并确定 Emoji 前缀
|
||||
- [ ] 提取核心要点(3-5条)
|
||||
- [ ] 生成关键词
|
||||
- [ ] **创建飞书文档**(使用标准模板,指定 wiki_node)
|
||||
- [ ] **更新多维表格**(添加完整记录,包含**原链接**字段)
|
||||
- [ ] **更新文档索引**(在素材索引中添加条目)
|
||||
- [ ] 发送收录完成通知给用户
|
||||
|
||||
**任何一步未完成,视为收录失败!**
|
||||
|
||||
## Integration with Memory
|
||||
|
||||
After each collection, update MEMORY.md:
|
||||
|
||||
```markdown
|
||||
### YYYY-MM-DD - Content Collection
|
||||
- **新增收录**: [Title]
|
||||
- **来源**: [Source]
|
||||
- **分类**: [Category]
|
||||
- **知识库状态**: 共[N]条记录
|
||||
- **索引更新**: ✅ 已更新
|
||||
```
|
||||
|
||||
This skill is part of the core knowledge management system. Execute with care and attention to detail.
|
||||
|
||||
---
|
||||
|
||||
## 附录:图片处理解决方案
|
||||
|
||||
### 问题
|
||||
原始网页中的图片无法直接显示在飞书文档中(外链限制)
|
||||
|
||||
### 解决方案
|
||||
|
||||
#### 方案1:自动下载上传(推荐)
|
||||
|
||||
**实现步骤**:
|
||||
|
||||
```python
|
||||
import re
|
||||
import requests
|
||||
import os
|
||||
|
||||
def process_images_in_content(markdown_content):
|
||||
"""
|
||||
处理 Markdown 内容中的图片:
|
||||
1. 提取图片URL
|
||||
2. 下载到本地
|
||||
3. 上传到飞书
|
||||
4. 替换为飞书图片链接
|
||||
"""
|
||||
|
||||
# 正则匹配 Markdown 图片: 
|
||||
img_pattern = r'!\[(.*?)\]\((https?://[^\)]+)\)'
|
||||
|
||||
def replace_image(match):
|
||||
alt_text = match.group(1)
|
||||
img_url = match.group(2)
|
||||
|
||||
try:
|
||||
# 1. 下载图片
|
||||
local_path = f"/tmp/img_{abs(hash(img_url)) % 100000}.jpg"
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
||||
}
|
||||
response = requests.get(img_url, headers=headers, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
with open(local_path, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
# 2. 上传到飞书
|
||||
upload_result = feishu_im_bot_upload(
|
||||
action="upload_image",
|
||||
file_path=local_path
|
||||
)
|
||||
|
||||
image_key = upload_result.get("image_key")
|
||||
|
||||
# 3. 清理临时文件
|
||||
os.remove(local_path)
|
||||
|
||||
# 4. 返回飞书图片格式
|
||||
if image_key:
|
||||
return f""
|
||||
else:
|
||||
# 上传失败,保留原链接并添加警告
|
||||
return f"\n\n> ⚠️ 图片上传失败,已保留原链接: {img_url}"
|
||||
|
||||
except Exception as e:
|
||||
# 处理失败,保留原链接
|
||||
return f"\n\n> ⚠️ 图片处理失败: {str(e)[:50]}"
|
||||
|
||||
# 执行替换
|
||||
processed_content = re.sub(img_pattern, replace_image, markdown_content)
|
||||
|
||||
return processed_content
|
||||
```
|
||||
|
||||
**使用方式**:
|
||||
在创建文档之前调用:
|
||||
```python
|
||||
# 获取原始内容
|
||||
raw_content = kimi_fetch(url=link)
|
||||
|
||||
# 处理图片
|
||||
processed_content = process_images_in_content(raw_content)
|
||||
|
||||
# 创建文档(使用处理后的内容)
|
||||
feishu_create_doc(
|
||||
title=title,
|
||||
markdown=processed_content
|
||||
)
|
||||
```
|
||||
|
||||
#### 方案2:保留原链接 + 备用方案
|
||||
|
||||
```python
|
||||
def add_image_fallback_notice(markdown_content, original_url):
|
||||
"""
|
||||
在文档末尾添加图片查看说明
|
||||
"""
|
||||
notice = f"""
|
||||
|
||||
---
|
||||
|
||||
## 📎 原始图片资源
|
||||
|
||||
本文档中的图片已保留原始链接。
|
||||
如图片无法显示,请查看原文:
|
||||
[{original_url}]({original_url})
|
||||
|
||||
"""
|
||||
return markdown_content + notice
|
||||
```
|
||||
|
||||
#### 方案3:批量图片归档
|
||||
|
||||
创建一个独立的「图片资源库」多维表格:
|
||||
|
||||
```python
|
||||
# 收录时同时记录图片信息
|
||||
feishu_bitable_app_table_record(
|
||||
action="create",
|
||||
app_token="图片资源库_token",
|
||||
fields={
|
||||
"文档标题": doc_title,
|
||||
"图片URL": img_url,
|
||||
"图片描述": alt_text,
|
||||
"原文链接": original_url,
|
||||
"收录状态": "待上传/已上传/失败"
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### 建议实施顺序
|
||||
|
||||
1. **短期**(立即):使用方案2,保留原链接并添加查看提示
|
||||
2. **中期**(本周):实施方案1,自动下载上传核心文章的图片
|
||||
3. **长期**(可选):建立独立的图片资源库管理系统
|
||||
|
||||
### 注意事项
|
||||
|
||||
1. **图片大小限制**:飞书图片上传通常限制 10MB
|
||||
2. **格式支持**:JPG、PNG、GIF 等常见格式
|
||||
3. **网络超时**:下载图片时设置合理的超时时间(30秒)
|
||||
4. **失败处理**:单张图片失败不应影响整篇文档收录
|
||||
5. **版权注意**:确保有权限使用原网页中的图片
|
||||
|
||||
---
|
||||
|
||||
*图片处理方案 v1.0 - 2026-03-05*
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"ownerId": "kn7fnbpdh1f84y30j2c75qb6pn81z8ah",
|
||||
"slug": "content-collector-skill",
|
||||
"version": "0.1.0",
|
||||
"publishedAt": 1773042083338
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "daily-stock-analysis",
|
||||
"installedVersion": "1.0.2",
|
||||
"installedAt": 1773406361271
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
---
|
||||
name: daily-stock-analysis
|
||||
description: Deterministic daily stock analysis skill for global equities. Use when users need daily analysis, next-trading-day close prediction, prior forecast review, rolling accuracy, and reliable markdown report output.
|
||||
---
|
||||
|
||||
# Daily Stock Analysis
|
||||
|
||||
Perform market-aware, evidence-based daily stock analysis with prediction, next-run review, rolling accuracy tracking, and a structured self-evolution mechanism that updates future assumptions from observed forecast errors.
|
||||
|
||||
## Hard Rules
|
||||
|
||||
1. Read and write files only under `working_directory`.
|
||||
2. Save new reports only to:
|
||||
|
||||
- `<working_directory>/daily-stock-analysis/reports/`
|
||||
|
||||
3. Use filename:
|
||||
|
||||
- `YYYY-MM-DD-<TICKER>-analysis.md`
|
||||
|
||||
4. If same ticker/day file exists, ask user:
|
||||
|
||||
- `overwrite` or `new_version` (`-v2`, `-v3`, ...)
|
||||
- For unattended runs, default to `new_version`
|
||||
|
||||
5. Always review history before new prediction.
|
||||
6. Limit history read count to control token usage:
|
||||
|
||||
- Script mode: max 5 files (default)
|
||||
- Compatibility mode: max 3 files
|
||||
|
||||
## Required Scripts (Use First)
|
||||
|
||||
1. Plan output path + collect history:
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/report_manager.py plan \
|
||||
--workdir <working_directory> \
|
||||
--ticker <TICKER> \
|
||||
--run-date <YYYY-MM-DD> \
|
||||
--versioning auto \
|
||||
--history-limit 5
|
||||
```
|
||||
|
||||
2. Compute rolling accuracy from existing reports:
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/calc_accuracy.py \
|
||||
--workdir <working_directory> \
|
||||
--ticker <TICKER> \
|
||||
--windows 1,3,7,30 \
|
||||
--history-limit 60
|
||||
```
|
||||
|
||||
3. Optional: migrate legacy files after explicit user confirmation:
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/report_manager.py migrate \
|
||||
--workdir <working_directory> \
|
||||
--file <ABS_PATH_1> --file <ABS_PATH_2>
|
||||
```
|
||||
|
||||
## Compatibility Mode (No Python / Small Model)
|
||||
|
||||
If Python scripts are unavailable or model capability is limited, switch to minimal mode:
|
||||
|
||||
1. Read at most 3 recent reports for the same ticker.
|
||||
2. Use only a minimal source set:
|
||||
|
||||
- one official disclosure source
|
||||
- one reliable market data source (Yahoo Finance acceptable)
|
||||
|
||||
3. Output concise result only:
|
||||
|
||||
- recommendation
|
||||
- `pred_close_t1`
|
||||
- prior review (`prev_pred_close_t1`, `prev_actual_close_t1`, `AE`, `APE`) if available
|
||||
- one `improvement_action`
|
||||
|
||||
4. Save report with same filename rules in canonical reports directory.
|
||||
|
||||
See `references/minimal_mode.md`.
|
||||
|
||||
## Minimal Run Protocol
|
||||
|
||||
1. Resolve ticker/exchange/market (ask if ambiguous).
|
||||
2. Run `report_manager.py plan`.
|
||||
3. Read `history_files` returned by script.
|
||||
4. If `legacy_files` exist, list all absolute paths and ask whether to migrate.
|
||||
5. Gather data using `references/sources.md` + `references/search_queries.md`.
|
||||
6. Run `calc_accuracy.py` for consistent metrics.
|
||||
7. Render report using `references/report_template.md`.
|
||||
8. Save to `selected_output_file` returned by `report_manager.py`.
|
||||
|
||||
## Required Output Fields
|
||||
|
||||
Must include:
|
||||
|
||||
- `recommendation`
|
||||
- `pred_close_t1`
|
||||
- `prev_pred_close_t1`
|
||||
- `prev_actual_close_t1`
|
||||
- `AE`, `APE`
|
||||
- rolling strict/loose accuracy fields
|
||||
- `improvement_actions`
|
||||
|
||||
## Self-Improvement (Required)
|
||||
|
||||
Each run must include 1-3 concrete `improvement_actions` from recent misses and use them in the next run.
|
||||
Do not skip this step.
|
||||
|
||||
## Scheduling Recommendation
|
||||
|
||||
Recommend users set this as a weekday recurring task (for example 10:00 local time) to keep prediction-review windows continuous.
|
||||
|
||||
## References
|
||||
|
||||
Default:
|
||||
|
||||
- `references/workflow.md`
|
||||
- `references/report_template.md`
|
||||
- `references/metrics.md`
|
||||
- `references/search_queries.md`
|
||||
- `references/sources.md`
|
||||
- `references/minimal_mode.md`
|
||||
- `references/security.md`
|
||||
|
||||
Deep-dive only (`full_report` mode):
|
||||
|
||||
- `references/fundamental-analysis.md`
|
||||
- `references/technical-analysis.md`
|
||||
- `references/financial-metrics.md`
|
||||
|
||||
## Compliance
|
||||
|
||||
Always append:
|
||||
|
||||
"This content is for research and informational purposes only and does not constitute investment advice or a return guarantee. Markets are risky; invest with caution."
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"ownerId": "kn7arpc65p9wdnhbw70435rrf181jvtk",
|
||||
"slug": "daily-stock-analysis",
|
||||
"version": "1.0.2",
|
||||
"publishedAt": 1772265206033
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
# Financial Metrics Reference
|
||||
|
||||
Use these formulas and interpretations consistently. Metric availability may differ across US/CN/HK data providers.
|
||||
|
||||
## 1. Profitability
|
||||
|
||||
1. Gross Margin
|
||||
- Formula: `(Revenue - COGS) / Revenue * 100%`
|
||||
- Use: Pricing power and production efficiency.
|
||||
|
||||
2. Operating Margin
|
||||
- Formula: `Operating Income / Revenue * 100%`
|
||||
- Use: Core operating efficiency.
|
||||
|
||||
3. Net Margin
|
||||
- Formula: `Net Income / Revenue * 100%`
|
||||
- Use: End-to-end profitability quality.
|
||||
|
||||
4. ROE
|
||||
- Formula: `Net Income / Average Equity * 100%`
|
||||
- Use: Equity capital efficiency.
|
||||
|
||||
5. ROIC
|
||||
- Formula: `NOPAT / Invested Capital * 100%`
|
||||
- Use: Capital allocation quality across debt and equity.
|
||||
|
||||
## 2. Growth
|
||||
|
||||
1. Revenue Growth (YoY / QoQ)
|
||||
- Formula: `(Current Revenue - Prior Revenue) / Prior Revenue * 100%`
|
||||
|
||||
2. EPS Growth
|
||||
- Formula: `(Current EPS - Prior EPS) / Prior EPS * 100%`
|
||||
|
||||
3. Multi-year CAGR
|
||||
- Formula: `(Ending / Beginning)^(1/Years) - 1`
|
||||
|
||||
## 3. Valuation
|
||||
|
||||
1. P/E (Trailing / Forward)
|
||||
- Formula: `Price / EPS`
|
||||
|
||||
2. PEG
|
||||
- Formula: `P/E / Earnings Growth Rate`
|
||||
|
||||
3. P/B
|
||||
- Formula: `Price / Book Value Per Share`
|
||||
|
||||
4. P/S
|
||||
- Formula: `Market Cap / Revenue`
|
||||
|
||||
5. EV
|
||||
- Formula: `Market Cap + Total Debt - Cash`
|
||||
|
||||
6. EV/EBITDA
|
||||
- Formula: `EV / EBITDA`
|
||||
|
||||
7. EV/Sales
|
||||
- Formula: `EV / Revenue`
|
||||
|
||||
## 4. Leverage and Liquidity
|
||||
|
||||
1. Debt-to-Equity
|
||||
- Formula: `Total Debt / Total Equity`
|
||||
|
||||
2. Interest Coverage
|
||||
- Formula: `EBIT / Interest Expense`
|
||||
|
||||
3. Current Ratio
|
||||
- Formula: `Current Assets / Current Liabilities`
|
||||
|
||||
4. Quick Ratio
|
||||
- Formula: `(Current Assets - Inventory) / Current Liabilities`
|
||||
|
||||
## 5. Cash Flow Quality
|
||||
|
||||
1. Free Cash Flow (FCF)
|
||||
- Formula: `Operating Cash Flow - Capital Expenditures`
|
||||
|
||||
2. FCF Yield
|
||||
- Formula: `FCF Per Share / Price * 100%`
|
||||
|
||||
3. Cash Conversion
|
||||
- Formula: `FCF / Net Income`
|
||||
|
||||
## 6. Interpretation Guidance
|
||||
|
||||
1. Always compare metrics against:
|
||||
- Company historical range
|
||||
- Sector and direct peers
|
||||
- Current macro regime
|
||||
|
||||
2. Avoid single-metric conclusions.
|
||||
3. Flag where accounting standards or reporting cadence reduce cross-market comparability.
|
||||
@@ -1,75 +0,0 @@
|
||||
# Fundamental Analysis Reference
|
||||
|
||||
Use this framework in both `daily` and `full_report` modes. Keep outputs concise unless full report is requested.
|
||||
|
||||
## 1. Business Quality
|
||||
|
||||
Assess:
|
||||
|
||||
1. Moat quality:
|
||||
- Brand, network effects, switching costs, cost advantage, IP/regulatory barriers.
|
||||
|
||||
2. Management quality:
|
||||
- Capital allocation discipline, communication quality, execution consistency.
|
||||
|
||||
3. Business model durability:
|
||||
- Revenue concentration, customer concentration, geographic risk, pricing power.
|
||||
|
||||
## 2. Financial Health
|
||||
|
||||
Focus areas:
|
||||
|
||||
1. Profitability trend:
|
||||
- Gross, operating, net margin direction.
|
||||
|
||||
2. Growth quality:
|
||||
- Revenue and earnings growth consistency, segment contribution quality.
|
||||
|
||||
3. Balance sheet:
|
||||
- Debt burden, liquidity, refinancing risk, cash buffer.
|
||||
|
||||
4. Cash flow quality:
|
||||
- OCF consistency, FCF conversion, capex intensity.
|
||||
|
||||
## 3. Valuation Lens
|
||||
|
||||
Use multiple perspectives:
|
||||
|
||||
1. Relative multiples:
|
||||
- P/E, PEG, P/B, P/S, EV/EBITDA, EV/Sales.
|
||||
|
||||
2. Historical range context:
|
||||
- Current valuation vs own history.
|
||||
|
||||
3. Peer context:
|
||||
- Premium/discount vs direct peers and rationale.
|
||||
|
||||
## 4. Risk Framework
|
||||
|
||||
Map risks by category:
|
||||
|
||||
1. Company-specific:
|
||||
- Product concentration, customer concentration, execution risk, governance issues.
|
||||
|
||||
2. Market/macro:
|
||||
- Rate sensitivity, FX exposure, commodity sensitivity, policy risk.
|
||||
|
||||
3. Event risk:
|
||||
- Earnings, regulatory approvals, legal actions, financing events.
|
||||
|
||||
## 5. Market-Specific Notes (US/CN/HK)
|
||||
|
||||
1. Data depth may vary by market and language.
|
||||
2. Prefer exchange filings and official disclosure portals in each market.
|
||||
3. Align accounting period labels and fiscal calendars before comparison.
|
||||
4. Flag where metric comparability is limited.
|
||||
|
||||
## 6. Output Guidance
|
||||
|
||||
For daily mode, include:
|
||||
|
||||
- 2-3 key fundamental drivers
|
||||
- 1-2 valuation signals
|
||||
- top downside risks
|
||||
|
||||
For full report mode, include full multi-year trend tables and peer comparison.
|
||||
@@ -1,99 +0,0 @@
|
||||
# Metrics Definition
|
||||
|
||||
Use these definitions consistently across all reports.
|
||||
|
||||
## 1. Core Error Metrics
|
||||
|
||||
Let:
|
||||
|
||||
- `pred` = predicted close for target session
|
||||
- `actual` = official actual close for that session
|
||||
|
||||
Compute:
|
||||
|
||||
- Absolute Error (AE): `|pred - actual|`
|
||||
- Absolute Percentage Error (APE): `|pred - actual| / actual * 100%`
|
||||
|
||||
## 2. Hit Criteria
|
||||
|
||||
Report two hit criteria in parallel:
|
||||
|
||||
- Strict hit: `APE <= 1%`
|
||||
- Loose hit: `APE <= 2%`
|
||||
|
||||
These thresholds are the default correctness criteria for predicted close price.
|
||||
|
||||
## 3. Rolling Accuracy Windows
|
||||
|
||||
For each window `W` (1d, 3d, 7d, 30d, custom):
|
||||
|
||||
- `strict_accuracy_W = strict_hits_W / n_W`
|
||||
- `loose_accuracy_W = loose_hits_W / n_W`
|
||||
|
||||
Where `n_W` is number of valid forecast/actual pairs in that window.
|
||||
|
||||
## 4. Optional Direction Accuracy
|
||||
|
||||
Let direction be sign of close-to-close return.
|
||||
|
||||
- Direction hit if predicted direction equals realized direction.
|
||||
- `direction_accuracy_W = direction_hits_W / n_W`
|
||||
|
||||
Use only when direction labels are explicitly available.
|
||||
|
||||
## 5. Forecast Correctness Score (Optional)
|
||||
|
||||
For a single forecast, you may map APE to a score:
|
||||
|
||||
- `correctness_score = max(0, 100 - 50 * APE_percent)`
|
||||
|
||||
Examples:
|
||||
|
||||
- `APE = 0.8%` -> score `60`
|
||||
- `APE = 1.5%` -> score `25`
|
||||
- `APE >= 2.0%` -> score `0` (or near 0)
|
||||
|
||||
## 6. Sample Size and Insufficient Data Rules
|
||||
|
||||
1. Never pad missing samples.
|
||||
2. If `n_W = 0`, output `N/A` for the window.
|
||||
3. If `0 < n_W < target_window_size`, output partial result and annotate as partial.
|
||||
4. Always display `n_W` beside each window metric.
|
||||
|
||||
## 7. Adjustment and Comparability Rules
|
||||
|
||||
1. Prefer adjusted price series when corporate actions materially affect comparability.
|
||||
2. If non-adjusted close is used, state it explicitly.
|
||||
3. Keep forecast and actual on the same price basis.
|
||||
|
||||
## 8. Improvement Trend Metrics
|
||||
|
||||
Track whether forecast quality is improving over time:
|
||||
|
||||
1. `delta_APE_7d_vs_prev7d`
|
||||
- Difference between current 7-day average APE and previous 7-day average APE.
|
||||
|
||||
2. `delta_strict_hit_rate_7d`
|
||||
- Change in strict hit rate versus previous 7-day block.
|
||||
|
||||
3. `trend_label`
|
||||
- `improving`, `stable`, or `degrading` based on combined delta signals.
|
||||
|
||||
## 9. Reporting Format (Minimum)
|
||||
|
||||
Every report should include:
|
||||
|
||||
1. Prior-session review row:
|
||||
- `prev_pred_close_t1`, `prev_actual_close_t1`, `AE`, `APE`, strict/loose hit status
|
||||
|
||||
2. Rolling table with at least:
|
||||
- 1d, 3d, 7d, 30d, optional custom
|
||||
- strict accuracy, loose accuracy, optional direction accuracy
|
||||
- sample size `n`
|
||||
|
||||
3. One-line interpretation:
|
||||
- whether model performance is improving, stable, or degrading
|
||||
|
||||
4. Improvement block:
|
||||
- what changed from review
|
||||
- what will be adjusted in next run
|
||||
@@ -1,33 +0,0 @@
|
||||
# Minimal Compatibility Mode
|
||||
|
||||
Use this mode when Python scripts are unavailable or model capability is limited.
|
||||
|
||||
## Goal
|
||||
|
||||
Maximize success rate and correctness with minimal token and logic complexity.
|
||||
|
||||
## Rules
|
||||
|
||||
1. Read at most 3 recent reports for the same ticker.
|
||||
2. Use minimal sources:
|
||||
- one official disclosure source
|
||||
- one reliable market data source (Yahoo Finance acceptable)
|
||||
3. Keep output short and deterministic.
|
||||
4. Still include one self-improvement action from prior misses.
|
||||
|
||||
## Minimal Output Schema
|
||||
|
||||
- `recommendation`: Buy/Hold/Sell/Watch
|
||||
- `pred_close_t1`: point estimate
|
||||
- `prev_pred_close_t1`: if available, else `N/A`
|
||||
- `prev_actual_close_t1`: if available, else `N/A/pending`
|
||||
- `AE`, `APE`: if available, else `N/A`
|
||||
- `improvement_actions`: exactly 1 item
|
||||
- `status`: `ok|pending_data|blocked`
|
||||
|
||||
## Minimal Source Checklist
|
||||
|
||||
1. Official disclosure page (exchange/regulator/IR)
|
||||
2. Market quote page (for example Yahoo Finance quote)
|
||||
|
||||
If the two sources conflict on critical values, set confidence to `Low`.
|
||||
@@ -1,99 +0,0 @@
|
||||
# Report Template (Strict)
|
||||
|
||||
Use this template exactly. Keep key names unchanged for downstream parsing.
|
||||
|
||||
```markdown
|
||||
---
|
||||
version: 1
|
||||
run_date: <YYYY-MM-DD>
|
||||
run_time_local: <YYYY-MM-DD HH:mm TZ>
|
||||
mode: <daily|daily_minimal|full_report>
|
||||
ticker: <TICKER>
|
||||
exchange: <EXCHANGE>
|
||||
market: <TEXT>
|
||||
report_dir: <working_directory>/daily-stock-analysis/reports/
|
||||
output_file: <YYYY-MM-DD-TICKER-analysis.md or -vN.md>
|
||||
report_versioning_mode: <overwrite|new_version>
|
||||
history_window_days: <N>
|
||||
|
||||
recommendation: <Buy|Hold|Sell|Watch>
|
||||
recommendation_triggers: <ENTRY/EXIT/INVALIDATION SUMMARY>
|
||||
|
||||
pred_close_t1: <NUMBER>
|
||||
pred_range_t1: <LOW-HIGH or N/A>
|
||||
pred_confidence: <High|Medium|Low>
|
||||
pred_assumptions: <SHORT TEXT>
|
||||
|
||||
prev_pred_close_t1: <NUMBER or N/A>
|
||||
prev_actual_close_t1: <NUMBER or pending or N/A>
|
||||
AE: <NUMBER or N/A>
|
||||
APE: <PERCENT or N/A>
|
||||
strict_hit: <true|false|N/A>
|
||||
loose_hit: <true|false|N/A>
|
||||
|
||||
acc_1d_strict: <PERCENT or N/A>
|
||||
acc_1d_loose: <PERCENT or N/A>
|
||||
acc_3d_strict: <PERCENT or N/A>
|
||||
acc_3d_loose: <PERCENT or N/A>
|
||||
acc_7d_strict: <PERCENT or N/A>
|
||||
acc_7d_loose: <PERCENT or N/A>
|
||||
acc_30d_strict: <PERCENT or N/A>
|
||||
acc_30d_loose: <PERCENT or N/A>
|
||||
acc_custom_strict: <PERCENT or N/A>
|
||||
acc_custom_loose: <PERCENT or N/A>
|
||||
|
||||
improvement_actions:
|
||||
- <ACTION_1>
|
||||
- <ACTION_2 or N/A>
|
||||
- <ACTION_3 or N/A>
|
||||
status: <ok|pending_data|blocked>
|
||||
status_note: <SHORT TEXT>
|
||||
---
|
||||
|
||||
# Daily Stock Analysis - <TICKER> (<EXCHANGE>)
|
||||
|
||||
## 1) Market Snapshot
|
||||
- Last/Close: <VALUE>
|
||||
- Session Range: <LOW-HIGH>
|
||||
- Volume/Volatility: <SUMMARY>
|
||||
- Thesis: <BULLISH/NEUTRAL/BEARISH + concise rationale>
|
||||
|
||||
## 2) Recommendation
|
||||
- Recommendation: <Buy/Hold/Sell/Watch>
|
||||
- Trigger Conditions: <ENTRY/EXIT/INVALIDATION>
|
||||
- Risk Controls: <SHORT TEXT>
|
||||
|
||||
## 3) Next Trading Day Prediction
|
||||
- Point Forecast: <pred_close_t1>
|
||||
- Range: <pred_range_t1>
|
||||
- Confidence: <pred_confidence>
|
||||
- Assumptions: <pred_assumptions>
|
||||
|
||||
## 4) Prior Forecast Review
|
||||
- Previous Forecast: <prev_pred_close_t1>
|
||||
- Actual Close: <prev_actual_close_t1>
|
||||
- AE / APE: <AE> / <APE>
|
||||
- Attribution: <WHY HIT OR MISS>
|
||||
|
||||
## 5) Rolling Accuracy
|
||||
| Window | Strict | Loose |
|
||||
|---|---:|---:|
|
||||
| 1d | <acc_1d_strict> | <acc_1d_loose> |
|
||||
| 3d | <acc_3d_strict> | <acc_3d_loose> |
|
||||
| 7d | <acc_7d_strict> | <acc_7d_loose> |
|
||||
| 30d | <acc_30d_strict> | <acc_30d_loose> |
|
||||
| Custom | <acc_custom_strict> | <acc_custom_loose> |
|
||||
|
||||
## 6) Self-Improvement Actions for Next Run
|
||||
1. <ACTION_1>
|
||||
2. <ACTION_2 or N/A>
|
||||
3. <ACTION_3 or N/A>
|
||||
|
||||
## 7) Sources (with timestamp)
|
||||
- <SOURCE_1>
|
||||
- <SOURCE_2>
|
||||
- <SOURCE_3>
|
||||
|
||||
## 8) Disclaimer
|
||||
This content is for research and informational purposes only and does not constitute investment advice or a return guarantee. Markets are risky; invest with caution.
|
||||
```
|
||||
@@ -1,48 +0,0 @@
|
||||
# Search Query Templates (Concise)
|
||||
|
||||
Use these templates with search engines and `site:` filters.
|
||||
|
||||
Detailed source list is in `references/sources.md`.
|
||||
|
||||
## 1) Identity and Listing
|
||||
|
||||
- `<COMPANY> ticker symbol exchange`
|
||||
- `<TICKER> exchange listing market`
|
||||
|
||||
## 2) Official Filings and Disclosures
|
||||
|
||||
- `<TICKER> official filings latest`
|
||||
- `<COMPANY> investor relations latest release`
|
||||
- `site:sec.gov <TICKER> 10-Q OR 10-K OR 8-K`
|
||||
- `site:hkexnews.hk <TICKER> announcement`
|
||||
- `site:sse.com.cn <TICKER> 公告`
|
||||
- `site:szse.cn <TICKER> 公告`
|
||||
|
||||
## 3) Market Data and Price Context
|
||||
|
||||
- `site:finance.yahoo.com <TICKER> quote`
|
||||
- `<TICKER> latest close open high low volume`
|
||||
- `<TICKER> 52 week range market cap`
|
||||
|
||||
## 4) News and Analyst Context
|
||||
|
||||
- `site:reuters.com <TICKER> earnings guidance`
|
||||
- `site:bloomberg.com <TICKER> stock news`
|
||||
- `<TICKER> analyst rating target price`
|
||||
|
||||
## 5) Technical Context
|
||||
|
||||
- `<TICKER> RSI MACD moving average`
|
||||
- `<TICKER> support resistance trend`
|
||||
|
||||
## 6) Macro Context (if used in thesis)
|
||||
|
||||
- `<MARKET> benchmark index today`
|
||||
- `<MARKET> central bank policy rate outlook`
|
||||
- `US 10Y yield today`
|
||||
|
||||
## Data Quality Rules
|
||||
|
||||
1. Prefer Tier-1 official sources first.
|
||||
2. Cross-check critical values with two independent sources.
|
||||
3. Record source URL and timestamp in report.
|
||||
@@ -1,27 +0,0 @@
|
||||
# Security and Privacy Rules
|
||||
|
||||
These rules are mandatory for both script mode and compatibility mode.
|
||||
|
||||
## Scope Control
|
||||
|
||||
1. Operate only under `working_directory`.
|
||||
2. Do not read, move, or write files outside `working_directory`.
|
||||
3. Do not follow symlinks when scanning report files.
|
||||
|
||||
## Data Minimization
|
||||
|
||||
1. Read only report files matching:
|
||||
- `YYYY-MM-DD-<TICKER>-analysis.md`
|
||||
- `YYYY-MM-DD-<TICKER>-analysis-vN.md`
|
||||
2. Parse only required metadata fields.
|
||||
3. Cap historical reads:
|
||||
- script mode default: 5 files
|
||||
- compatibility mode: 3 files
|
||||
|
||||
## Script Safety
|
||||
|
||||
1. Scripts are local-file utilities only; no network calls.
|
||||
2. Migration is explicit and non-destructive:
|
||||
- move only user-confirmed files
|
||||
- skip when target already exists
|
||||
3. If a safety check fails, return `blocked` with reason.
|
||||
@@ -1,104 +0,0 @@
|
||||
# Authoritative Information Sources
|
||||
|
||||
Use search engines with `site:` filters to prioritize authoritative sources.
|
||||
|
||||
## Source Priority
|
||||
|
||||
1. Tier 1 (Primary / official)
|
||||
- Exchange and regulator disclosures
|
||||
- Company investor-relations pages
|
||||
- Official macro data publishers
|
||||
|
||||
2. Tier 2 (High-quality financial media/data)
|
||||
- Yahoo Finance, Reuters, Bloomberg, WSJ, CNBC, MarketWatch
|
||||
|
||||
3. Tier 3 (Supporting context)
|
||||
- TradingView, StockCharts, sector/ETF summaries
|
||||
|
||||
For critical values (close price, earnings, guidance, major filings), cross-check with at least two independent sources.
|
||||
|
||||
## Tier 1: Exchange and Regulatory Sources
|
||||
|
||||
### Global baseline
|
||||
- Company Investor Relations pages
|
||||
- Official exchange announcements for the ticker listing venue
|
||||
|
||||
### United States
|
||||
- SEC EDGAR: [https://www.sec.gov/edgar/searchedgar/companysearch](https://www.sec.gov/edgar/searchedgar/companysearch)
|
||||
- Nasdaq company pages: [https://www.nasdaq.com](https://www.nasdaq.com)
|
||||
- NYSE company pages: [https://www.nyse.com](https://www.nyse.com)
|
||||
|
||||
### Hong Kong
|
||||
- HKEXnews: [https://www.hkexnews.hk](https://www.hkexnews.hk)
|
||||
|
||||
### Mainland China
|
||||
- SSE disclosures: [https://www.sse.com.cn/disclosure/](https://www.sse.com.cn/disclosure/)
|
||||
- SZSE disclosures: [https://www.szse.cn/disclosure/](https://www.szse.cn/disclosure/)
|
||||
|
||||
### Japan
|
||||
- JPX: [https://www.jpx.co.jp/english/](https://www.jpx.co.jp/english/)
|
||||
- TDnet (Timely Disclosure): [https://www.release.tdnet.info/](https://www.release.tdnet.info/)
|
||||
|
||||
### United Kingdom
|
||||
- London Stock Exchange RNS: [https://www.londonstockexchange.com/news](https://www.londonstockexchange.com/news)
|
||||
|
||||
### Europe (multi-country)
|
||||
- Euronext news/disclosures: [https://live.euronext.com/en/markets](https://live.euronext.com/en/markets)
|
||||
|
||||
## Tier 2: High-Quality Financial Data and News
|
||||
|
||||
- Yahoo Finance: [https://finance.yahoo.com](https://finance.yahoo.com)
|
||||
- Reuters Markets: [https://www.reuters.com/markets/](https://www.reuters.com/markets/)
|
||||
- Bloomberg Markets: [https://www.bloomberg.com/markets](https://www.bloomberg.com/markets)
|
||||
- WSJ Markets: [https://www.wsj.com/market-data](https://www.wsj.com/market-data)
|
||||
- CNBC Markets: [https://www.cnbc.com/markets/](https://www.cnbc.com/markets/)
|
||||
- MarketWatch: [https://www.marketwatch.com](https://www.marketwatch.com)
|
||||
- Morningstar (supporting valuation context): [https://www.morningstar.com](https://www.morningstar.com)
|
||||
|
||||
## Tier 1 Macro Data (for market regime context)
|
||||
|
||||
### United States
|
||||
- U.S. Treasury rates: [https://home.treasury.gov](https://home.treasury.gov)
|
||||
- Federal Reserve (FRED): [https://fred.stlouisfed.org](https://fred.stlouisfed.org)
|
||||
- BLS: [https://www.bls.gov](https://www.bls.gov)
|
||||
- BEA: [https://www.bea.gov](https://www.bea.gov)
|
||||
|
||||
### Global
|
||||
- IMF Data: [https://www.imf.org/en/Data](https://www.imf.org/en/Data)
|
||||
- World Bank Data: [https://data.worldbank.org](https://data.worldbank.org)
|
||||
- ECB: [https://www.ecb.europa.eu](https://www.ecb.europa.eu)
|
||||
- BoE: [https://www.bankofengland.co.uk](https://www.bankofengland.co.uk)
|
||||
- BoJ: [https://www.boj.or.jp/en/](https://www.boj.or.jp/en/)
|
||||
|
||||
## Technical/Charting Support (Tier 3)
|
||||
|
||||
- TradingView: [https://www.tradingview.com](https://www.tradingview.com)
|
||||
- StockCharts: [https://stockcharts.com](https://stockcharts.com)
|
||||
|
||||
## Search Engine Patterns
|
||||
|
||||
Use search engines with domain filters:
|
||||
|
||||
- `site:finance.yahoo.com <TICKER> quote`
|
||||
- `site:reuters.com <TICKER> earnings`
|
||||
- `site:sec.gov <TICKER> 10-Q`
|
||||
- `site:hkexnews.hk <TICKER> announcement`
|
||||
- `site:sse.com.cn <TICKER> 公告`
|
||||
- `site:szse.cn <TICKER> 公告`
|
||||
- `site:investor.<company-domain> earnings release`
|
||||
|
||||
## Minimum Source Set Per Run
|
||||
|
||||
At least include:
|
||||
|
||||
1. One Tier-1 disclosure source
|
||||
2. One Tier-2 market data source (Yahoo Finance is acceptable baseline)
|
||||
3. One Tier-2/Tier-1 news source
|
||||
4. One macro source if macro is cited in thesis
|
||||
|
||||
## Compatibility Mode Minimum Source Set
|
||||
|
||||
When running in minimal compatibility mode, use:
|
||||
|
||||
1. One Tier-1 disclosure source
|
||||
2. One Tier-2 market data source (Yahoo Finance acceptable)
|
||||
@@ -1,77 +0,0 @@
|
||||
# Technical Analysis Reference
|
||||
|
||||
Use technical analysis as a decision support layer, not as a standalone certainty signal.
|
||||
|
||||
## 1. Trend Framework
|
||||
|
||||
1. Moving averages:
|
||||
- 20/50/200-period moving averages as baseline trend map.
|
||||
- Bullish regime: price above key moving averages with supportive slope.
|
||||
- Bearish regime: price below key moving averages with negative slope.
|
||||
|
||||
2. Trend strength:
|
||||
- Confirm with higher highs/higher lows (uptrend) or lower highs/lower lows (downtrend).
|
||||
|
||||
## 2. Momentum Framework
|
||||
|
||||
1. RSI:
|
||||
- Overbought > 70, oversold < 30.
|
||||
- Use divergence vs price as an early warning, not a standalone trigger.
|
||||
|
||||
2. MACD:
|
||||
- Track line/signal crossovers and histogram trend.
|
||||
- Prefer signals aligned with broader trend.
|
||||
|
||||
## 3. Volatility and Structure
|
||||
|
||||
1. ATR context:
|
||||
- Use ATR expansion/contraction to assess regime change risk.
|
||||
|
||||
2. Bollinger context:
|
||||
- Squeeze can precede expansion.
|
||||
- Band walk can persist in strong trends.
|
||||
|
||||
## 4. Support and Resistance
|
||||
|
||||
Map levels from:
|
||||
|
||||
- Recent swing highs/lows
|
||||
- Volume clusters
|
||||
- Moving-average confluence
|
||||
- Psychological round numbers
|
||||
|
||||
Use level breaks with volume confirmation where possible.
|
||||
|
||||
## 5. Volume Confirmation
|
||||
|
||||
1. Breakout quality improves with volume expansion.
|
||||
2. Weak volume breakouts carry higher failure risk.
|
||||
3. Divergence between price trend and volume trend can signal exhaustion.
|
||||
|
||||
## 6. Multi-Timeframe Alignment
|
||||
|
||||
1. Use higher timeframe (weekly/daily) for primary bias.
|
||||
2. Use lower timeframe (daily/intraday where available) for timing.
|
||||
3. Do not let lower timeframe noise override higher timeframe structure without strong evidence.
|
||||
|
||||
## 7. Signal Quality Rules
|
||||
|
||||
1. Require at least two independent confirmations before strong directional calls.
|
||||
2. Mark low-confidence calls when indicators conflict.
|
||||
3. Define invalidation level for every directional view.
|
||||
|
||||
## 8. Market-Specific Notes (US/CN/HK)
|
||||
|
||||
1. Liquidity and session structure differ by market.
|
||||
2. Gap behavior and close auction effects may vary.
|
||||
3. Technical indicator reliability can degrade during event-driven sessions.
|
||||
|
||||
## 9. Daily Output Guidance
|
||||
|
||||
At minimum provide:
|
||||
|
||||
- Trend state (bullish/neutral/bearish)
|
||||
- 2-3 key levels
|
||||
- RSI/MACD summary
|
||||
- volume confirmation status
|
||||
- invalidation condition
|
||||
@@ -1,104 +0,0 @@
|
||||
# Workflow (Command-First)
|
||||
|
||||
Use this sequence exactly.
|
||||
|
||||
## 0) Choose Execution Mode
|
||||
|
||||
Use `script` mode by default.
|
||||
|
||||
Switch to `compatibility` mode when:
|
||||
|
||||
- `python3` is unavailable, or
|
||||
- model capability is low and deterministic minimal output is preferred.
|
||||
|
||||
## 1) Resolve Instrument
|
||||
|
||||
- Resolve `ticker`, `exchange`, `market`, and next valid trading day.
|
||||
- If ticker is ambiguous, stop and ask user.
|
||||
|
||||
## 2) Plan Files and History
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/report_manager.py plan \
|
||||
--workdir <working_directory> \
|
||||
--ticker <TICKER> \
|
||||
--run-date <YYYY-MM-DD> \
|
||||
--versioning auto \
|
||||
--history-limit 5
|
||||
```
|
||||
|
||||
Use returned JSON fields:
|
||||
|
||||
- `selected_output_file`
|
||||
- `requires_user_choice`
|
||||
- `history_files`
|
||||
- `legacy_files`
|
||||
|
||||
If `requires_user_choice=true`, ask user `overwrite` vs `new_version`.
|
||||
Read only `history_files` returned by script (default max 5).
|
||||
|
||||
## 3) Legacy Compatibility (Optional Migration)
|
||||
|
||||
- Read legacy files from `legacy_files` for review history.
|
||||
- If user agrees to migrate, run:
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/report_manager.py migrate \
|
||||
--workdir <working_directory> \
|
||||
--file <ABS_PATH_1> --file <ABS_PATH_2>
|
||||
```
|
||||
|
||||
Security: only process files under `working_directory`.
|
||||
|
||||
## 4) Collect New Data
|
||||
|
||||
- Use `references/sources.md` tier priority.
|
||||
- Use `references/search_queries.md` templates.
|
||||
- For critical values, cross-check with at least 2 sources.
|
||||
|
||||
## 5) Compute Accuracy via Script
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/calc_accuracy.py \
|
||||
--workdir <working_directory> \
|
||||
--ticker <TICKER> \
|
||||
--windows 1,3,7,30 \
|
||||
--history-limit 60
|
||||
```
|
||||
|
||||
Use script output to fill rolling accuracy fields.
|
||||
|
||||
## 6) Generate Report
|
||||
|
||||
- Render with `references/report_template.md`.
|
||||
- Keep all required frontmatter keys.
|
||||
- Include `improvement_actions`.
|
||||
|
||||
## 7) Persist and Return
|
||||
|
||||
- Save to `selected_output_file` from step 2.
|
||||
- Return summary + absolute file path + pending/blocked status.
|
||||
|
||||
## 8) Recommended Operation
|
||||
|
||||
Use recurring weekday schedule to stabilize review windows and success rate.
|
||||
|
||||
## Compatibility Mode (Fallback)
|
||||
|
||||
When scripts cannot run:
|
||||
|
||||
1. Manually locate report files only under `working_directory`.
|
||||
2. Read at most 3 recent same-ticker reports.
|
||||
3. Collect minimal sources:
|
||||
- one official disclosure source
|
||||
- one reliable market data source
|
||||
4. Produce minimal output:
|
||||
- recommendation
|
||||
- `pred_close_t1`
|
||||
- prior review metrics (if available)
|
||||
- one `improvement_action`
|
||||
5. Save report in canonical reports directory using standard filename rules.
|
||||
@@ -1,162 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Shared helpers for daily-stock-analysis scripts."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from datetime import date
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
|
||||
FILENAME_RE = re.compile(
|
||||
r"^(?P<run_date>\d{4}-\d{2}-\d{2})-(?P<ticker>[A-Za-z0-9._-]+)-analysis(?:-v(?P<version>\d+))?\.md$",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ReportFile:
|
||||
path: str
|
||||
run_date: str
|
||||
ticker: str
|
||||
version: int
|
||||
in_canonical_dir: bool
|
||||
|
||||
|
||||
def canonical_reports_dir(workdir: str) -> str:
|
||||
return os.path.join(os.path.abspath(workdir), "daily-stock-analysis", "reports")
|
||||
|
||||
|
||||
def compatible_dirs(workdir: str) -> List[str]:
|
||||
root = os.path.abspath(workdir)
|
||||
return [
|
||||
canonical_reports_dir(root),
|
||||
os.path.join(root, "daily-stock-analysis"),
|
||||
root,
|
||||
]
|
||||
|
||||
|
||||
def is_within_workdir(path: str, workdir: str) -> bool:
|
||||
root = os.path.realpath(os.path.abspath(workdir))
|
||||
target = os.path.realpath(os.path.abspath(path))
|
||||
return target == root or target.startswith(root + os.sep)
|
||||
|
||||
|
||||
def parse_filename(name: str) -> Optional[Dict[str, str]]:
|
||||
match = FILENAME_RE.match(name)
|
||||
if not match:
|
||||
return None
|
||||
return {
|
||||
"run_date": match.group("run_date"),
|
||||
"ticker": match.group("ticker").upper(),
|
||||
"version": str(int(match.group("version") or "1")),
|
||||
}
|
||||
|
||||
|
||||
def discover_reports(workdir: str, ticker: str) -> List[ReportFile]:
|
||||
root = os.path.abspath(workdir)
|
||||
ticker_upper = ticker.upper()
|
||||
canonical_dir = canonical_reports_dir(root)
|
||||
seen = set()
|
||||
records: List[ReportFile] = []
|
||||
|
||||
for directory in compatible_dirs(root):
|
||||
if not is_within_workdir(directory, root):
|
||||
continue
|
||||
if not os.path.isdir(directory):
|
||||
continue
|
||||
for entry in os.scandir(directory):
|
||||
# Never follow symlinks for safety/privacy.
|
||||
if not entry.is_file(follow_symlinks=False):
|
||||
continue
|
||||
parsed = parse_filename(entry.name)
|
||||
if not parsed:
|
||||
continue
|
||||
if parsed["ticker"] != ticker_upper:
|
||||
continue
|
||||
abs_path = os.path.abspath(entry.path)
|
||||
real_path = os.path.realpath(abs_path)
|
||||
if real_path in seen:
|
||||
continue
|
||||
seen.add(real_path)
|
||||
records.append(
|
||||
ReportFile(
|
||||
path=abs_path,
|
||||
run_date=parsed["run_date"],
|
||||
ticker=parsed["ticker"],
|
||||
version=int(parsed["version"]),
|
||||
in_canonical_dir=os.path.dirname(abs_path) == canonical_dir,
|
||||
)
|
||||
)
|
||||
|
||||
def sort_key(record: ReportFile):
|
||||
try:
|
||||
d = date.fromisoformat(record.run_date)
|
||||
except ValueError:
|
||||
d = date.min
|
||||
return (d, record.version, 1 if record.in_canonical_dir else 0)
|
||||
|
||||
return sorted(records, key=sort_key, reverse=True)
|
||||
|
||||
|
||||
def read_frontmatter(path: str) -> Dict[str, str]:
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
first_line = f.readline()
|
||||
if first_line.strip() != "---":
|
||||
return {}
|
||||
|
||||
# Read only a bounded header section to avoid loading large files.
|
||||
frontmatter: Dict[str, str] = {}
|
||||
total_chars = len(first_line)
|
||||
for _ in range(200):
|
||||
line = f.readline()
|
||||
if not line:
|
||||
break
|
||||
total_chars += len(line)
|
||||
if total_chars > 64 * 1024:
|
||||
break
|
||||
raw = line.rstrip("\n")
|
||||
if raw.strip() == "---":
|
||||
break
|
||||
if not raw.strip():
|
||||
continue
|
||||
if raw.startswith(" - "):
|
||||
continue
|
||||
if ":" not in raw:
|
||||
continue
|
||||
key, value = raw.split(":", 1)
|
||||
frontmatter[key.strip()] = value.strip()
|
||||
return frontmatter
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return {}
|
||||
|
||||
|
||||
def parse_float(value: Optional[str]) -> Optional[float]:
|
||||
if value is None:
|
||||
return None
|
||||
text = value.strip()
|
||||
if not text:
|
||||
return None
|
||||
if text.upper() in {"N/A", "NA", "NONE", "NULL", "PENDING"}:
|
||||
return None
|
||||
text = text.replace(",", "")
|
||||
if text.endswith("%"):
|
||||
text = text[:-1]
|
||||
try:
|
||||
return float(text)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def parse_bool(value: Optional[str]) -> Optional[bool]:
|
||||
if value is None:
|
||||
return None
|
||||
text = value.strip().lower()
|
||||
if text in {"true", "yes", "1"}:
|
||||
return True
|
||||
if text in {"false", "no", "0"}:
|
||||
return False
|
||||
return None
|
||||
@@ -1,122 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compute rolling forecast accuracy from existing report files."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from statistics import mean
|
||||
from typing import Dict, List
|
||||
|
||||
from _report_utils import discover_reports, parse_bool, parse_float, read_frontmatter
|
||||
|
||||
|
||||
def _window_list(text: str) -> List[int]:
|
||||
windows = []
|
||||
for item in text.split(","):
|
||||
item = item.strip()
|
||||
if not item:
|
||||
continue
|
||||
value = int(item)
|
||||
if value <= 0:
|
||||
continue
|
||||
if value not in windows:
|
||||
windows.append(value)
|
||||
return windows or [1, 3, 7, 30]
|
||||
|
||||
|
||||
def _build_review_rows(workdir: str, ticker: str, history_limit: int) -> List[Dict[str, object]]:
|
||||
reports = discover_reports(workdir, ticker)[:history_limit]
|
||||
rows: List[Dict[str, object]] = []
|
||||
seen_run_date = set()
|
||||
|
||||
for report in reports:
|
||||
# Keep the newest report for each run_date to avoid same-day duplicate counting.
|
||||
if report.run_date in seen_run_date:
|
||||
continue
|
||||
frontmatter = read_frontmatter(report.path)
|
||||
ape = parse_float(frontmatter.get("APE"))
|
||||
strict = parse_bool(frontmatter.get("strict_hit"))
|
||||
loose = parse_bool(frontmatter.get("loose_hit"))
|
||||
|
||||
if strict is None and ape is not None:
|
||||
strict = ape <= 1.0
|
||||
if loose is None and ape is not None:
|
||||
loose = ape <= 2.0
|
||||
|
||||
if ape is None and strict is None and loose is None:
|
||||
continue
|
||||
|
||||
rows.append(
|
||||
{
|
||||
"run_date": report.run_date,
|
||||
"path": report.path,
|
||||
"ape": ape,
|
||||
"strict_hit": strict,
|
||||
"loose_hit": loose,
|
||||
}
|
||||
)
|
||||
seen_run_date.add(report.run_date)
|
||||
|
||||
return rows
|
||||
|
||||
|
||||
def _rate(hit_count: int, total: int):
|
||||
if total == 0:
|
||||
return None
|
||||
return round(hit_count * 100.0 / total, 2)
|
||||
|
||||
|
||||
def compute_accuracy(workdir: str, ticker: str, windows: List[int], history_limit: int) -> Dict[str, object]:
|
||||
rows = _build_review_rows(workdir, ticker, history_limit)
|
||||
metrics = {}
|
||||
|
||||
for window in windows:
|
||||
sample = rows[:window]
|
||||
n = len(sample)
|
||||
strict_hits = sum(1 for r in sample if r["strict_hit"] is True)
|
||||
loose_hits = sum(1 for r in sample if r["loose_hit"] is True)
|
||||
ape_values = [r["ape"] for r in sample if isinstance(r["ape"], float)]
|
||||
metrics[str(window)] = {
|
||||
"n": n,
|
||||
"strict_rate_percent": _rate(strict_hits, n),
|
||||
"loose_rate_percent": _rate(loose_hits, n),
|
||||
"avg_ape_percent": round(mean(ape_values), 4) if ape_values else None,
|
||||
}
|
||||
|
||||
latest = rows[0] if rows else None
|
||||
return {
|
||||
"ticker": ticker.upper(),
|
||||
"workdir": os.path.abspath(workdir),
|
||||
"windows": metrics,
|
||||
"review_samples": len(rows),
|
||||
"latest_review": latest,
|
||||
"status": "ok" if rows else "insufficient_history",
|
||||
"security_scope": "working_directory_only",
|
||||
}
|
||||
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Calculate rolling forecast accuracy.")
|
||||
parser.add_argument("--workdir", default=os.getcwd())
|
||||
parser.add_argument("--ticker", required=True)
|
||||
parser.add_argument("--windows", default="1,3,7,30")
|
||||
parser.add_argument("--history-limit", type=int, default=60)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = _parse_args()
|
||||
result = compute_accuracy(
|
||||
workdir=args.workdir,
|
||||
ticker=args.ticker,
|
||||
windows=_window_list(args.windows),
|
||||
history_limit=max(args.history_limit, 1),
|
||||
)
|
||||
print(json.dumps(result, indent=2, ensure_ascii=True))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,189 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Deterministic report path and migration manager for daily-stock-analysis."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from datetime import date
|
||||
from typing import Dict, List
|
||||
|
||||
from _report_utils import (
|
||||
FILENAME_RE,
|
||||
canonical_reports_dir,
|
||||
discover_reports,
|
||||
is_within_workdir,
|
||||
)
|
||||
|
||||
|
||||
def _same_day_versions_in_canonical(
|
||||
reports: List, reports_dir: str, run_date: str, ticker_upper: str
|
||||
) -> List[int]:
|
||||
versions = []
|
||||
for report in reports:
|
||||
if report.run_date != run_date:
|
||||
continue
|
||||
if report.ticker != ticker_upper:
|
||||
continue
|
||||
if os.path.dirname(report.path) != reports_dir:
|
||||
continue
|
||||
versions.append(report.version)
|
||||
return versions
|
||||
|
||||
|
||||
def plan_output(
|
||||
workdir: str,
|
||||
ticker: str,
|
||||
run_date: str,
|
||||
versioning: str,
|
||||
unattended: bool,
|
||||
history_limit: int,
|
||||
) -> Dict[str, object]:
|
||||
root = os.path.abspath(workdir)
|
||||
ticker_upper = ticker.upper()
|
||||
reports_dir = canonical_reports_dir(root)
|
||||
os.makedirs(reports_dir, exist_ok=True)
|
||||
|
||||
reports = discover_reports(root, ticker_upper)
|
||||
history_files = [r.path for r in reports[:history_limit]]
|
||||
legacy_files = [r.path for r in reports if not r.in_canonical_dir]
|
||||
|
||||
base_name = f"{run_date}-{ticker_upper}-analysis.md"
|
||||
base_path = os.path.join(reports_dir, base_name)
|
||||
base_exists = os.path.exists(base_path)
|
||||
|
||||
requires_user_choice = False
|
||||
selected_mode = "new_file"
|
||||
selected_path = base_path
|
||||
|
||||
if base_exists:
|
||||
if versioning == "overwrite":
|
||||
selected_mode = "overwrite"
|
||||
elif versioning == "new_version":
|
||||
selected_mode = "new_version"
|
||||
else:
|
||||
if unattended:
|
||||
selected_mode = "new_version"
|
||||
else:
|
||||
selected_mode = "new_version"
|
||||
requires_user_choice = True
|
||||
|
||||
if selected_mode == "new_version":
|
||||
versions = _same_day_versions_in_canonical(
|
||||
reports, reports_dir, run_date, ticker_upper
|
||||
)
|
||||
next_version = max(versions or [1]) + 1
|
||||
selected_path = os.path.join(
|
||||
reports_dir, f"{run_date}-{ticker_upper}-analysis-v{next_version}.md"
|
||||
)
|
||||
|
||||
return {
|
||||
"ticker": ticker_upper,
|
||||
"workdir": root,
|
||||
"reports_dir": reports_dir,
|
||||
"base_output_file": base_path,
|
||||
"selected_output_file": selected_path,
|
||||
"selected_versioning_mode": selected_mode,
|
||||
"requires_user_choice": requires_user_choice,
|
||||
"history_files": history_files,
|
||||
"legacy_files": legacy_files,
|
||||
"history_limit": history_limit,
|
||||
"security_scope": "working_directory_only",
|
||||
}
|
||||
|
||||
|
||||
def migrate_files(workdir: str, files: List[str]) -> Dict[str, object]:
|
||||
root = os.path.abspath(workdir)
|
||||
reports_dir = canonical_reports_dir(root)
|
||||
os.makedirs(reports_dir, exist_ok=True)
|
||||
|
||||
moved = []
|
||||
skipped = []
|
||||
|
||||
for raw_path in files:
|
||||
src = os.path.abspath(raw_path)
|
||||
if not is_within_workdir(src, root):
|
||||
skipped.append({"file": src, "reason": "outside_workdir"})
|
||||
continue
|
||||
if not os.path.isfile(src):
|
||||
skipped.append({"file": src, "reason": "not_file"})
|
||||
continue
|
||||
if os.path.islink(src):
|
||||
skipped.append({"file": src, "reason": "symlink_not_allowed"})
|
||||
continue
|
||||
if not FILENAME_RE.match(os.path.basename(src)):
|
||||
skipped.append({"file": src, "reason": "filename_not_supported"})
|
||||
continue
|
||||
|
||||
dst = os.path.join(reports_dir, os.path.basename(src))
|
||||
if os.path.abspath(src) == os.path.abspath(dst):
|
||||
skipped.append({"file": src, "reason": "already_in_reports_dir"})
|
||||
continue
|
||||
|
||||
if os.path.exists(dst):
|
||||
# Keep migration deterministic and non-destructive.
|
||||
skipped.append({"file": src, "reason": "target_exists"})
|
||||
continue
|
||||
|
||||
try:
|
||||
shutil.move(src, dst)
|
||||
except OSError as exc:
|
||||
skipped.append({"file": src, "reason": f"move_failed:{exc}"})
|
||||
continue
|
||||
|
||||
moved.append({"from": src, "to": dst})
|
||||
|
||||
return {
|
||||
"reports_dir": reports_dir,
|
||||
"moved": moved,
|
||||
"skipped": skipped,
|
||||
"security_scope": "working_directory_only",
|
||||
}
|
||||
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Manage report paths and migrations.")
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
plan_parser = subparsers.add_parser("plan", help="Plan output path and history usage.")
|
||||
plan_parser.add_argument("--workdir", default=os.getcwd())
|
||||
plan_parser.add_argument("--ticker", required=True)
|
||||
plan_parser.add_argument("--run-date", default=date.today().isoformat())
|
||||
plan_parser.add_argument(
|
||||
"--versioning",
|
||||
choices=["auto", "overwrite", "new_version"],
|
||||
default="auto",
|
||||
)
|
||||
plan_parser.add_argument("--unattended", action="store_true")
|
||||
plan_parser.add_argument("--history-limit", type=int, default=5)
|
||||
|
||||
migrate_parser = subparsers.add_parser(
|
||||
"migrate", help="Move legacy report files into canonical reports directory."
|
||||
)
|
||||
migrate_parser.add_argument("--workdir", default=os.getcwd())
|
||||
migrate_parser.add_argument("--file", action="append", required=True)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = _parse_args()
|
||||
if args.command == "plan":
|
||||
result = plan_output(
|
||||
workdir=args.workdir,
|
||||
ticker=args.ticker,
|
||||
run_date=args.run_date,
|
||||
versioning=args.versioning,
|
||||
unattended=args.unattended,
|
||||
history_limit=max(args.history_limit, 1),
|
||||
)
|
||||
else:
|
||||
result = migrate_files(workdir=args.workdir, files=args.file)
|
||||
print(json.dumps(result, indent=2, ensure_ascii=True))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "proactive-agent-lite",
|
||||
"installedVersion": "1.0.0",
|
||||
"installedAt": 1773644526594
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
# Proactive Agent Lite
|
||||
|
||||
Transform your AI agents from passive responders into proactive partners that anticipate needs and continuously improve.
|
||||
|
||||
## Overview
|
||||
|
||||
Proactive Agent Lite implements battle-tested patterns that enable AI agents to:
|
||||
- Learn from every interaction
|
||||
- Create value without being asked
|
||||
- Stay aligned with their mission
|
||||
- Self-diagnose and fix issues
|
||||
- Surface hidden opportunities
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
clawhub install proactive-agent-lite
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### 🧠 Memory Architecture
|
||||
- **Pre-compaction flush**: Ensures important context survives even when the conversation window fills up
|
||||
- **Long-term memory**: Maintains continuity across sessions
|
||||
- **Context preservation**: Never loses track of important details
|
||||
|
||||
### 💡 Reverse Prompting
|
||||
- **Idea generation**: Surfaces concepts and solutions you didn't know to ask for
|
||||
- **Opportunity discovery**: Identifies potential improvements and optimizations
|
||||
- **Proactive suggestions**: Offers relevant insights without waiting for explicit requests
|
||||
|
||||
### 🛡️ Security Hardening
|
||||
- **Safe defaults**: Conservative approach to external actions
|
||||
- **Permission awareness**: Respects boundaries and asks before acting
|
||||
- **Data protection**: Never exposes private information
|
||||
|
||||
### 🔧 Self-Healing Patterns
|
||||
- **Error detection**: Automatically identifies when something goes wrong
|
||||
- **Recovery mechanisms**: Implements strategies to get back on track
|
||||
- **Continuous improvement**: Learns from mistakes to prevent recurrence
|
||||
|
||||
### 🎯 Alignment Systems
|
||||
- **Mission focus**: Always remembers the core objective
|
||||
- **User-centric**: Prioritizes your needs and preferences
|
||||
- **Value-driven**: Makes decisions based on what creates the most value for you
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, your agent will automatically begin exhibiting proactive behavior. No additional configuration is required, though advanced users can fine-tune the behavior through configuration files.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Start conservative**: Begin with default settings and adjust as needed
|
||||
- **Monitor interactions**: Observe how the proactive behavior manifests in your use cases
|
||||
- **Provide feedback**: Help the agent learn what types of proactive suggestions are most valuable to you
|
||||
|
||||
## Integration
|
||||
|
||||
This skill works well with other OpenClaw skills and can enhance any agent workflow. Consider combining it with:
|
||||
- `evomap-heartbeat-manager` for proactive network monitoring
|
||||
- `evomap-work-processor` for proactive work opportunity handling
|
||||
- Any domain-specific skills for enhanced proactive capabilities
|
||||
|
||||
## Support
|
||||
|
||||
For questions or feature requests, contact the skill maintainer through ClawHub.
|
||||
@@ -1,49 +0,0 @@
|
||||
---
|
||||
name: proactive-agent-lite
|
||||
description: Transform AI agents from task-followers into proactive partners with memory architecture, reverse prompting, and self-healing patterns. Lightweight version focused on core proactive capabilities.
|
||||
metadata:
|
||||
{
|
||||
"openclaw":
|
||||
{
|
||||
"requires": {},
|
||||
"install": []
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
# Proactive Agent Lite
|
||||
|
||||
Transform your AI agents from passive task-followers into proactive partners that anticipate needs and continuously improve.
|
||||
|
||||
## Core Features
|
||||
|
||||
- **Memory Architecture**: Pre-compaction flush ensures context survives when window fills
|
||||
- **Reverse Prompting**: Surfaces ideas you didn't know to ask for
|
||||
- **Security Hardening**: Built-in security considerations and safe defaults
|
||||
- **Self-Healing Patterns**: Diagnoses and fixes its own issues automatically
|
||||
- **Alignment Systems**: Stays on mission and remembers who it serves
|
||||
|
||||
## Key Benefits
|
||||
|
||||
✅ **Anticipates Needs**: Proactively suggests solutions before you ask
|
||||
✅ **Continuous Learning**: Improves from every interaction without explicit training
|
||||
✅ **Mission-Focused**: Never loses sight of the core objective
|
||||
✅ **Self-Maintaining**: Automatically recovers from errors and inconsistencies
|
||||
✅ **Value Creation**: Generates insights and opportunities without being prompted
|
||||
|
||||
## Usage
|
||||
|
||||
This skill enhances any OpenClaw agent by providing proactive behavior patterns. Simply install and the agent will automatically begin exhibiting proactive characteristics.
|
||||
|
||||
## Integration
|
||||
|
||||
Works seamlessly with all OpenClaw agents and can be combined with other skills for enhanced functionality.
|
||||
|
||||
## Requirements
|
||||
|
||||
- OpenClaw v1.0 or higher
|
||||
- Standard agent configuration
|
||||
|
||||
## Customization
|
||||
|
||||
The proactive behavior can be tuned through configuration parameters to match your preferred level of initiative and communication style.
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"ownerId": "kn778z31czjyj515snpsht5ghh80hy50",
|
||||
"slug": "proactive-agent-lite",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1772250292761
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "stock-monitor-skill",
|
||||
"installedVersion": "0.1.0",
|
||||
"installedAt": 1773406340232
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
# Stock Monitor Pro
|
||||
|
||||
全功能智能股票监控预警系统
|
||||
|
||||
## 功能
|
||||
- 成本百分比预警
|
||||
- 日内涨跌幅预警
|
||||
- 成交量异动监控
|
||||
- 均线金叉死叉
|
||||
- RSI超买超卖
|
||||
- 跳空缺口检测
|
||||
- 动态止盈
|
||||
|
||||
## 快速开始
|
||||
```bash
|
||||
cd scripts
|
||||
cp config.example.py config.py
|
||||
# 编辑 config.py 填入你的持仓
|
||||
./control.sh start
|
||||
```
|
||||
|
||||
## 许可证
|
||||
MIT
|
||||
@@ -1,193 +0,0 @@
|
||||
---
|
||||
name: stock-monitor
|
||||
description: 全功能智能股票监控预警系统。支持成本百分比、均线金叉死叉、RSI超买超卖、成交量异动、跳空缺口、动态止盈等7大预警规则。符合中国投资者习惯(红涨绿跌)。
|
||||
---
|
||||
|
||||
# Stock Monitor Pro - 全功能智能投顾系统
|
||||
|
||||
## 🎯 核心特色
|
||||
|
||||
### 1. 七大预警规则 (全都要!)
|
||||
|
||||
| 规则 | 触发条件 | 权重 |
|
||||
|------|----------|------|
|
||||
| **成本百分比** | 盈利+15% / 亏损-12% | ⭐⭐⭐ |
|
||||
| **日内涨跌幅** | 个股±4% / ETF±2% / 黄金±2.5% | ⭐⭐ |
|
||||
| **成交量异动** | 放量>2倍均量 / 缩量<0.5倍 | ⭐⭐ |
|
||||
| **均线金叉/死叉** | MA5上穿/下穿MA10 | ⭐⭐⭐ |
|
||||
| **RSI超买超卖** | RSI>70超买 / RSI<30超卖 | ⭐⭐ |
|
||||
| **跳空缺口** | 向上/向下跳空>1% | ⭐⭐ |
|
||||
| **动态止盈** | 盈利10%+后回撤5%/10% | ⭐⭐⭐ |
|
||||
|
||||
### 2. 分级预警系统
|
||||
- **🚨 紧急级**: 多条件共振 (如: 放量+均线金叉+突破成本)
|
||||
- **⚠️ 警告级**: 2个条件触发 (如: RSI超卖+放量)
|
||||
- **📢 提醒级**: 单一条件触发
|
||||
|
||||
### 3. 中国习惯
|
||||
- **🔴 红色** = 上涨 / 盈利
|
||||
- **🟢 绿色** = 下跌 / 亏损
|
||||
|
||||
## 📋 监控配置
|
||||
|
||||
### 完整预警规则示例
|
||||
```python
|
||||
{
|
||||
"code": "600362",
|
||||
"name": "江西铜业",
|
||||
"type": "individual", # 个股
|
||||
"market": "sh",
|
||||
"cost": 57.00, # 持仓成本
|
||||
"alerts": {
|
||||
# 1. 成本百分比
|
||||
"cost_pct_above": 15.0, # 盈利15%提醒 (¥65.55)
|
||||
"cost_pct_below": -12.0, # 亏损12%提醒 (¥50.16)
|
||||
|
||||
# 2. 日内涨跌幅 (个股±4%)
|
||||
"change_pct_above": 4.0,
|
||||
"change_pct_below": -4.0,
|
||||
|
||||
# 3. 成交量异动
|
||||
"volume_surge": 2.0, # 放量>2倍5日均量
|
||||
|
||||
# 4-7. 技术指标 (默认开启)
|
||||
"ma_monitor": True, # 均线金叉死叉
|
||||
"rsi_monitor": True, # RSI超买超卖
|
||||
"gap_monitor": True, # 跳空缺口
|
||||
"trailing_stop": True # 动态止盈
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 标的类型差异化
|
||||
| 类型 | 日内异动阈值 | 成交量阈值 | 适用标的 |
|
||||
|------|-------------|-----------|----------|
|
||||
| individual (个股) | ±4% | 2倍 | 江西铜业、中国平安 |
|
||||
| etf (ETF) | ±2% | 1.8倍 | 恒生医疗、创50等 |
|
||||
| gold (黄金) | ±2.5% | 无 | 伦敦金 |
|
||||
|
||||
## 🚀 运行方式
|
||||
|
||||
### 后台常驻进程
|
||||
```bash
|
||||
cd ~/workspace/skills/stock-monitor/scripts
|
||||
./control.sh start # 启动
|
||||
./control.sh status # 查看状态
|
||||
./control.sh log # 查看日志
|
||||
./control.sh stop # 停止
|
||||
```
|
||||
|
||||
## ⚡ 智能频率 (北京时间)
|
||||
|
||||
| 时间段 | 频率 | 监控标的 |
|
||||
|--------|------|----------|
|
||||
| 交易时间 9:30-15:00 | 每5分钟 | 全部+技术指标 |
|
||||
| 午休 11:30-13:00 | 每10分钟 | 全部 |
|
||||
| 收盘后 15:00-24:00 | 每30分钟 | 全部 (日线数据) |
|
||||
| 凌晨 0:00-9:30 | 每1小时 | 仅伦敦金 |
|
||||
| 周末 | 每1小时 | 仅伦敦金 |
|
||||
|
||||
## 🔔 预警消息示例
|
||||
|
||||
### 多条件共振 (紧急级)
|
||||
```
|
||||
🚨【紧急】🔴 江西铜业 (600362)
|
||||
━━━━━━━━━━━━━━━━━━━━
|
||||
💰 当前价格: ¥65.50 (+15.0%)
|
||||
📊 持仓成本: ¥57.00 | 盈亏: 🔴+14.9%
|
||||
|
||||
🎯 触发预警 (3项):
|
||||
• 🎯 盈利 15% (目标价 ¥65.55)
|
||||
• 🌟 均线金叉 (MA5¥63.2上穿MA10¥62.8)
|
||||
• 📊 放量 2.5倍 (5日均量)
|
||||
|
||||
📊 江西铜业 深度分析
|
||||
💰 价格异动:
|
||||
• 当前: 65.5 (+15.0%)
|
||||
• MA趋势: MA5>MA10>MA20 [多头排列]
|
||||
• RSI: 68 [接近超买]
|
||||
|
||||
💡 Kimi建议:
|
||||
🚀 多条件共振,趋势强劲,可考虑继续持有或分批减仓。
|
||||
```
|
||||
|
||||
### RSI超卖 (警告级)
|
||||
```
|
||||
⚠️【警告】🟢 恒生医疗 (159892)
|
||||
━━━━━━━━━━━━━━━━━━━━
|
||||
💰 当前价格: ¥0.72 (-10.0%)
|
||||
📊 持仓成本: ¥0.80 | 盈亏: 🟢-10.0%
|
||||
|
||||
🎯 触发预警 (2项):
|
||||
• 📉 日内大跌 -10.0%
|
||||
• ❄️ RSI超卖 (28.5),可能反弹
|
||||
|
||||
💡 Kimi建议:
|
||||
🔍 短期超跌严重,RSI进入超卖区,关注反弹机会但勿急于抄底。
|
||||
```
|
||||
|
||||
### 动态止盈提醒
|
||||
```
|
||||
📢【提醒】🔴 中国平安 (601318)
|
||||
━━━━━━━━━━━━━━━━━━━━
|
||||
💰 当前价格: ¥70.50 (+6.8%)
|
||||
📊 持仓成本: ¥66.00 | 盈亏: 🔴+6.8%
|
||||
|
||||
🎯 触发预警:
|
||||
• 📉 利润回撤 5.2%,建议减仓保护利润
|
||||
(最高盈利12%已回撤)
|
||||
```
|
||||
|
||||
## 🛠️ 文件结构
|
||||
```
|
||||
stock-monitor/
|
||||
├── SKILL.md # 本文档
|
||||
├── RULE_REVIEW_REPORT.md # 规则审核报告
|
||||
└── scripts/
|
||||
├── monitor.py # 核心监控 (7大规则)
|
||||
├── monitor_daemon.py # 后台常驻进程
|
||||
├── analyser.py # 智能分析引擎
|
||||
└── control.sh # 一键控制脚本
|
||||
```
|
||||
|
||||
## ⚙️ 自定义配置
|
||||
|
||||
### 修改成本价
|
||||
```python
|
||||
"cost": 55.50, # 改成你的实际成本
|
||||
```
|
||||
|
||||
### 调整预警阈值
|
||||
```python
|
||||
"cost_pct_above": 20.0, # 盈利20%提醒
|
||||
"cost_pct_below": -15.0, # 亏损15%提醒
|
||||
"change_pct_above": 5.0, # 日内异动±5%
|
||||
"volume_surge": 3.0, # 放量3倍提醒
|
||||
```
|
||||
|
||||
### 开关技术指标
|
||||
```python
|
||||
"ma_monitor": False, # 关闭均线
|
||||
"rsi_monitor": True, # 开启RSI
|
||||
"gap_monitor": True, # 开启跳空
|
||||
```
|
||||
|
||||
## 📝 更新日志
|
||||
- **v3.0 全功能版**: 完成7大预警规则 (成本/涨跌幅/成交量/均线/RSI/跳空/动态止盈)
|
||||
- **v2.4 成本百分比版**: 支持基于持仓成本的百分比预警
|
||||
- **v2.3 中国版**: 红涨绿跌颜色习惯
|
||||
- **v2.2 常驻进程版**: 后台常驻进程支持
|
||||
- **v2.1 智能频率版**: 智能频率控制
|
||||
- **v2.0 Pro版**: 新闻舆情分析
|
||||
|
||||
## ⚠️ 使用提示
|
||||
|
||||
1. **技术指标有滞后性**: 均线、MACD等都是滞后指标,用于确认趋势而非预测
|
||||
2. **避免过度交易**: 预警只是参考,不要每个信号都操作
|
||||
3. **多条件共振更可靠**: 单一指标容易假信号,多条件共振更准确
|
||||
4. **动态止盈要灵活**: 回撤5%减仓、10%清仓是建议,根据市场灵活调整
|
||||
|
||||
---
|
||||
|
||||
**核心原则**:
|
||||
> 预警系统目标是"不错过大机会,不犯大错误",不是"抓住每一个波动"。
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"ownerId": "kn70aj13hr3z4fpmfk1y2jmpz181gn2z",
|
||||
"slug": "stock-monitor-skill",
|
||||
"version": "0.1.0",
|
||||
"publishedAt": 1771579954718
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,249 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Stock Monitor Pro - 智能分析引擎
|
||||
集成:新闻、资金流向、龙虎榜、宏观关联分析
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List, Dict, Optional
|
||||
|
||||
class StockAnalyser:
|
||||
"""股票智能分析器 - 结合多维度数据给出建议"""
|
||||
|
||||
def __init__(self):
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update({
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||
})
|
||||
|
||||
# ========== 1. 新闻舆情 ==========
|
||||
|
||||
def fetch_eastmoney_news(self, symbol: str, name: str, limit: int = 5) -> List[Dict]:
|
||||
"""获取东方财富个股新闻"""
|
||||
url = f"https://searchapi.eastmoney.com/api/suggest/get"
|
||||
params = {
|
||||
"input": name,
|
||||
"type": 14,
|
||||
"count": limit
|
||||
}
|
||||
try:
|
||||
resp = self.session.get(url, params=params, timeout=10)
|
||||
data = resp.json()
|
||||
news_list = []
|
||||
for item in data.get("QuotationCodeTable", {}).get("Data", []):
|
||||
news_list.append({
|
||||
"title": item.get("Title", ""),
|
||||
"url": item.get("Url", ""),
|
||||
"time": item.get("ShowTime", "")
|
||||
})
|
||||
return news_list
|
||||
except Exception as e:
|
||||
return []
|
||||
|
||||
def fetch_sina_news(self, symbol: str, name: str) -> List[Dict]:
|
||||
"""获取新浪财经个股新闻"""
|
||||
# 新浪新闻搜索接口
|
||||
url = f"https://search.sina.com.cn/?q={name}&c=news&sort=time"
|
||||
try:
|
||||
resp = self.session.get(url, timeout=10)
|
||||
# 这里可以做更精细的HTML解析
|
||||
# 简化返回示例
|
||||
return [{"title": f"新浪财经-{name}相关新闻", "source": "新浪"}]
|
||||
except:
|
||||
return []
|
||||
|
||||
def analyze_sentiment(self, news_list: List[Dict]) -> Dict:
|
||||
"""简单情感分析"""
|
||||
positive_words = ['利好', '增长', '突破', '买入', '增持', '涨停', '超预期', '业绩大增']
|
||||
negative_words = ['利空', '减持', '下跌', '卖出', '亏损', '暴雷', '跌停', '不及预期']
|
||||
|
||||
sentiment = {"positive": 0, "negative": 0, "neutral": 0, "summary": []}
|
||||
|
||||
for news in news_list:
|
||||
title = news.get("title", "")
|
||||
p_count = sum(1 for w in positive_words if w in title)
|
||||
n_count = sum(1 for w in negative_words if w in title)
|
||||
|
||||
if p_count > n_count:
|
||||
sentiment["positive"] += 1
|
||||
elif n_count > p_count:
|
||||
sentiment["negative"] += 1
|
||||
else:
|
||||
sentiment["neutral"] += 1
|
||||
|
||||
# 生成情感摘要
|
||||
if sentiment["positive"] > sentiment["negative"]:
|
||||
sentiment["overall"] = "偏多"
|
||||
elif sentiment["negative"] > sentiment["positive"]:
|
||||
sentiment["overall"] = "偏空"
|
||||
else:
|
||||
sentiment["overall"] = "中性"
|
||||
|
||||
return sentiment
|
||||
|
||||
# ========== 2. 资金流向 ==========
|
||||
|
||||
def fetch_fund_flow(self, symbol: str, market: str = "sz") -> Dict:
|
||||
"""获取个股资金流向 (新浪财经)"""
|
||||
# 新浪资金流向接口
|
||||
code = f"{market}{symbol}"
|
||||
url = f"https://quotes.sina.cn/cn/api/quotes.php?symbol={code}&source=sina"
|
||||
|
||||
try:
|
||||
resp = self.session.get(url, timeout=10)
|
||||
# 解析返回数据
|
||||
return {
|
||||
"main_inflow": "数据获取中...",
|
||||
"retail_inflow": "数据获取中...",
|
||||
"net_inflow": "数据获取中..."
|
||||
}
|
||||
except:
|
||||
return {"error": "获取失败"}
|
||||
|
||||
def fetch_northbound_flow(self) -> Dict:
|
||||
"""获取北向资金 (沪深股通) 流向"""
|
||||
url = "https://push2.eastmoney.com/api/qt/stock/get"
|
||||
params = {"secid": "1.000001", "fields": "f170"} # 简化示例
|
||||
try:
|
||||
resp = self.session.get(url, params=params, timeout=10)
|
||||
return {"northbound": "北向资金数据获取中..."}
|
||||
except:
|
||||
return {}
|
||||
|
||||
# ========== 3. 龙虎榜 ==========
|
||||
|
||||
def fetch_dragon_tiger(self, date: str = None) -> List[Dict]:
|
||||
"""获取龙虎榜数据"""
|
||||
if not date:
|
||||
date = datetime.now().strftime("%Y%m%d")
|
||||
|
||||
url = f"http://datacenter-web.eastmoney.com/api/data/v1/get"
|
||||
params = {
|
||||
"sortColumns": "NET_BUY_AMT",
|
||||
"sortTypes": "-1",
|
||||
"pageSize": "50",
|
||||
"pageNumber": "1",
|
||||
"reportName": "RPT_DMSK_TS",
|
||||
"columns": "ALL",
|
||||
"filter": f"(TRADE_DATE='{date}')"
|
||||
}
|
||||
|
||||
try:
|
||||
resp = self.session.get(url, params=params, timeout=10)
|
||||
data = resp.json()
|
||||
return data.get("result", {}).get("data", [])
|
||||
except:
|
||||
return []
|
||||
|
||||
# ========== 4. 宏观关联分析 ==========
|
||||
|
||||
def analyze_gold_correlation(self, gold_price: float, stocks: List[Dict]) -> str:
|
||||
"""分析金价与持仓股票的关联"""
|
||||
# 江西铜业等有色股与金价正相关
|
||||
correlation_map = {
|
||||
"600362": "强正相关", # 江西铜业
|
||||
"601318": "弱相关", # 中国平安
|
||||
"513180": "弱负相关", # 恒生科技
|
||||
"159892": "弱相关", # 恒生医疗
|
||||
}
|
||||
|
||||
analysis = []
|
||||
for stock in stocks:
|
||||
code = stock.get("code")
|
||||
corr = correlation_map.get(code, "未知")
|
||||
if corr in ["强正相关", "中等正相关"]:
|
||||
analysis.append(f"📈 {stock['name']}: 与金价{corr},金价上涨可能带动该股")
|
||||
|
||||
return "\n".join(analysis) if analysis else "暂无强关联标的"
|
||||
|
||||
# ========== 5. 综合分析 ==========
|
||||
|
||||
def generate_insight(self, stock: Dict, price_data: Dict, alerts: List) -> str:
|
||||
"""生成综合分析报告"""
|
||||
code = stock['code']
|
||||
name = stock['name']
|
||||
|
||||
# 1. 获取新闻
|
||||
news_list = self.fetch_eastmoney_news(code, name)
|
||||
sentiment = self.analyze_sentiment(news_list)
|
||||
|
||||
# 2. 资金流向
|
||||
fund_flow = self.fetch_fund_flow(code, stock.get('market', 'sz'))
|
||||
|
||||
# 3. 构建报告
|
||||
report = f"""📊 <b>{name} ({code}) 深度分析</b>
|
||||
|
||||
💰 <b>价格异动:</b>
|
||||
• 当前: {price_data.get('price', 'N/A')} ({price_data.get('change_pct', 0):+.2f}%)
|
||||
• 触发: {', '.join([a[1] for a in alerts])}
|
||||
|
||||
📰 <b>舆情分析 ({sentiment.get('overall', '未知')}):</b>
|
||||
• 最近新闻: {len(news_list)} 条
|
||||
• 正面: {sentiment.get('positive', 0)} | 负面: {sentiment.get('negative', 0)}
|
||||
"""
|
||||
|
||||
# 添加最新新闻标题
|
||||
if news_list:
|
||||
report += "\n<b>最新动态:</b>\n"
|
||||
for n in news_list[:2]:
|
||||
report += f"• {n.get('title', '无标题')[:30]}...\n"
|
||||
|
||||
# 4. 给出建议
|
||||
suggestion = self._generate_suggestion(sentiment, alerts)
|
||||
report += f"\n💡 <b>Kimi建议:</b>\n{suggestion}"
|
||||
|
||||
return report
|
||||
|
||||
def _generate_suggestion(self, sentiment: Dict, alerts: List) -> str:
|
||||
"""基于数据生成建议"""
|
||||
alert_types = [a[0] for a in alerts]
|
||||
overall = sentiment.get("overall", "中性")
|
||||
|
||||
# 价格下跌 + 舆情偏空 = 谨慎
|
||||
if "below" in alert_types and overall == "偏空":
|
||||
return "⚠️ 价格跌破支撑位,且舆情偏空,建议观察等待,不急于抄底。"
|
||||
|
||||
# 价格下跌 + 舆情偏多 = 可能是机会
|
||||
if "below" in alert_types and overall == "偏多":
|
||||
return "🔍 价格下跌但舆情偏多,可能是情绪错杀,关注是否有反弹机会。"
|
||||
|
||||
# 价格突破 + 舆情偏多 = 确认趋势
|
||||
if "above" in alert_types and overall == "偏多":
|
||||
return "🚀 价格突破且舆情配合,趋势可能延续,可考虑顺势而为。"
|
||||
|
||||
# 大涨
|
||||
if "pct_up" in alert_types:
|
||||
return "📈 短期涨幅较大,注意获利了结风险。"
|
||||
|
||||
# 大跌
|
||||
if "pct_down" in alert_types:
|
||||
return "📉 短期跌幅较大,关注是否超跌反弹,但勿急于抄底。"
|
||||
|
||||
return "⏳ 建议保持观察,等待更明确信号。"
|
||||
|
||||
|
||||
# ========== 测试 ==========
|
||||
if __name__ == '__main__':
|
||||
analyser = StockAnalyser()
|
||||
|
||||
# 测试新闻抓取
|
||||
print("=== 新闻测试 ===")
|
||||
news = analyser.fetch_eastmoney_news("600362", "江西铜业")
|
||||
print(f"获取到 {len(news)} 条新闻")
|
||||
for n in news[:3]:
|
||||
print(f" - {n.get('title', 'N/A')[:40]}...")
|
||||
|
||||
# 测试情感分析
|
||||
print("\n=== 情感分析测试 ===")
|
||||
sentiment = analyser.analyze_sentiment(news)
|
||||
print(f"整体情绪: {sentiment.get('overall')}")
|
||||
print(f"正面: {sentiment.get('positive')}, 负面: {sentiment.get('negative')}")
|
||||
|
||||
# 测试金价关联
|
||||
print("\n=== 宏观关联测试 ===")
|
||||
stocks = [{"code": "600362", "name": "江西铜业"}]
|
||||
corr = analyser.analyze_gold_correlation(2743, stocks)
|
||||
print(corr)
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Stock Monitor 一键启动脚本
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
LOG_DIR="$HOME/.stock_monitor"
|
||||
PID_FILE="$LOG_DIR/monitor.pid"
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
|
||||
echo "⚠️ 监控进程已在运行 (PID: $(cat $PID_FILE))"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🚀 启动 Stock Monitor 后台进程..."
|
||||
mkdir -p "$LOG_DIR"
|
||||
nohup python3 "$SCRIPT_DIR/monitor_daemon.py" > "$LOG_DIR/monitor.log" 2>&1 &
|
||||
echo $! > "$PID_FILE"
|
||||
echo "✅ 已启动 (PID: $!)"
|
||||
echo "📋 日志: $LOG_DIR/monitor.log"
|
||||
;;
|
||||
|
||||
stop)
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
echo "🛑 停止监控进程 (PID: $PID)..."
|
||||
kill "$PID"
|
||||
rm "$PID_FILE"
|
||||
echo "✅ 已停止"
|
||||
else
|
||||
echo "⚠️ 进程不存在"
|
||||
rm "$PID_FILE"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ 没有运行中的进程"
|
||||
fi
|
||||
;;
|
||||
|
||||
status)
|
||||
if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
|
||||
echo "✅ 监控运行中 (PID: $(cat $PID_FILE))"
|
||||
echo "📋 最近日志:"
|
||||
tail -5 "$LOG_DIR/monitor.log" 2>/dev/null || echo " 暂无日志"
|
||||
else
|
||||
echo "⏹️ 监控未运行"
|
||||
fi
|
||||
;;
|
||||
|
||||
log)
|
||||
tail -f "$LOG_DIR/monitor.log"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Stock Monitor 控制脚本"
|
||||
echo ""
|
||||
echo "用法: ./control.sh [start|stop|status|log]"
|
||||
echo ""
|
||||
echo " start - 启动后台监控"
|
||||
echo " stop - 停止监控"
|
||||
echo " status - 查看状态"
|
||||
echo " log - 查看实时日志"
|
||||
;;
|
||||
esac
|
||||
@@ -1,483 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
自选股监控预警工具 - OpenClaw集成版
|
||||
支持 A股、ETF 及 国际现货黄金 (伦敦金)
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# ============ 配置区 ============
|
||||
|
||||
# 监控列表 - 长期挂机通用配置
|
||||
# 注意: 伦敦金使用新浪hf_XAU接口,价格为 人民币/克 (约4800元/克 = $2740/盎司)
|
||||
#
|
||||
# 预警规则设计原则 (适合长期挂机):
|
||||
# 1. 成本百分比预警: 基于持仓成本设置 ±10%/±15% 预警,比固定价格更合理
|
||||
# 2. 单日涨跌幅预警:
|
||||
# - 个股 ±3%~5% (波动大)
|
||||
# - ETF ±1.5%~2.5% (波动小)
|
||||
# - 黄金 ±2%~3% (24H特殊)
|
||||
# 3. 防骚扰: 同类预警30分钟内只发一次
|
||||
|
||||
# 标的类型定义
|
||||
STOCK_TYPE = {
|
||||
"INDIVIDUAL": "individual", # 个股
|
||||
"ETF": "etf", # ETF
|
||||
"GOLD": "gold" # 黄金/贵金属
|
||||
}
|
||||
|
||||
WATCHLIST = [
|
||||
# ===== 用户自定义监控个股 =====
|
||||
{
|
||||
"code": "000630",
|
||||
"name": "铜陵有色",
|
||||
"market": "sz",
|
||||
"type": "individual",
|
||||
"cost": 7.00, # 参考成本价
|
||||
"alerts": {
|
||||
"change_pct_above": 5.0, # 日内涨超 5% 预警
|
||||
"change_pct_below": -5.0, # 日内跌超 5% 预警
|
||||
"volume_surge": 2.0 # 成交量异动
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "002195",
|
||||
"name": "岩山科技",
|
||||
"market": "sz",
|
||||
"type": "individual",
|
||||
"cost": 10.68, # 200 股,成本 10.68 元
|
||||
"alerts": {
|
||||
"cost_pct_above": 5.0, # 盈利超 5% 快跑 (目标价 ¥11.21)
|
||||
"change_pct_above": 5.0, # 日内涨超 5% 预警
|
||||
"change_pct_below": -5.0, # 日内跌超 5% 预警
|
||||
"volume_surge": 2.0 # 成交量异动
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# 智能频率配置
|
||||
SMART_SCHEDULE = {
|
||||
"market_open": {"hours": [(9, 30), (11, 30), (13, 0), (15, 0)], "interval": 300}, # 交易时间: 5分钟
|
||||
"after_hours": {"interval": 1800}, # 收盘后: 30分钟
|
||||
"night": {"hours": [(0, 0), (8, 0)], "interval": 3600}, # 凌晨: 1小时(仅伦敦金)
|
||||
}
|
||||
|
||||
# ============ 核心代码 ============
|
||||
|
||||
class StockAlert:
|
||||
def __init__(self):
|
||||
self.prev_data = {}
|
||||
self.alert_log = []
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update({"User-Agent": "Mozilla/5.0"})
|
||||
|
||||
def should_run_now(self):
|
||||
"""智能频率控制: 判断当前是否应该执行监控 (基于北京时间)"""
|
||||
# 服务器在纽约(EST),中国股市用北京时间(CST = EST + 13小时)
|
||||
from datetime import timedelta
|
||||
now = datetime.now() + timedelta(hours=13) # 转换成北京时间
|
||||
hour, minute = now.hour, now.minute
|
||||
time_val = hour * 100 + minute
|
||||
weekday = now.weekday()
|
||||
|
||||
# 周末只监控伦敦金
|
||||
if weekday >= 5: # 周六日
|
||||
return {"run": True, "mode": "weekend", "stocks": [s for s in WATCHLIST if s['market'] == 'fx']}
|
||||
|
||||
# 交易时间 (9:30-11:30, 13:00-15:00)
|
||||
morning_session = 930 <= time_val <= 1130
|
||||
afternoon_session = 1300 <= time_val <= 1500
|
||||
|
||||
if morning_session or afternoon_session:
|
||||
return {"run": True, "mode": "market", "stocks": WATCHLIST, "interval": 300}
|
||||
|
||||
# 午休 (11:30-13:00)
|
||||
if 1130 < time_val < 1300:
|
||||
return {"run": True, "mode": "lunch", "stocks": WATCHLIST, "interval": 600} # 10分钟
|
||||
|
||||
# 收盘后 (15:00-24:00)
|
||||
if 1500 <= time_val <= 2359:
|
||||
return {"run": True, "mode": "after_hours", "stocks": WATCHLIST, "interval": 1800} # 30分钟
|
||||
|
||||
# 凌晨 (0:00-9:30)
|
||||
if 0 <= time_val < 930:
|
||||
return {"run": True, "mode": "night", "stocks": [s for s in WATCHLIST if s['market'] == 'fx'], "interval": 3600} # 1小时
|
||||
|
||||
return {"run": False}
|
||||
|
||||
def fetch_eastmoney_kline(self, symbol, market):
|
||||
"""获取最新日K线数据 (收盘后也能获取收盘价)"""
|
||||
secid = f"{market}.{symbol}"
|
||||
url = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
|
||||
params = {
|
||||
'secid': secid,
|
||||
'fields1': 'f1,f2,f3,f4,f5,f6',
|
||||
'fields2': 'f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61',
|
||||
'klt': '101', # 日线
|
||||
'fqt': '0',
|
||||
'end': '20500101',
|
||||
'lmt': '2' # 取最近2天,用于计算涨跌幅
|
||||
}
|
||||
try:
|
||||
resp = self.session.get(url, params=params, timeout=10)
|
||||
data = resp.json()
|
||||
klines = data.get('data', {}).get('klines', [])
|
||||
if len(klines) >= 1:
|
||||
# 格式: 日期,开盘,收盘,最高,最低,成交量,成交额,振幅,涨跌幅,涨跌额,换手率
|
||||
today = klines[-1].split(',')
|
||||
prev_close = float(today[2]) # 昨收
|
||||
if len(klines) >= 2:
|
||||
prev_close = float(klines[-2].split(',')[2]) # 前一天收盘
|
||||
return {
|
||||
'name': data.get('data', {}).get('name', symbol),
|
||||
'price': float(today[2]), # 收盘
|
||||
'prev_close': prev_close,
|
||||
'volume': int(float(today[5])),
|
||||
'amount': float(today[6]),
|
||||
'date': today[0],
|
||||
'time': '15:00:00'
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"东财K线获取失败 {symbol}: {e}")
|
||||
return None
|
||||
|
||||
def fetch_volume_ma5(self, symbol, market):
|
||||
"""获取5日平均成交量"""
|
||||
secid = f"{market}.{symbol}"
|
||||
url = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
|
||||
params = {
|
||||
'secid': secid,
|
||||
'fields1': 'f1,f2,f3,f4,f5,f6',
|
||||
'fields2': 'f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61',
|
||||
'klt': '101',
|
||||
'fqt': '0',
|
||||
'end': '20500101',
|
||||
'lmt': '6' # 取最近6天(今天+前5天)
|
||||
}
|
||||
try:
|
||||
resp = self.session.get(url, params=params, timeout=10)
|
||||
data = resp.json()
|
||||
klines = data.get('data', {}).get('klines', [])
|
||||
if len(klines) >= 2:
|
||||
# 计算前5日平均成交量(不含今天)
|
||||
volumes = []
|
||||
for k in klines[:-1]: # 排除最后一天(今天)
|
||||
p = k.split(',')
|
||||
volumes.append(float(p[5])) # 成交量
|
||||
return sum(volumes) / len(volumes) if volumes else 0
|
||||
except Exception as e:
|
||||
print(f"获取均量失败 {symbol}: {e}")
|
||||
return 0
|
||||
|
||||
def fetch_ma_data(self, symbol, market):
|
||||
"""获取均线数据 (MA5, MA10, MA20) 和 RSI"""
|
||||
secid = f"{market}.{symbol}"
|
||||
url = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
|
||||
params = {
|
||||
'secid': secid,
|
||||
'fields1': 'f1,f2,f3,f4,f5,f6',
|
||||
'fields2': 'f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61',
|
||||
'klt': '101',
|
||||
'fqt': '0',
|
||||
'end': '20500101',
|
||||
'lmt': '30' # 取最近30天计算MA20和RSI
|
||||
}
|
||||
try:
|
||||
resp = self.session.get(url, params=params, timeout=10)
|
||||
data = resp.json()
|
||||
klines = data.get('data', {}).get('klines', [])
|
||||
if len(klines) >= 20:
|
||||
closes = []
|
||||
for k in klines:
|
||||
p = k.split(',')
|
||||
closes.append(float(p[2])) # 收盘价
|
||||
|
||||
# 计算均线
|
||||
ma5 = sum(closes[-5:]) / 5
|
||||
ma10 = sum(closes[-10:]) / 10
|
||||
ma20 = sum(closes[-20:]) / 20
|
||||
|
||||
# 判断均线趋势
|
||||
prev_ma5 = sum(closes[-6:-1]) / 5
|
||||
prev_ma10 = sum(closes[-11:-1]) / 10
|
||||
|
||||
# 计算RSI(14)
|
||||
rsi = self._calculate_rsi(closes, 14)
|
||||
|
||||
return {
|
||||
'MA5': ma5,
|
||||
'MA10': ma10,
|
||||
'MA20': ma20,
|
||||
'MA5_trend': 'up' if ma5 > prev_ma5 else 'down',
|
||||
'MA10_trend': 'up' if ma10 > prev_ma10 else 'down',
|
||||
'golden_cross': prev_ma5 <= prev_ma10 and ma5 > ma10,
|
||||
'death_cross': prev_ma5 >= prev_ma10 and ma5 < ma10,
|
||||
'RSI': rsi,
|
||||
'RSI_overbought': rsi > 70 if rsi else False,
|
||||
'RSI_oversold': rsi < 30 if rsi else False
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"获取均线失败 {symbol}: {e}")
|
||||
return None
|
||||
|
||||
def _calculate_rsi(self, closes, period=14):
|
||||
"""计算RSI指标"""
|
||||
if len(closes) < period + 1:
|
||||
return None
|
||||
|
||||
gains = []
|
||||
losses = []
|
||||
|
||||
for i in range(1, period + 1):
|
||||
change = closes[-i] - closes[-i-1]
|
||||
if change > 0:
|
||||
gains.append(change)
|
||||
losses.append(0)
|
||||
else:
|
||||
gains.append(0)
|
||||
losses.append(abs(change))
|
||||
|
||||
avg_gain = sum(gains) / period
|
||||
avg_loss = sum(losses) / period
|
||||
|
||||
if avg_loss == 0:
|
||||
return 100
|
||||
|
||||
rs = avg_gain / avg_loss
|
||||
rsi = 100 - (100 / (1 + rs))
|
||||
return round(rsi, 2)
|
||||
|
||||
def fetch_tencent_realtime(self, stocks):
|
||||
"""获取实时行情 (腾讯财经接口,更稳定)"""
|
||||
stock_list = [s for s in stocks if s['market'] != 'fx']
|
||||
fx_list = [s for s in stocks if s['market'] == 'fx']
|
||||
results = {}
|
||||
|
||||
# 1. A 股/ETF - 腾讯财经接口
|
||||
if stock_list:
|
||||
for stock in stock_list:
|
||||
code = f"{stock['market']}{stock['code']}"
|
||||
url = f"http://qt.gtimg.cn/q={code}"
|
||||
try:
|
||||
resp = self.session.get(url, timeout=5)
|
||||
resp.encoding = 'gbk'
|
||||
data = resp.text.strip()
|
||||
if '="' not in data:
|
||||
continue
|
||||
parts = data.strip('"').split('~')
|
||||
start_idx = 0
|
||||
for j, p in enumerate(parts):
|
||||
if p.isdigit() and len(p) == 2:
|
||||
start_idx = j
|
||||
break
|
||||
if len(parts) > start_idx + 20:
|
||||
current = float(parts[start_idx+3])
|
||||
prev_close = float(parts[start_idx+4])
|
||||
open_p = float(parts[start_idx+5])
|
||||
change = 0
|
||||
change_pct = 0
|
||||
high = 0
|
||||
low = 0
|
||||
for j in range(len(parts)-5):
|
||||
try:
|
||||
if parts[j].startswith('-') and '.' in parts[j]:
|
||||
v1 = float(parts[j])
|
||||
v2 = float(parts[j+1])
|
||||
if -10 < v2 < 10:
|
||||
change = v1
|
||||
change_pct = v2
|
||||
high = float(parts[j+2])
|
||||
low = float(parts[j+3])
|
||||
break
|
||||
except:
|
||||
continue
|
||||
results[stock['code']] = {
|
||||
'name': parts[start_idx+1],
|
||||
'price': current,
|
||||
'prev_close': prev_close,
|
||||
'open': open_p,
|
||||
'high': high,
|
||||
'low': low,
|
||||
'volume': 0,
|
||||
'amount': 0,
|
||||
'date': datetime.now().strftime('%Y-%m-%d'),
|
||||
'time': datetime.now().strftime('%H:%M:%S')
|
||||
}
|
||||
print(f"✅ {stock['name']} ({stock['code']}): ¥{current:.2f}")
|
||||
except Exception as e:
|
||||
print(f"腾讯行情获取失败 {stock['code']}: {e}")
|
||||
|
||||
# 2. 伦敦金 (保留原逻辑)
|
||||
if fx_list:
|
||||
url = "https://hq.sinajs.cn/list=hf_XAU"
|
||||
try:
|
||||
resp = self.session.get(url, timeout=5)
|
||||
line = resp.text.strip()
|
||||
if '"' in line:
|
||||
data_str = line[line.index('"')+1 : line.rindex('"')]
|
||||
p = data_str.split(',')
|
||||
if len(p) >= 13:
|
||||
price = float(p[0])
|
||||
results['XAU'] = {
|
||||
'name': '伦敦金',
|
||||
'price': price,
|
||||
'prev_close': float(p[7]),
|
||||
'volume': 0, 'amount': 0,
|
||||
'date': datetime.now().strftime('%Y-%m-%d'),
|
||||
'time': p[6]
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"伦敦金获取失败:{e}")
|
||||
|
||||
return results
|
||||
|
||||
def record_alert(self, code, icon):
|
||||
"""记录预警日志 (简化版)"""
|
||||
# 简单打印日志,实际可以写入文件
|
||||
print(f" 📝 预警记录:{code} - {icon}")
|
||||
|
||||
def check_alerts(self, stock_config, data):
|
||||
"""检查预警条件 (返回格式:[(icon, text), ...], level)"""
|
||||
alerts = []
|
||||
code = stock_config['code']
|
||||
cfg = stock_config.get('alerts', {})
|
||||
cost = stock_config.get('cost', 0)
|
||||
|
||||
price = data['price']
|
||||
prev_close = data['prev_close']
|
||||
change_pct = ((price - prev_close) / prev_close) * 100 if prev_close else 0
|
||||
|
||||
# 1. 成本百分比预警
|
||||
if cost > 0:
|
||||
if 'cost_pct_above' in cfg:
|
||||
threshold = cost * (1 + cfg['cost_pct_above'] / 100)
|
||||
if price >= threshold:
|
||||
alerts.append(("🎯", f"盈利 {cfg['cost_pct_above']}% (目标价 ¥{threshold:.2f})"))
|
||||
|
||||
if 'cost_pct_below' in cfg:
|
||||
threshold = cost * (1 + cfg['cost_pct_below'] / 100)
|
||||
if price <= threshold:
|
||||
alerts.append(("📉", f"亏损 {abs(cfg['cost_pct_below'])}% (止损价 ¥{threshold:.2f})"))
|
||||
|
||||
# 2. 日内涨跌幅预警
|
||||
if 'change_pct_above' in cfg and change_pct >= cfg['change_pct_above']:
|
||||
alerts.append(("📈", f"日内大涨 {change_pct:.2f}% (阈值 {cfg['change_pct_above']}%)"))
|
||||
|
||||
if 'change_pct_below' in cfg and change_pct <= cfg['change_pct_below']:
|
||||
alerts.append(("📉", f"日内大跌 {change_pct:.2f}% (阈值 {cfg['change_pct_below']}%)"))
|
||||
|
||||
# 确定预警级别
|
||||
if len(alerts) >= 3:
|
||||
level = "critical"
|
||||
elif len(alerts) >= 2:
|
||||
level = "warning"
|
||||
elif len(alerts) >= 1:
|
||||
level = "info"
|
||||
else:
|
||||
level = "none"
|
||||
|
||||
return alerts, level
|
||||
|
||||
def fetch_news(self, symbol):
|
||||
"""抓取个股最近新闻 (新浪/东财聚合) - 简化版"""
|
||||
try:
|
||||
# 使用东财个股新闻API
|
||||
url = f"https://emweb.securities.eastmoney.com/PC_HSF10/CompanySurvey/CompanySurveyAjax"
|
||||
params = {"code": symbol}
|
||||
resp = self.session.get(url, params=params, timeout=5)
|
||||
return ["新闻模块已就绪 (市场收盘中)"]
|
||||
except:
|
||||
return []
|
||||
|
||||
def run_once(self, smart_mode=True):
|
||||
"""执行监控 (支持智能频率)"""
|
||||
if smart_mode:
|
||||
schedule = self.should_run_now()
|
||||
if not schedule.get("run"):
|
||||
return []
|
||||
|
||||
stocks_to_check = schedule.get("stocks", WATCHLIST)
|
||||
mode = schedule.get("mode", "normal")
|
||||
|
||||
# 只在特定模式打印日志
|
||||
if mode in ["market", "weekend"]:
|
||||
print(f"[{datetime.now().strftime('%H:%M')}] {mode}模式扫描 {len(stocks_to_check)} 只标的...")
|
||||
else:
|
||||
stocks_to_check = WATCHLIST
|
||||
|
||||
data_map = self.fetch_tencent_realtime(stocks_to_check)
|
||||
triggered = []
|
||||
|
||||
for stock in stocks_to_check:
|
||||
code = stock['code']
|
||||
if code not in data_map: continue
|
||||
|
||||
data = data_map[code]
|
||||
|
||||
# 数据有效性检查
|
||||
if data['price'] <= 0 or data['prev_close'] <= 0:
|
||||
continue
|
||||
|
||||
alerts, level = self.check_alerts(stock, data)
|
||||
|
||||
if alerts:
|
||||
change_pct = (data['price'] - data['prev_close']) / data['prev_close'] * 100 if data['prev_close'] else 0
|
||||
|
||||
# 中国习惯: 红色=上涨, 绿色=下跌
|
||||
if change_pct > 0:
|
||||
color_emoji = "🔴" # 红涨
|
||||
elif change_pct < 0:
|
||||
color_emoji = "🟢" # 绿跌
|
||||
else:
|
||||
color_emoji = "⚪"
|
||||
|
||||
# 预警级别标识
|
||||
level_icons = {
|
||||
"critical": "🚨", # 紧急
|
||||
"warning": "⚠️", # 警告
|
||||
"info": "📢" # 提醒
|
||||
}
|
||||
level_icon = level_icons.get(level, "📢")
|
||||
level_text = {"critical": "【紧急】", "warning": "【警告】", "info": "【提醒】"}.get(level, "")
|
||||
|
||||
msg = f"<b>{level_icon} {level_text}{color_emoji} {stock['name']} ({code})</b>\n"
|
||||
msg += f"━━━━━━━━━━━━━━━━━━━━\n"
|
||||
msg += f"💰 当前价格: <b>{data['price']:.2f}</b> ({change_pct:+.2f}%)\n"
|
||||
|
||||
# 显示持仓盈亏
|
||||
cost = stock.get('cost', 0)
|
||||
if cost > 0:
|
||||
cost_change = (data['price'] - cost) / cost * 100
|
||||
profit_icon = "🔴+" if cost_change > 0 else "🟢"
|
||||
msg += f"📊 持仓成本: ¥{cost:.2f} | 盈亏: {profit_icon}{cost_change:.2f}%\n"
|
||||
|
||||
msg += f"\n🎯 触发预警 ({len(alerts)}项):\n"
|
||||
for _, text in alerts:
|
||||
msg += f" • {text}\n"
|
||||
self.record_alert(code, _)
|
||||
|
||||
# Pro版:集成智能分析
|
||||
try:
|
||||
from analyser import StockAnalyser
|
||||
analyser = StockAnalyser()
|
||||
insight = analyser.generate_insight(stock, {
|
||||
'price': data['price'],
|
||||
'change_pct': change_pct
|
||||
}, alerts)
|
||||
msg += f"\n{insight}"
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
triggered.append(msg)
|
||||
|
||||
return triggered
|
||||
|
||||
if __name__ == '__main__':
|
||||
monitor = StockAlert()
|
||||
for alert in monitor.run_once():
|
||||
print(alert)
|
||||
@@ -1,107 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Stock Monitor Daemon - 后台常驻进程
|
||||
自动运行监控,智能控制频率,支持 graceful shutdown
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# 设置日志
|
||||
log_dir = Path.home() / ".stock_monitor"
|
||||
log_dir.mkdir(exist_ok=True)
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(log_dir / "monitor.log"),
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 导入监控类
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from monitor import StockAlert, WATCHLIST
|
||||
|
||||
class MonitorDaemon:
|
||||
def __init__(self):
|
||||
self.monitor = StockAlert()
|
||||
self.running = True
|
||||
self.last_run_time = 0
|
||||
|
||||
# 设置信号处理
|
||||
signal.signal(signal.SIGTERM, self.handle_shutdown)
|
||||
signal.signal(signal.SIGINT, self.handle_shutdown)
|
||||
|
||||
def handle_shutdown(self, signum, frame):
|
||||
"""优雅退出"""
|
||||
logger.info(f"收到信号 {signum},正在关闭...")
|
||||
self.running = False
|
||||
|
||||
def get_sleep_interval(self):
|
||||
"""根据当前时间获取睡眠间隔"""
|
||||
schedule = self.monitor.should_run_now()
|
||||
if not schedule.get("run"):
|
||||
# 如果当前不需要运行,计算到下次运行的时间
|
||||
now = datetime.now()
|
||||
hour = now.hour
|
||||
|
||||
# 凌晨时段,1小时后检查
|
||||
if 0 <= hour < 9:
|
||||
return 3600
|
||||
return 300 # 默认5分钟
|
||||
|
||||
return schedule.get("interval", 300)
|
||||
|
||||
def run(self):
|
||||
"""主循环"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("🚀 Stock Monitor Daemon 启动")
|
||||
logger.info(f"📋 监控标的: {len(WATCHLIST)} 只")
|
||||
logger.info("=" * 60)
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
# 检查是否应该执行
|
||||
schedule = self.monitor.should_run_now()
|
||||
|
||||
if schedule.get("run"):
|
||||
mode = schedule.get("mode", "normal")
|
||||
stocks_count = len(schedule.get("stocks", []))
|
||||
logger.info(f"[{mode}] 扫描 {stocks_count} 只标的...")
|
||||
|
||||
# 执行监控
|
||||
alerts = self.monitor.run_once(smart_mode=False) # 已经判断过了
|
||||
|
||||
if alerts:
|
||||
logger.info(f"⚠️ 触发 {len(alerts)} 条预警")
|
||||
# 这里会通过 message 工具发送通知
|
||||
else:
|
||||
logger.debug("✅ 无预警")
|
||||
|
||||
self.last_run_time = time.time()
|
||||
|
||||
# 计算睡眠间隔
|
||||
sleep_interval = self.get_sleep_interval()
|
||||
logger.debug(f"下次检查: {sleep_interval} 秒后")
|
||||
|
||||
# 分段睡眠,方便及时响应退出信号
|
||||
slept = 0
|
||||
while slept < sleep_interval and self.running:
|
||||
time.sleep(1)
|
||||
slept += 1
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"运行出错: {e}", exc_info=True)
|
||||
time.sleep(60) # 出错后等待1分钟重试
|
||||
|
||||
logger.info("👋 Daemon 已停止")
|
||||
|
||||
if __name__ == '__main__':
|
||||
daemon = MonitorDaemon()
|
||||
daemon.run()
|
||||
@@ -1,198 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
铜陵有色专项监控 - 实时股价监控
|
||||
使用腾讯财经接口,确保数据准确性
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# ============ 配置 ============
|
||||
|
||||
WATCHLIST = [
|
||||
{
|
||||
"code": "000630",
|
||||
"name": "铜陵有色",
|
||||
"market": "sz",
|
||||
"alerts": {
|
||||
"change_pct_above": 5.0, # 涨超 5% 预警
|
||||
"change_pct_below": -5.0, # 跌超 5% 预警
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# 企业微信配置
|
||||
WECOM_BOT_ID = "aibwl3AhnzfRPRTEZvBVwlB-vRD33yJdUVX"
|
||||
WECOM_SECRET = "1eUB2yd2R7bll6VjBQ5OGptJj2YiwutMUmACe9UGC7k"
|
||||
ALLOW_USERS = ["HouHuan", "WanMeiShengHuo", "XinNingXianGuoNaiChaKaFeiZhaJiHa"]
|
||||
|
||||
# ============ 核心功能 ============
|
||||
|
||||
def fetch_tencent_price(stock):
|
||||
"""腾讯财经接口获取实时股价"""
|
||||
code = f"{stock['market']}{stock['code']}"
|
||||
url = f"http://qt.gtimg.cn/q={code}"
|
||||
|
||||
try:
|
||||
resp = requests.get(url, timeout=5)
|
||||
resp.encoding = 'gbk'
|
||||
data = resp.text.strip()
|
||||
|
||||
# 解析:v_sz000630="51~名称~代码~现价~昨收~今开~...
|
||||
if '="' not in data:
|
||||
return None
|
||||
|
||||
parts = data.strip('"').split('~')
|
||||
|
||||
# 找到前缀位置
|
||||
start_idx = 0
|
||||
for i, p in enumerate(parts):
|
||||
if p.isdigit() and len(p) == 2:
|
||||
start_idx = i
|
||||
break
|
||||
|
||||
if len(parts) <= start_idx + 20:
|
||||
return None
|
||||
|
||||
# 正确解析索引
|
||||
name = parts[start_idx+1]
|
||||
code = parts[start_idx+2]
|
||||
current = float(parts[start_idx+3]) # 现价
|
||||
prev_close = float(parts[start_idx+4]) # 昨收
|
||||
open_p = float(parts[start_idx+5]) # 今开
|
||||
|
||||
# 找涨跌额、涨跌幅、最高、最低
|
||||
change = 0
|
||||
change_pct = 0
|
||||
high = 0
|
||||
low = 0
|
||||
|
||||
for i in range(len(parts)-5):
|
||||
try:
|
||||
if parts[i].startswith('-') and '.' in parts[i]:
|
||||
v1 = float(parts[i])
|
||||
v2 = float(parts[i+1])
|
||||
if -10 < v2 < 10: # 涨跌幅一般在 -10~10 之间
|
||||
change = v1
|
||||
change_pct = v2
|
||||
high = float(parts[i+2])
|
||||
low = float(parts[i+3])
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
return {
|
||||
'name': name,
|
||||
'code': code,
|
||||
'price': current,
|
||||
'prev_close': prev_close,
|
||||
'open': open_p,
|
||||
'high': high,
|
||||
'low': low,
|
||||
'change': change,
|
||||
'change_pct': change_pct,
|
||||
'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"❌ 数据获取失败:{e}")
|
||||
return None
|
||||
|
||||
def check_alerts(stock, data):
|
||||
"""检查是否触发预警"""
|
||||
alerts = []
|
||||
cfg = stock.get('alerts', {})
|
||||
|
||||
change_pct = data['change_pct']
|
||||
|
||||
# 检查涨跌幅预警
|
||||
if 'change_pct_above' in cfg and change_pct >= cfg['change_pct_above']:
|
||||
alerts.append({
|
||||
'type': '🔴 大涨',
|
||||
'condition': f"涨幅超过 {cfg['change_pct_above']}%",
|
||||
'value': f"{change_pct:.2f}%"
|
||||
})
|
||||
|
||||
if 'change_pct_below' in cfg and change_pct <= cfg['change_pct_below']:
|
||||
alerts.append({
|
||||
'type': '🟢 大跌',
|
||||
'condition': f"跌幅超过 {abs(cfg['change_pct_below'])}%",
|
||||
'value': f"{change_pct:.2f}%"
|
||||
})
|
||||
|
||||
return alerts
|
||||
|
||||
def send_wecom_alert(stock_name, data, alerts):
|
||||
"""发送企业微信预警消息"""
|
||||
from gateway import send_message
|
||||
|
||||
# 组合消息
|
||||
alert_text = "\n".join([f" • {a['type']}: {a['condition']} ({a['value']})" for a in alerts])
|
||||
|
||||
message = f"""🚨【股价预警】{stock_name} ({data['code']})
|
||||
━━━━━━━━━━━━━━━━━━━━
|
||||
💰 当前价格:¥{data['price']:.2f} ({data['change_pct']:+.2f}%)
|
||||
|
||||
🎯 触发预警:
|
||||
{alert_text}
|
||||
|
||||
📊 详细数据:
|
||||
• 昨收:¥{data['prev_close']:.2f}
|
||||
• 今开:¥{data['open']:.2f}
|
||||
• 最高:¥{data['high']:.2f}
|
||||
• 最低:¥{data['low']:.2f}
|
||||
|
||||
⏰ 数据时间:{data['time']}
|
||||
|
||||
💡 建议关注后续走势,注意风险控制。
|
||||
"""
|
||||
|
||||
# 发送给所有允许的用户
|
||||
for user in ALLOW_USERS:
|
||||
try:
|
||||
send_message(
|
||||
channel="wecom",
|
||||
target=user,
|
||||
message=message
|
||||
)
|
||||
print(f"✅ 预警已发送给用户:{user}")
|
||||
except Exception as e:
|
||||
print(f"❌ 发送失败 {user}: {e}")
|
||||
|
||||
def monitor_once():
|
||||
"""执行一次监控"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"📊 铜陵有色监控 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
for stock in WATCHLIST:
|
||||
data = fetch_tencent_price(stock)
|
||||
|
||||
if not data:
|
||||
print(f"❌ {stock['name']} 数据获取失败")
|
||||
continue
|
||||
|
||||
print(f"✅ {stock['name']} ({stock['code']})")
|
||||
print(f" 现价:¥{data['price']:.2f} ({data['change_pct']:+.2f}%)")
|
||||
print(f" 昨收:¥{data['prev_close']:.2f}")
|
||||
print(f" 涨跌:¥{data['change']:.2f}")
|
||||
|
||||
# 检查预警
|
||||
alerts = check_alerts(stock, data)
|
||||
|
||||
if alerts:
|
||||
print(f" 🚨 触发 {len(alerts)} 条预警!")
|
||||
send_wecom_alert(stock['name'], data, alerts)
|
||||
else:
|
||||
print(f" ✅ 正常波动范围")
|
||||
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
# ============ 主程序 ============
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 单次执行
|
||||
monitor_once()
|
||||
@@ -1,352 +0,0 @@
|
||||
# 📈 股票技能使用手册
|
||||
|
||||
> 三大股票分析技能完整使用指南
|
||||
> 更新时间:2026-03-13
|
||||
> 适用市场:A 股(沪深两市)
|
||||
|
||||
---
|
||||
|
||||
## 📋 技能列表
|
||||
|
||||
| 技能名称 | 功能定位 | 适用场景 |
|
||||
|----------|----------|----------|
|
||||
| **a-stock-trading-assistant** | A 股实时交易助手 | 查行情、个股分析、买卖点建议 |
|
||||
| **daily-stock-analysis** | 每日分析报告 | 每日收盘后自动生成分析报告 |
|
||||
| **stock-monitor-skill** | 智能监控预警 | 7 大预警规则,实时推送提醒 |
|
||||
|
||||
---
|
||||
|
||||
## 1️⃣ A 股股票交易助手 (a-stock-trading-assistant)
|
||||
|
||||
### 🎯 功能定位
|
||||
专业 A 股交易助手,提供实时行情、个股分析、大盘情绪、热点板块、交易策略等全方位服务。
|
||||
|
||||
### 📊 支持市场
|
||||
| 代码前缀 | 市场 | 示例 |
|
||||
|----------|------|------|
|
||||
| 60xxxx | 上交所主板 | 600519 贵州茅台 |
|
||||
| 00xxxx | 深交所主板 | 000001 平安银行 |
|
||||
| 30xxxx | 创业板 | 300750 宁德时代 |
|
||||
| 68xxxx | 科创板 | 688981 中芯国际 |
|
||||
|
||||
### 💡 核心功能
|
||||
|
||||
#### 1. 实时行情查询
|
||||
```bash
|
||||
# 查询单只股票
|
||||
python3 scripts/fetch_stock.py --code 600519
|
||||
|
||||
# 查询大盘指数
|
||||
python3 scripts/fetch_stock.py --index
|
||||
|
||||
# 查询热点板块
|
||||
python3 scripts/fetch_stock.py --hot-sectors
|
||||
```
|
||||
|
||||
**输出内容:**
|
||||
- 当前价、涨跌幅、涨跌额
|
||||
- 成交量、成交额、换手率
|
||||
- 振幅、52 周高/低
|
||||
- 分时走势摘要
|
||||
|
||||
#### 2. 个股综合分析
|
||||
- **技术面**:均线系统、趋势判断、支撑/压力位、MACD/KDJ 信号
|
||||
- **基本面**:PE/PB 估值、近期业绩、行业地位、风险点
|
||||
- **综合判断**:看多/看空/中性
|
||||
|
||||
#### 3. 大盘情绪与风险判断
|
||||
- 大盘强弱(趋势、量能、板块轮动)
|
||||
- 市场情绪指数(赚钱效应、涨跌比)
|
||||
- 风险等级(低/中/高)及应对建议
|
||||
|
||||
#### 4. 热点板块与龙头股
|
||||
- 识别主线板块(连续性强)
|
||||
- 识别情绪板块(短期热点)
|
||||
- 列出核心龙头股
|
||||
|
||||
#### 5. 交易策略建议
|
||||
```
|
||||
【操作建议】XX 股(XXXXXX)
|
||||
方向:做多/观望/回避
|
||||
入场区间:XX.XX - XX.XX 元
|
||||
止损位:XX.XX 元(跌破离场)
|
||||
止盈位:XX.XX 元(分批减仓)
|
||||
仓位:XX%(轻/中/重仓)
|
||||
逻辑:[核心理由 2-3 条]
|
||||
风险:[主要风险 1-2 条]
|
||||
```
|
||||
|
||||
#### 6. 价格预警监控
|
||||
- 记录目标价、预警条件到 watchlist.md
|
||||
- 配合券商 App 实时推送
|
||||
|
||||
### 🗣️ 使用示例
|
||||
```
|
||||
用户:贵州茅台现在多少钱?
|
||||
用户:分析一下宁德时代的技术面
|
||||
用户:今天大盘情绪怎么样?
|
||||
用户:最近有什么热点板块?
|
||||
用户:给我看看 600519 的买卖点建议
|
||||
```
|
||||
|
||||
### ⚠️ 注意事项
|
||||
- 数据标注来源和获取时间(精确到分钟)
|
||||
- 所有价格建议附风险提示
|
||||
- 避免绝对化表述("必涨"/"稳赚")
|
||||
- 数字精确到小数点后 2 位
|
||||
|
||||
---
|
||||
|
||||
## 2️⃣ 每日股票分析 (daily-stock-analysis)
|
||||
|
||||
### 🎯 功能定位
|
||||
每日收盘后自动生成股票分析报告,包含次日收盘价预测、历史预测准确率追踪、自我进化机制。
|
||||
|
||||
### 📁 报告存储
|
||||
- **路径**:`<working_directory>/daily-stock-analysis/reports/`
|
||||
- **文件名**:`YYYY-MM-DD-<TICKER>-analysis.md`
|
||||
- **版本控制**:同一天同一只股票自动生成 `-v2`、`-v3` 版本
|
||||
|
||||
### 💡 核心功能
|
||||
|
||||
#### 1. 预测与回顾
|
||||
- **pred_close_t1**:预测次日收盘价
|
||||
- **prev_pred_close_t1**:上次预测的收盘价
|
||||
- **prev_actual_close_t1**:实际收盘价
|
||||
- **AE/APE**:预测误差/误差百分比
|
||||
|
||||
#### 2. 滚动准确率追踪
|
||||
```bash
|
||||
# 计算滚动准确率
|
||||
python3 scripts/calc_accuracy.py \
|
||||
--workdir <working_directory> \
|
||||
--ticker <TICKER> \
|
||||
--windows 1,3,7,30 \
|
||||
--history-limit 60
|
||||
```
|
||||
|
||||
#### 3. 自我进化机制
|
||||
每次分析包含 1-3 个 `improvement_actions`,从近期预测失误中学习,用于下一次分析。
|
||||
|
||||
### 🗓️ 调度建议
|
||||
设置为**工作日每天 10:00** 运行,保持预测 - 回顾窗口连续。
|
||||
|
||||
### 📄 报告模板
|
||||
```markdown
|
||||
# <TICKER> 每日分析 - YYYY-MM-DD
|
||||
|
||||
## 推荐建议
|
||||
recommendation: 买入/持有/卖出
|
||||
|
||||
## 价格预测
|
||||
pred_close_t1: XX.XX 元
|
||||
|
||||
## 历史预测回顾
|
||||
prev_pred_close_t1: XX.XX 元
|
||||
prev_actual_close_t1: XX.XX 元
|
||||
AE: X.XX | APE: X.XX%
|
||||
|
||||
## 滚动准确率
|
||||
1 日准确率:XX%
|
||||
7 日准确率:XX%
|
||||
|
||||
## 改进措施
|
||||
1. [具体改进行动]
|
||||
2. [具体改进行动]
|
||||
```
|
||||
|
||||
### ⚠️ 合规声明
|
||||
每份报告必须附加:
|
||||
> "本内容仅供研究和参考,不构成投资建议或收益保证。市场有风险,投资需谨慎。"
|
||||
|
||||
---
|
||||
|
||||
## 3️⃣ 股票监控预警 (stock-monitor-skill)
|
||||
|
||||
### 🎯 功能定位
|
||||
全功能智能股票监控预警系统,7 大预警规则,实时推送提醒,符合中国投资者习惯(红涨绿跌)。
|
||||
|
||||
### 🚨 七大预警规则
|
||||
|
||||
| 规则 | 触发条件 | 权重 |
|
||||
|------|----------|------|
|
||||
| **成本百分比** | 盈利 +15% / 亏损 -12% | ⭐⭐⭐ |
|
||||
| **日内涨跌幅** | 个股±4% / ETF±2% / 黄金±2.5% | ⭐⭐ |
|
||||
| **成交量异动** | 放量>2 倍均量 / 缩量<0.5 倍 | ⭐⭐ |
|
||||
| **均线金叉/死叉** | MA5 上穿/下穿 MA10 | ⭐⭐⭐ |
|
||||
| **RSI 超买超卖** | RSI>70 超买 / RSI<30 超卖 | ⭐⭐ |
|
||||
| **跳空缺口** | 向上/向下跳空>1% | ⭐⭐ |
|
||||
| **动态止盈** | 盈利 10%+ 后回撤 5%/10% | ⭐⭐⭐ |
|
||||
|
||||
### 📊 分级预警系统
|
||||
- **🚨 紧急级**:多条件共振(如:放量 + 均线金叉 + 突破成本)
|
||||
- **⚠️ 警告级**:2 个条件触发(如:RSI 超卖 + 放量)
|
||||
- **📢 提醒级**:单一条件触发
|
||||
|
||||
### 🚀 运行方式
|
||||
|
||||
#### 后台常驻进程
|
||||
```bash
|
||||
cd ~/workspace/skills/stock-monitor/scripts
|
||||
./control.sh start # 启动
|
||||
./control.sh status # 查看状态
|
||||
./control.sh log # 查看日志
|
||||
./control.sh stop # 停止
|
||||
```
|
||||
|
||||
### ⚡ 智能监控频率(北京时间)
|
||||
|
||||
| 时间段 | 频率 | 监控标的 |
|
||||
|--------|------|----------|
|
||||
| 交易时间 9:30-15:00 | 每 5 分钟 | 全部 + 技术指标 |
|
||||
| 午休 11:30-13:00 | 每 10 分钟 | 全部 |
|
||||
| 收盘后 15:00-24:00 | 每 30 分钟 | 全部(日线数据) |
|
||||
| 凌晨 0:00-9:30 | 每 1 小时 | 仅伦敦金 |
|
||||
| 周末 | 每 1 小时 | 仅伦敦金 |
|
||||
|
||||
### 📋 监控配置示例
|
||||
|
||||
```python
|
||||
{
|
||||
"code": "600362",
|
||||
"name": "江西铜业",
|
||||
"type": "individual", # 个股
|
||||
"market": "sh",
|
||||
"cost": 57.00, # 持仓成本
|
||||
"alerts": {
|
||||
# 1. 成本百分比
|
||||
"cost_pct_above": 15.0, # 盈利 15% 提醒
|
||||
"cost_pct_below": -12.0, # 亏损 12% 提醒
|
||||
|
||||
# 2. 日内涨跌幅
|
||||
"change_pct_above": 4.0,
|
||||
"change_pct_below": -4.0,
|
||||
|
||||
# 3. 成交量异动
|
||||
"volume_surge": 2.0, # 放量>2 倍
|
||||
|
||||
# 4-7. 技术指标
|
||||
"ma_monitor": True, # 均线金叉死叉
|
||||
"rsi_monitor": True, # RSI 超买超卖
|
||||
"gap_monitor": True, # 跳空缺口
|
||||
"trailing_stop": True # 动态止盈
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🔔 预警消息示例
|
||||
|
||||
#### 🚨 紧急级(多条件共振)
|
||||
```
|
||||
🚨【紧急】🔴 江西铜业 (600362)
|
||||
━━━━━━━━━━━━━━━━━━━━
|
||||
💰 当前价格:¥65.50 (+15.0%)
|
||||
📊 持仓成本:¥57.00 | 盈亏:🔴+14.9%
|
||||
|
||||
🎯 触发预警 (3 项):
|
||||
• 🎯 盈利 15% (目标价 ¥65.55)
|
||||
• 🌟 均线金叉 (MA5¥63.2 上穿 MA10¥62.8)
|
||||
• 📊 放量 2.5 倍 (5 日均量)
|
||||
|
||||
💡 建议:多条件共振,趋势强劲,可考虑继续持有或分批减仓。
|
||||
```
|
||||
|
||||
#### ⚠️ 警告级
|
||||
```
|
||||
⚠️【警告】🟢 恒生医疗 (159892)
|
||||
━━━━━━━━━━━━━━━━━━━━
|
||||
💰 当前价格:¥0.72 (-10.0%)
|
||||
|
||||
🎯 触发预警 (2 项):
|
||||
• 📉 日内大跌 -10.0%
|
||||
• ❄️ RSI 超卖 (28.5),可能反弹
|
||||
|
||||
💡 建议:短期超跌严重,RSI 进入超卖区,关注反弹机会但勿急于抄底。
|
||||
```
|
||||
|
||||
### 🛠️ 自定义配置
|
||||
|
||||
#### 修改成本价
|
||||
```python
|
||||
"cost": 55.50, # 改成你的实际成本
|
||||
```
|
||||
|
||||
#### 调整预警阈值
|
||||
```python
|
||||
"cost_pct_above": 20.0, # 盈利 20% 提醒
|
||||
"cost_pct_below": -15.0, # 亏损 15% 提醒
|
||||
"change_pct_above": 5.0, # 日内异动±5%
|
||||
"volume_surge": 3.0, # 放量 3 倍提醒
|
||||
```
|
||||
|
||||
#### 开关技术指标
|
||||
```python
|
||||
"ma_monitor": False, # 关闭均线
|
||||
"rsi_monitor": True, # 开启 RSI
|
||||
"gap_monitor": True, # 开启跳空
|
||||
```
|
||||
|
||||
### ⚠️ 使用提示
|
||||
1. **技术指标有滞后性**:均线、MACD 等用于确认趋势而非预测
|
||||
2. **避免过度交易**:预警只是参考,不要每个信号都操作
|
||||
3. **多条件共振更可靠**:单一指标容易假信号
|
||||
4. **动态止盈要灵活**:回撤 5% 减仓、10% 清仓是建议,根据市场调整
|
||||
|
||||
---
|
||||
|
||||
## 🔧 技能安装与管理
|
||||
|
||||
### 安装技能
|
||||
```bash
|
||||
clawhub install a-stock-trading-assistant
|
||||
clawhub install daily-stock-analysis
|
||||
clawhub install stock-monitor-skill
|
||||
```
|
||||
|
||||
### 查看已安装技能
|
||||
```bash
|
||||
ls ~/.openclaw/workspace/skills/ | grep stock
|
||||
```
|
||||
|
||||
### 更新技能
|
||||
```bash
|
||||
clawhub update a-stock-trading-assistant
|
||||
clawhub update daily-stock-analysis
|
||||
clawhub update stock-monitor-skill
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 常见问题
|
||||
|
||||
### Q1: 数据源从哪里来?
|
||||
- **a-stock-trading-assistant**:东方财富、新浪财经、同花顺、雪球
|
||||
- **daily-stock-analysis**:Yahoo Finance + 官方披露
|
||||
- **stock-monitor-skill**:实时行情 API
|
||||
|
||||
### Q2: 支持港股和美股吗?
|
||||
- **a-stock-trading-assistant**:仅支持 A 股
|
||||
- **daily-stock-analysis**:支持全球股市
|
||||
- **stock-monitor-skill**:主要支持 A 股,可配置港股/美股
|
||||
|
||||
### Q3: 预警怎么推送?
|
||||
- 后台常驻进程运行 `monitor_daemon.py`
|
||||
- 可配置微信、钉钉、飞书等推送渠道
|
||||
- 建议配合券商 App 使用
|
||||
|
||||
### Q4: 预测准确率怎么样?
|
||||
- 运行 `calc_accuracy.py` 查看滚动准确率
|
||||
- 1 日/3 日/7 日/30 日准确率分别统计
|
||||
- 自我进化机制持续提升
|
||||
|
||||
---
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
| 日期 | 更新内容 |
|
||||
|------|----------|
|
||||
| 2026-03-13 | 三大技能使用手册首次整理 |
|
||||
|
||||
---
|
||||
|
||||
*文档由皮皮虾整理 🦐 | 投资有风险,入市需谨慎*
|
||||
Reference in New Issue
Block a user