Files
big-qmt/labs/analysis/etf/check_candidates.py
2026-09-21 12:38:13 +08:00

81 lines
2.6 KiB
Python

"""校验候选 ETF 在策略数据源上有足够日线(策略要求 >=61 根,这里按最新 120 根缓存)。
用法: py -3.14 -B labs/analysis/etf/check_candidates.py
"""
import json
import sys
import urllib.request
from datetime import datetime, date
from pathlib import Path
HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
try:
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
except Exception:
pass
from backtest import DAILY_URL, CACHE # noqa: E402
CANDIDATES = {
"AI": "159819.SZ",
"CPO": "515880.SH",
"PCB": "159732.SZ",
"人形机器人": "562500.SH",
"": "515790.SH",
"创新药": "159992.SZ",
"半导体": "588200.SH",
"存储": "588750.SH",
"半导体材料": "588160.SH",
"玻璃基板": "159745.SZ",
"电力": "159326.SZ",
"航空航天": "159227.SZ",
"金属": "518880.SH",
"金融": "512880.SH",
"能源": "515220.SH",
"宽基(保留)": "510300.SH",
}
def probe(code: str) -> dict:
request = urllib.request.Request(
f"{DAILY_URL}?code={code}",
headers={"User-Agent": "Mozilla/5.0"},
)
with urllib.request.urlopen(request, timeout=30) as response:
rows = json.load(response)
if not isinstance(rows, list) or not rows:
return {"bars": 0}
CACHE.mkdir(parents=True, exist_ok=True)
(CACHE / f"{code}.json").write_text(json.dumps(rows), encoding="utf-8")
bars = sorted(rows, key=lambda r: str(r["trade_date"]))
closes = [float(b["close"]) for b in bars]
return {
"bars": len(bars),
"first": str(bars[0]["trade_date"]),
"last": str(bars[-1]["trade_date"]),
"close": closes[-1],
"min": min(closes),
"max": max(closes),
}
print(f"{'板块':12} {'代码':11} {'根数':>5} {'首日':>9} {'末日':>9} {'最新价':>8} {'区间低':>8} {'区间高':>8} 判定")
ok = True
for sector, code in CANDIDATES.items():
try:
info = probe(code)
except Exception as exc:
print(f"{sector:12} {code:11} 抓取失败:{exc}")
ok = False
continue
bars = info.get("bars", 0)
verdict = "OK" if bars >= 61 else ("不足 61 根 → 策略会跳过" if bars else "无数据 → 策略会跳过")
if bars < 61:
ok = False
print(f"{sector:12} {code:11} {bars:5} {str(info.get('first','-')):>9} {str(info.get('last','-')):>9} "
f"{info.get('close', 0):8.3f} {info.get('min', 0):8.3f} {info.get('max', 0):8.3f} {verdict}")
print()
print("全部可用" if ok else "存在数据不足的标的,需替换或接受其被跳过")