diff --git a/scripts/candidate_filter.py b/scripts/candidate_filter.py index 76034b7a..e1b8cd56 100644 --- a/scripts/candidate_filter.py +++ b/scripts/candidate_filter.py @@ -168,49 +168,56 @@ def stage3_technical(code, name, klines): # ── Stage 4: 资金性质分析 ── def stage4_capital_flow(code, name): - """第四关:资金流向 - 东方财富资金流API - """ + """第四关:资金性质(从腾讯实时行情提取外盘/内盘比)""" raw = str(code).strip() if raw.startswith(("6", "9")): - secid = f"1.{raw}" + prefix = "sh" elif raw.startswith(("0", "3")): - secid = f"0.{raw}" + prefix = "sz" else: return False, 0, "非A股" - url = (f"https://push2his.eastmoney.com/api/qt/stock/fflow/daykline/get?" - f"secid={secid}&fields1=f1,f2,f3&fields2=f51,f52,f53,f54,f55&lmt=3") + import subprocess as _sp + url = f"http://qt.gtimg.cn/q={prefix}{raw}" try: - import subprocess as _sp - curl_cmd = ["curl", "-s", "-H", "Referer: https://quote.eastmoney.com/", - "-H", "User-Agent: Mozilla/5.0", url] - r = _sp.run(curl_cmd, capture_output=True, text=True, timeout=15) - data = json.loads(r.stdout) - klines = data.get("data", {}).get("klines", []) - if not klines: - return False, 0, "无资金流数据" + r = _sp.run(["curl", "-s", url], capture_output=True, timeout=10) + text = r.stdout.decode("gbk", errors="ignore") + parts = text.split("~") + if len(parts) < 40: + return False, 0, "数据不足" + + # 腾讯字段:[7]=外盘(主动买,股),[8]=内盘(主动卖,股) + try: + outer = int(float(parts[7])) if parts[7] else 0 # 外盘 + inner = int(float(parts[8])) if parts[8] else 0 # 内盘 + except: + return False, 0, "解析失败" + + if outer <= 0 or inner <= 0: + return False, 0, "无盘口数据" score = 0 + ratio = outer / inner if inner > 0 else 1 checks = [] - for k in klines: - parts = k.split(",") - if len(parts) >= 5: - # 超大单净流入 - net_inflow = float(parts[4]) if parts[4] else 0 - if net_inflow > 0: - score += 1 - if score >= 2: - checks.append("多日资金净流入") - elif score >= 1: - checks.append("有资金流入迹象") + if ratio > 1.3: + score += 2 + checks.append(f"外/内={ratio:.2f}") + elif ratio > 1.0: + score += 1 + checks.append(f"买稍强{ratio:.2f}") else: - checks.append("资金流出") + checks.append(f"卖稍强{ratio:.2f}") + + # 绝对量也说明资金活跃度 + total = outer + inner + if total > 50000000: # >5000万股 + score += 1 + checks.append(f"活跃{total/10000:.0f}万") return score >= 1, score, "; ".join(checks) except: - return False, 0, "资金流接口失败" + return False, 0, "接口失败" # ── Stage 5: 基本面 ──