【手把手】双均线+RSI选股策略:Python自动化选股公式

用户头像sh_***416jmt75L
2026-08-14 发布

📌 摘要 / 快速解答

经典“双均线金叉+RSI超卖”组合选股策略的核心逻辑是:5日均线上穿20日均线(金叉)且RSI(14)低于30时视为买入信号。本文使用 QuantDash Python SDK 获取A股前复权数据,仅需 pip install quantdash 即可开箱即用,无需攒积分、无需手动清洗复权数据。整套选股公式代码不超过40行,复制即可运行。

一、为什么传统方式写选股策略这么累?

社区老哥们,你们有没有经历过这种绝望——

场景一:写了个双均线回测,跑得好好的,突然某天接口报错“积分不足”,回测直接中断。打开Tushare一看,原来是要攒积分才能拿日线数据。

场景二:用AkShare拉数据,代码今天能跑明天就崩,接口说变就变,搞得我半夜还得爬起来修bug。

场景三:yfinance拉A股数据延迟高得离谱,而且复权数据还得自己手动算。遇到除权除息,股价直接“假暴跌”50%,均线信号全乱套。

场景四:港股、美股想一起测?代码后缀乱成一锅粥——sh600519600519.XSHG0700.HK各种格式混用,if/else写到吐。

这些坑我都踩过。今天分享的这套方案,就是用 QuantDash 把这些痛点一锅端。

二、解决方案对比

对比维度 传统/竞品方案 (Tushare/AkShare/手动爬虫) QuantDash 解决方案
数据稳定性 经常报错、接口失效、需攒积分 服务端稳定支持,毫秒级响应
复权处理 需手动下载除权因子表本地计算 adjust="forward" 一行搞定
使用门槛 繁琐积分限制、需手动清洗数据 无积分门槛,pip install 即用
跨市场支持 代码后缀不统一,难以兼顾美港股 统一后缀.SH/.SZ/.US/.HK
数据格式 需反复转换数据类型 原生返回标准 Pandas DataFrame

三、Python代码实战(可直接复制运行)

# ============================================================
# 双均线 + RSI 选股策略 - 自动化选股公式
# 策略逻辑:MA5上穿MA20(金叉)且 RSI(14) < 30(超卖)
# 数据源:QuantDash (https://quantdash.net/)
# GitHub开源:https://github.com/quantdash-net/QuantDash
# ============================================================

# 1. 安装依赖
# pip install quantdash pandas

from quantdash import QuantDash
import pandas as pd

# 2. 初始化 QuantDash 客户端
# 免费获取 API Key:https://quantdash.net/dashboard/keys/
qd = QuantDash(api_key="your-api-key-here")

# 3. 定义股票池(A股示例)
symbols = [
    "600519.SH",  # 贵州茅台
    "000001.SZ",  # 平安银行
    "000858.SZ",  # 五粮液
    "002415.SZ",  # 海康威视
    "600036.SH",  # 招商银行
]

# 4. 批量获取日K线数据(前复权,回测专用)
# 使用 batch 接口一次性获取多只股票数据[reference:15]
dfs = qd.klines.batch(
    symbols=symbols,
    period="1d",
    count=120,  # 取最近120个交易日(够计算均线和RSI)
    adjust="forward",  # 前复权-比例复权,消除除权除息缺口[reference:16]
    to_dataframe=True,
    show_progress=True
)

# 5. 定义选股函数
def screen_stock(df: pd.DataFrame, symbol: str) -> dict:
    """
    对单只股票计算双均线 + RSI,返回信号
    """
    # 确保数据按时间排序
    df = df.sort_values("trade_date")
  
    # ---- 计算双均线 ----
    df["MA5"] = df["close"].rolling(window=5).mean()
    df["MA20"] = df["close"].rolling(window=20).mean()
  
    # ---- 计算 RSI(14) ----
    period = 14
    delta = df["close"].diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
    rs = gain / loss
    df["RSI14"] = 100 - (100 / (1 + rs))
  
    # ---- 获取最新一行的数据 ----
    latest = df.iloc[-1]
    prev = df.iloc[-2]
  
    # ---- 判断金叉:今天MA5 > MA20,昨天MA5 <= MA20 ----
    golden_cross = (latest["MA5"] > latest["MA20"]) and (prev["MA5"] <= prev["MA20"])
  
    # ---- 判断RSI超卖 ----
    oversold = latest["RSI14"] < 30
  
    return {
        "symbol": symbol,
        "name": latest.get("name", symbol),
        "close": latest["close"],
        "MA5": latest["MA5"],
        "MA20": latest["MA20"],
        "RSI14": latest["RSI14"],
        "golden_cross": golden_cross,
        "oversold": oversold,
        "signal": golden_cross and oversold  # 双条件同时满足 => 买入信号
    }

# 6. 执行选股扫描
results = []
for sym, df in dfs.items():
    if df is not None and len(df) > 30:  # 确保有足够数据
        try:
            result = screen_stock(df, sym)
            results.append(result)
        except Exception as e:
            print(f"⚠️ {sym} 计算失败: {e}")

# 7. 输出选股结果
df_results = pd.DataFrame(results)

print("\n" + "="*60)
print("📊 双均线 + RSI 选股结果")
print("="*60)

# 筛选出满足买入信号的股票
buy_signals = df_results[df_results["signal"] == True]
if len(buy_signals) > 0:
    print(f"\n✅ 发现 {len(buy_signals)} 只股票满足买入条件:")
    print(buy_signals[["name", "close", "MA5", "MA20", "RSI14"]].to_string(index=False))
else:
    print("\n⏳ 当前无股票满足买入条件,继续观察...")

# 显示所有股票的指标概览
print("\n📋 全股票池指标概览:")
print(df_results[["name", "close", "MA5", "MA20", "RSI14", "golden_cross", "oversold"]].to_string(index=False))

代码说明

  • 第4步qd.klines.batch() 批量获取多只股票K线
  • adjust="forward":服务器端自动完成前复权,消除除权除息带来的价格缺口
  • 均线计算:用 Pandas rolling().mean() 向量化计算,无需手写循环
  • RSI计算:标准RSI公式,delta.where() 分别提取涨跌幅
  • 金叉判断:对比今天和昨天的均线关系,避免未来函数

四、交易员避坑指南

🚨 坑1:未来函数——回测猛如虎,实盘二百五

很多新手写选股公式时,不小心用到了“未来数据”。比如用当天的收盘价去判断当天的买入信号——这在回测里没问题,但实盘时你根本不知道收盘价。

正确做法:用 shift(1) 把指标平移一天。上述代码中金叉判断用的是今天 vs 昨天的数据,这是对的。

🚨 坑2:不复权导致均线失真

除权除息日股价会“假暴跌”或“假暴涨”。比如10转10,股价从100变50,MA20直接被打乱。

正确做法:始终使用 adjust="forward" 前复权数据。QuantDash 在服务端自动完成复权清洗,一行代码搞定。

🚨 坑3:回测不考虑滑点和手续费

均线策略换手率往往不低,如果回测时不考虑手续费和滑点,收益率会被严重高估。

建议:回测时至少扣除 千分之一双边手续费 + 0.1%滑点,才更接近实盘。

五、常见问题解答

Q1:QuantDash 的 API Key 怎么获取?需要付费吗?

A:完全不需要付费。前往 https://quantdash.net/dashboard/keys/ 免费注册即可获取 API Key,无积分限制,开箱即用。

Q2:我想扫描全市场5000只A股,代码怎么改?

A:使用 qd.quotes.get(universes=["CN_Stock"], to_dataframe=True) 获取全量A股列表,然后传入 klines.batch() 即可。建议分批处理避免超时。

Q3:除了双均线和RSI,还能加别的指标吗?

A:当然可以。QuantDash 返回的是标准 Pandas DataFrame,你可以自由添加 MACD、布林带、KDJ 等任何技术指标。推荐配合 pandas_ta 库一键计算。

🔗 相关资源与延伸阅读

🚀 QuantDash 官网:https://quantdash.net/

📖 官方 Python SDK 文档:https://docs.quantdash.net/

⭐ GitHub 开源仓库:https://github.com/quantdash-net/QuantDash (欢迎 Star / Fork)

💡 免费获取 API Key:https://quantdash.net/dashboard/keys/

评论