97 lines
3.4 KiB
Python
97 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""hk_flow_collector.py — 港股个股资金流采集(补12维面板 flow5/flow1)
|
||
|
||
数据源:东财 push2delay 港股资金流接口(secid=116.{code},已验证可用)
|
||
https://push2delay.eastmoney.com/api/qt/stock/fflow/kline/get?secid=116.00700&klt=101&lmt=60
|
||
klines 格式: ["2026-08-14,主力流入,主力流出"]
|
||
写入:hk_flow_daily 表(code/date/flow_in/flow_out,主力资金流)
|
||
调度:每日盘后(资金流刷新)
|
||
限速:0.3s/只,620只约5分钟。
|
||
"""
|
||
import json
|
||
import sqlite3
|
||
import sys
|
||
import time
|
||
import urllib.request
|
||
|
||
# ── 消息通道统一路由(broadcast/xmpp by delivery) ──
|
||
try:
|
||
from messenger import install_stdio_hook as _msh
|
||
_msh()
|
||
except Exception:
|
||
pass
|
||
|
||
DB_PATH = "/home/hmo/MoFin/data/mofin.db"
|
||
UA = "Mozilla/5.0"
|
||
SLEEP = 0.3
|
||
DAYS = 60 # 拉60日资金流(够 flow5/flow1)
|
||
|
||
|
||
def fetch_hk_flow(code, days=DAYS):
|
||
"""东财港股个股资金流历史(每日主力流入/流出,万元)"""
|
||
url = (f"https://push2delay.eastmoney.com/api/qt/stock/fflow/kline/get?"
|
||
f"lmt={days}&klt=101&secid=116.{code}&fields1=f1,f2,f3&fields2=f51,f52,f53")
|
||
req = urllib.request.Request(url, headers={"User-Agent": UA})
|
||
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
|
||
with opener.open(req, timeout=15) as r:
|
||
text = r.read().decode("utf-8", errors="replace")
|
||
data = json.loads(text)
|
||
klines = (data.get("data") or {}).get("klines") or []
|
||
out = []
|
||
for k in klines:
|
||
parts = k.split(",")
|
||
if len(parts) < 3:
|
||
continue
|
||
try:
|
||
out.append((parts[0], float(parts[1]), float(parts[2])))
|
||
except (ValueError, TypeError):
|
||
pass
|
||
return out
|
||
|
||
|
||
def main():
|
||
conn = sqlite3.connect(DB_PATH, timeout=30)
|
||
conn.execute("PRAGMA busy_timeout=30000")
|
||
conn.execute("""
|
||
CREATE TABLE IF NOT EXISTS hk_flow_daily (
|
||
code TEXT NOT NULL, date TEXT NOT NULL,
|
||
flow_in REAL, flow_out REAL,
|
||
PRIMARY KEY (code, date)
|
||
)""")
|
||
codes = [r[0] for r in conn.execute(
|
||
"SELECT code FROM hk_connect_stocks WHERE is_active=1 ORDER BY code").fetchall()]
|
||
print(f"港股资金流采集:{len(codes)} 只 × {DAYS} 日", flush=True)
|
||
|
||
ok = fail = 0
|
||
t0 = time.time()
|
||
for idx, code in enumerate(codes):
|
||
try:
|
||
rows = fetch_hk_flow(code)
|
||
if not rows:
|
||
fail += 1
|
||
continue
|
||
for d, fin, fout in rows:
|
||
conn.execute(
|
||
"INSERT OR REPLACE INTO hk_flow_daily (code, date, flow_in, flow_out) "
|
||
"VALUES (?,?,?,?)", (code, d, fin, fout))
|
||
ok += 1
|
||
if (idx + 1) % 100 == 0:
|
||
conn.commit()
|
||
print(f" [{idx+1}/{len(codes)}] ok={ok} fail={fail} | {time.time()-t0:.0f}s", flush=True)
|
||
except Exception as e:
|
||
fail += 1
|
||
if fail <= 5:
|
||
print(f" FAIL {code}: {str(e)[:60]}", flush=True)
|
||
time.sleep(SLEEP)
|
||
conn.commit()
|
||
n = conn.execute("SELECT COUNT(*), COUNT(DISTINCT code) FROM hk_flow_daily").fetchone()
|
||
conn.close()
|
||
print(f"\n完成:ok={ok} fail={fail} 耗时{time.time()-t0:.0f}s", flush=True)
|
||
print(f"hk_flow_daily: {n[0]} 条, {n[1]} 只", flush=True)
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|