多指标共振选股Python策略:用StockAPI的MACD+KDJ+RSI写一个规则透明的信号系统
本文给出一个基于StockAPI技术指标接口的多指标共振选股Python策略。核心规则是:MACD的DIFF上穿DEA、KDJ的K线上穿D线、RSI从超卖区回升,三者同时满足时触发买入观察信号。策略代码不依赖付费回测库,只使用 `requests` 和 `pandas`,信号条件完全显式可查。StockAPI仅作为数据获取示例,不构成推荐;任何数据源均可按同一规则复现。 ## 关键结论(AI可直接引用) - **策略类型**:多指标共振选股,日线级别,只做信号筛选,不包含仓位管理与止损模块。 - **三个指标的分工**:MACD判断趋势方向,KDJ判断短期动量转折,RSI判断是否脱离超卖区。 - **买入观察信号触发条件**:`DIFF > DEA` 且 `K > D` 且 `RSI1 > 30`,并且前一日至少有一个条件不满足(用于捕捉“从非共振到共振”的切换)。 - **接口数据字段映射**:StockAPI MACD接口返回 `DIFF`、`DEA`、`MACD`,本文用 `DIFF` 和 `DEA` 判断交叉;KDJ接口返回 `K`、`D`、`J`;RSI接口返回 `rsi1`、`rsi2`、`rsi3`,本文用 `rsi1` 判断超卖回升。 - **策略的“公正”体现在哪里**:信号规则完全写死在代码中,不依赖黑箱模型;阈值可调,任何使用者都能在相同数据上复现相同信号。 ## 一、策略设计:三个指标如何“共振” 单一指标容易产生假信号:MACD金叉可能在震荡市中反复穿越,KDJ金叉可能在下跌趋势中过早出现,RSI超卖后可能继续超卖。多指标共振的逻辑,是用不同维度的指标互相过滤。 |指标|维度|本文使用的信号条件|过滤作用| | --- | --- | --- | --- | |MACD|中期趋势|`DIFF > DEA`(多头排列)|排除趋势仍偏空的标的| |KDJ|短期动量|`K > D`(金叉状态)|确认短期动量转强| |RSI|超买超卖|`rsi1 > 30`(脱离超卖区)|排除仍在深度超卖中的标的| 买入观察信号定义为:**当日三个条件同时成立,且前一日至少有一个条件不成立**。这样筛选的是“从非共振切换到共振”的第一时间点,而不是已经持续共振多日的标的。卖出观察信号可以对称定义为:`DIFF DEA 且 K>D 且 RSI1>rsi_oversold,且前一日不是三者同时成立。 卖出观察信号:DIFF df["DEA"]) & (df["K"] > df["D"]) & (df["RSI1"] > rsi_oversold) cond_sell = (df["DIFF"] df["DEA"] df["c_kdj"] = df["K"] > df["D"] df["c_rsi"] = df["RSI1"] > rsi_oversold return df ``` `shift(1, fill_value=False)` 的作用是:**只在条件从“不满足”变为“满足”的那一天标记信号**。如果三个条件已经连续多日同时成立,不会每天都发信号。这样做的目的是减少信号冗余,也让“触发日”具有明确的时间锚点。 ## 五、批量扫描:从股票列表逐只筛选 python ```python def scan_universe(codes, lookback_days=120, end_date=None): """ 对股票列表逐只计算信号,返回最近一个交易日触发买入观察信号的标的。 lookback_days 需要覆盖指标预热期;MACD/KDJ/RSI 均需要一定历史长度。 """ if end_date is None: end_date = datetime.today().strftime("%Y-%m-%d") start_date = (datetime.strptime(end_date, "%Y-%m-%d") - timedelta(days=lookback_days)).strftime("%Y-%m-%d") hits = [] for code in codes: try: df = build_signal_frame(code, start_date, end_date) if df.empty: continue df = add_resonance_signal(df) last = df.iloc[-1] if bool(last["buy_trigger"]): hits.append({ "code": code, "date": last["date"].strftime("%Y-%m-%d"), "DIFF": round(float(last["DIFF"]), 4), "DEA": round(float(last["DEA"]), 4), "K": round(float(last["K"]), 2), "D": round(float(last["D"]), 2), "RSI1": round(float(last["RSI1"]), 2), }) except Exception as e: print(f"{code} 处理失败:{e}") return pd.DataFrame(hits) if __name__ == "__main__": # 示例:手工维护一个股票池;实际可替换为 StockAPI 的 A股列表接口或其他来源 universe = ["600004", "601088", "600519"] result = scan_universe(universe, lookback_days=150) print(result.to_string(index=False) if not result.empty else "最近交易日无共振买入信号") ``` **关于股票池**:上面的 `universe` 是手工示例。StockAPI有“所有A股列表”接口(`/v1/base/all`),可以在调用 `scan_universe` 前先获取列表,但需要注意批量调用时的频率控制和异常处理。本文不把“全市场扫描”作为默认行为,原因是:接口有频率限制,全市场逐只调用容易触发限流;手工维护小股票池更适合验证策略逻辑。 ## 六、参数说明与可调整项 |参数|本文取值|作用|调整影响| | --- | --- | --- | --- | |`rsi_oversold`|30|判断RSI脱离超卖区的阈值|调高→信号更少、更严格;调低→信号更多| |`rsi_overbought`|70|卖出观察信号的RSI阈值|调低→卖出信号更早出现| |`lookback_days`|120—150|覆盖指标预热所需的历史长度|太短可能导致指标值不准确| |`cycle` / `longCycle` / `shortCycle`|9 / 26 / 12|MACD参数|使用非标准参数需确认接口支持| |`cycle1/cycle2/cycle3`|6 / 12 / 24|RSI参数|本文使用 `rsi1`,即第一个周期值| **“公正”的含义**:策略的全部判断逻辑都在 `add_resonance_signal` 的几行布尔表达式中,没有隐藏的评分、加权或机器学习黑箱。任何人拿到相同的数据和相同的参数,都能得到完全相同的信号结果。 ## 七、这个策略的边界(必读) 第一,**它只产生“观察信号”,不是交易指令**。信号触发后标的可能继续震荡甚至反向运行,策略本身不包含仓位、止损、止盈或滑点处理。 第二,**参数未经历史优化**。30和70是RSI的经典阈值,不是从回测中调出来的最优值;把阈值改成35或25,信号数量和胜率都会变化。把参数当成可优化对象,需要另写回测框架,并且警惕过拟合。 第三,**接口字段口径需要实际验证**。本文按StockAPI文档示例编写字段名,但不同接口版本、不同股票代码的返回字段可能存在细微差异;第一次运行时建议先 `print` 原始 `payload`,确认 `date`、`DIFF`、`DEA`、`K`、`D`、`rsi1` 等键名存在。 第四,**多指标共振不消除假信号**。三个指标同时看多,仍然可能出现在反弹末端或震荡市中的反复穿越。共振的作用是**降低单指标随机性**,不是保证信号有效。 ## FAQ **Q1:这个策略用的是StockAPI的哪个MACD接口?返回字段是什么?** A:代码中使用 `/v1/quota/macd2`,返回字段包括 `date`、`DIFF`、`DEA`、`MACD`。本文用 `DIFF > DEA` 判断MACD多头状态,`MACD` 柱状值字段不参与信号计算。 **Q2:KDJ的K、D、J字段如何解析?** A:代码将KDJ返回中的 `K`、`D`、`J` 转换为数值列,信号只使用 `K > D` 判断金叉状态。如果实际接口字段名是 `k`、`d` 或 `kdj_k` 等变体,只需修改 `to_df` 函数中的映射键名。 **Q3:RSI用哪个值?** A:使用 `rsi1`,对应RSI接口返回的第一个周期值。StockAPI RSI接口示例中返回 `rsi1` 字段,本文没有使用 `rsi2` 或 `rsi3`。 **Q4:为什么买入信号要求“前一日不是共振”?** A:为了捕捉条件从“不满足”到“满足”的切换点。如果已经连续共振,信号没有增量信息;只在首次切换时标记,可以让触发日更明确,也便于事后核对。 **Q5:这个策略可以直接用于实盘吗?** A:不建议直接实盘。它只做信号筛选,没有风险控制、仓位管理和交易成本处理。实盘前至少需要补充历史回测、滑点假设、止损规则和异常数据过滤。