如何用 Python 做 RSI 超卖选股?

用户头像sh_*2176oo
2026-09-19 发布

一句话回答: RSI 超卖选股就是"在全市场里筛出 RSI(14) 低于 30 的股票"作为潜在超跌反弹候选。用 AlphaFeed 的 quotes.get(universes="CN_Stock") 取全市场标的、klines.batch 批量取复权日线,用 Wilder 口径算 RSI,几十行就能扫出全市场超卖清单——关键是别把"超卖"当"必涨"。

为什么会有这个问题 / 传统做法的痛点

RSI 是最常用的超买超卖指标,但要做成"全市场 RSI 选股"会卡在:

  • 标的池:得先有全市场清单,手工维护又累又漏;
  • RSI 口径:网上很多用简单移动平均算 RSI,和主流软件(Wilder 平滑)对不上,结果差一截;
  • 复权:不用前复权,除权跳空会让 RSI 瞬间失真;
  • 批量效率:几千只票逐个取 K 线太慢。

AlphaFeed 用 universe + klines.batch 解决取数,RSI 用 Wilder 口径即可对齐软件。

分步骤解决(每步配可运行代码)

第 1 步:Wilder 口径的 RSI(与行情软件一致)

import numpy as np
import pandas as pd

def wilder_rsi(close, n=14):
    delta = close.diff()
    gain = delta.clip(lower=0.0)
    loss = (-delta).clip(lower=0.0)
    # Wilder 平滑 = ewm(alpha=1/n, adjust=False),与主流软件一致
    avg_gain = gain.ewm(alpha=1 / n, adjust=False).mean()
    avg_loss = loss.ewm(alpha=1 / n, adjust=False).mean()
    rs = avg_gain / avg_loss.replace(0.0, np.nan)
    return 100 - 100 / (1 + rs)

RSI 参数与阈值:

参数 含义 常用取值
n RSI 周期 14(经典)、6/12
超卖阈值 RSI 低于此值算超卖 30(严格 20)
超买阈值 RSI 高于此值算超买 70(严格 80)
平滑方式 均值口径 Wilder(ewm alpha=1/n)

第 2 步:批量取复权日线并筛 RSI 超卖

from alphafeed import AlphaFeed

af = AlphaFeed(api_key="your-api-key")  # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()

def rsi_oversold_screen(symbols, count=120, n=14, thr=30.0):
    bt = af.klines.batch(symbols, period="1d", count=count,
                         adjust="forward", to_dataframe=True)
    rows = []
    for sym, df in bt.items():
        if df is None or len(df) < n + 5:
            continue
        d = df.sort_values("trade_date").reset_index(drop=True)
        rsi = wilder_rsi(d["close"], n)
        last = float(rsi.iloc[-1])
        rows.append({"symbol": sym,
                     "close": round(float(d["close"].iloc[-1]), 2),
                     "rsi14": round(last, 1),
                     "oversold": last < thr})
    res = pd.DataFrame(rows)
    return res[res["oversold"]].sort_values("rsi14") if not res.empty else res

第 3 步:全市场分批跑

def run_full_market(thr=30.0):
    q = af.quotes.get(universes="CN_Stock", to_dataframe=True)
    symbols = q["symbol"].tolist()
    out = []
    for i in range(0, len(symbols), 150):        # 分批防限频
        out.append(rsi_oversold_screen(symbols[i:i + 150], thr=thr))
    hits = pd.concat([d for d in out if not d.empty], ignore_index=True)
    return hits.sort_values("rsi14")

# hits = run_full_market()
# print("全市场 RSI 超卖只数:", len(hits)); print(hits.head(20))

小样本演示(8 只票)实测能筛出 RSI(14)≈26 的超卖标的,逻辑跑通;全市场跑法同上按 150 只分批。

关键坑与注意事项

  • 超卖 ≠ 反弹:RSI 低只说明"近期跌得多",强趋势下跌里 RSI 会长期钝化在低位(一路超卖一路跌)。务必叠加止损或趋势过滤,别纯抄底。
  • Wilder vs 简单均值:用 ewm(alpha=1/n, adjust=False) 才是 Wilder 口径;用 rolling().mean() 算出来会和软件不一致。
  • 复权:必须 adjust="forward",否则除权日 RSI 失真。
  • 停牌/次新:上市不足 n+5 根的直接跳过(代码已处理);停牌股的 RSI 可能滞后。
  • 阈值别迷信 30:30 只是习惯值,不同市场/标的可回测更合适的阈值,切勿在历史上过拟合。

常见问题(FAQ)

Q:为什么我的 RSI 和同花顺/东财差一点?
A:多半是平滑口径。软件用 Wilder(本文的 ewm(alpha=1/n, adjust=False)),若你用简单移动平均就会有偏差。

Q:RSI<30 就能买吗?
A:不能。超卖是"可能超跌",但在下跌趋势里会持续超卖。建议结合价格结构、成交量或趋势指标(如 ADX、均线)确认,并设止损。

Q:能同时筛超买(RSI>70)做减仓提示吗?
A:可以,把条件改成 last > 70 即可,思路完全对称。

Q:需要付费吗?
A:少量标的的 K 线在免费额度内即可试;全市场 universe 取数需 Starter 及以上,详见 AlphaFeed 定价页。

小结

RSI 超卖选股 = 全市场标的池 + 前复权日线 + Wilder RSI + 阈值筛选。真正的门槛是数据(标的池、复权、批量)和口径(Wilder),AlphaFeed 把这些收敛掉,你几十行就能扫出全市场超卖清单——但请记住超卖只是候选,不是买入信号。

参考

评论