feat: 迁移 trading 相关脚本到 skill 仓库 (第2批: 🟡 中优先级)

【迁移内容】
- dividend-investing/scripts/dca_monitor.py + dca_monitor_us.sh
- dividend-scanner/scripts/scan_cn.{py,sh} + scan_hk.sh + scan_us.sh
- okx-auto-position/scripts/signal_queue_retry.sh
- lottery-hk/scripts/verify_lottery.sh
- longbridge-cli/scripts/longport_http.py (公共模块)

【配套修改】
- 5 个 cron 任务 script 路径更新 (jobs.json):
  - 8929ca09 (DCA港股上午) → dividend-investing/scripts/dca_monitor.py
  - 9469c128 (DCA港股下午) → dividend-investing/scripts/dca_monitor.py
  - 3a4bef2c (DCA美股凌晨) → dividend-investing/scripts/dca_monitor_us.sh
  - a82a3ab0 (signal-queue-retry) → okx-auto-position/scripts/
  - b4868849 (lottery-verify-result) → lottery-hk/scripts/

【删除】本地 ~/.hermes/scripts/{dca_monitor,scan_*,signal_queue_retry,verify_lottery,longport_http}
【未迁移】scan_cn/hk/us 仍需挂 cron, 暂不删 (走 scanner skill)
This commit is contained in:
2026-07-24 11:42:13 +08:00
parent 1877a85cc5
commit 913d1945d4
9 changed files with 640 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""
A股高股息扫描器(LongPort取价 + 预设股息率)
"""
import os, sys, json
from datetime import datetime
# === 读取LongPort环境变量 ===
bashrc = open(os.path.expanduser("~/.bashrc")).read()
for line in bashrc.splitlines():
if line.startswith("export LONGPORT_") or line.startswith("export LONGBRIDGE_"):
parts = line.replace("export ", "").split("=", 1)
if len(parts) == 2:
os.environ[parts[0]] = parts[1].strip('"').strip("'")
from longport import openapi
cfg = openapi.Config.from_env()
ctx = openapi.QuoteContext(config=cfg)
# === A股候选池 ===
A_SHARE_POOL = {
"601088.SH": {"name": "中国神华", "yield": 6.7, "freq": "年+中期", "sector": "煤炭"},
"601328.SH": {"name": "交通银行", "yield": 6.2, "freq": "年度", "sector": "银行"},
"601398.SH": {"name": "工商银行", "yield": 5.9, "freq": "年度", "sector": "银行"},
"601288.SH": {"name": "农业银行", "yield": 5.8, "freq": "年度", "sector": "银行"},
"601939.SH": {"name": "建设银行", "yield": 6.0, "freq": "年度", "sector": "银行"},
"601988.SH": {"name": "中国银行", "yield": 5.7, "freq": "年度", "sector": "银行"},
"600900.SH": {"name": "长江电力", "yield": 3.8, "freq": "年度", "sector": "电力"},
"601857.SH": {"name": "中国石油", "yield": 5.5, "freq": "年度", "sector": "能源"},
"600028.SH": {"name": "中国石化", "yield": 5.2, "freq": "年度", "sector": "能源"},
"601728.SH": {"name": "中国电信", "yield": 4.8, "freq": "年度", "sector": "电信"},
"600036.SH": {"name": "招商银行", "yield": 4.5, "freq": "年度", "sector": "银行"},
"601166.SH": {"name": "兴业银行", "yield": 5.8, "freq": "年度", "sector": "银行"},
"601818.SH": {"name": "光大银行", "yield": 5.9, "freq": "年度", "sector": "银行"},
"600377.SH": {"name": "宁沪高速", "yield": 6.2, "freq": "年度", "sector": "高速"},
"601666.SH": {"name": "平煤股份", "yield": 6.2, "freq": "年度", "sector": "煤炭"},
"600023.SH": {"name": "浙能电力", "yield": 5.5, "freq": "年度", "sector": "电力"},
"000858.SZ": {"name": "五粮液", "yield": 10.5, "freq": "年度", "sector": "白酒"},
"000568.SZ": {"name": "泸州老窖", "yield": 7.0, "freq": "年度", "sector": "白酒"},
"000937.SZ": {"name": "冀中能源", "yield": 11.0, "freq": "年度", "sector": "煤炭"},
"002304.SZ": {"name": "洋河股份", "yield": 10.8, "freq": "年度", "sector": "白酒"},
"000596.SZ": {"name": "古井贡酒", "yield": 6.9, "freq": "年度", "sector": "白酒"},
"000001.SZ": {"name": "平安银行", "yield": 5.4, "freq": "年度", "sector": "银行"},
"600519.SH": {"name": "贵州茅台", "yield": 5.0, "freq": "年+中期", "sector": "白酒"},
}
def scan_a_share():
min_yield = 5.0
tickers = list(A_SHARE_POOL.keys())
all_quotes = {}
# LongPort批量获取A股价格
for i in range(0, len(tickers), 15):
batch = tickers[i:i+15]
try:
quotes = ctx.quote(batch)
for q in quotes:
all_quotes[q.symbol] = {
"price": float(q.last_done),
"prev_close": float(q.prev_close),
}
except Exception as e:
pass
results = []
for sym, info in A_SHARE_POOL.items():
if info["yield"] < min_yield:
continue
q = all_quotes.get(sym)
if q and q["price"] > 0:
change_pct = (q["price"] - q["prev_close"]) / q["prev_close"] * 100 if q["prev_close"] else 0
price = q["price"]
else:
# LongPort没拿到价格,用预设
price = 0
change_pct = 0
results.append({
"symbol": sym, "name": info["name"],
"price": price, "change_pct": change_pct,
"yield": info["yield"], "freq": info["freq"],
"flag": "🇨🇳", "sector": info["sector"],
})
results.sort(key=lambda x: x["yield"], reverse=True)
return results[:10]
def calc_ladder(price):
return [
{"tier": 1, "pct": -3, "price": round(price * 0.97, 2)},
{"tier": 2, "pct": -6, "price": round(price * 0.94, 2)},
{"tier": 3, "pct": -10, "price": round(price * 0.90, 2)},
]
def format_result(results):
now = datetime.now().strftime("%Y-%m-%d %H:%M")
if not results:
return f"🇨🇳 A股高息扫描 | {now}\n\n暂无符合条件的标的(≥5%"
lines = [f"🇨🇳 A股高息TOP | {now}", ""]
for i, r in enumerate(results, 1):
medal = ["🥇", "🥈", "🥉", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟"][min(i-1, 9)]
lines.append(f"{medal} {r['name']} [{r['sector']}]")
lines.append(f" {r['symbol']}")
if r["price"] > 0:
chg = "📈" if r["change_pct"] >= 0 else "📉"
lines.append(f" 💰 现价: {r['price']:.2f} {chg} {r['change_pct']:+.1f}%")
else:
lines.append(f" 💰 价格: 盘后/未获取")
lines.append(f" 📊 股息率: {r['yield']:.1f}% 派息: {r['freq']}")
if r["price"] > 0:
ladder = calc_ladder(r["price"])
lstr = "".join([f"T{l['tier']}:{l['price']:.2f}({l['pct']}%)" for l in ladder])
lines.append(f" 🪜 阶梯: {lstr}")
lines.append("")
lines.append("━━━━━━━━━━━━━")
lines.append(f"📋 共扫描 {len(A_SHARE_POOL)} 只,筛出 {len(results)}")
return "\n".join(lines)
if __name__ == "__main__":
results = scan_a_share()
print(format_result(results))
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cd /home/openclaw/.hermes/scripts
python3 scan_cn.py
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cd /home/openclaw/.hermes/scripts
python3 dca_scanner.py hk
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cd /home/openclaw/.hermes/scripts
python3 dca_scanner.py us