基于DataFrame实现RSI指标计算的技术求助
修正后的多股票RSI计算方案
先明确RSI的核心计算逻辑:
- 14天平均涨幅(Avg Gain):窗口内所有正日涨幅的平均值(下跌日计为0)
- 14天平均跌幅(Avg Loss):窗口内所有负日跌幅的绝对值的平均值(上涨日计为0)
- RSI = 100 - (100 / (1 + (Avg Gain / Avg Loss)))
针对你的多股票处理场景,直接看修正后的可运行代码:
import pandas as pd import yfinance as yf stocklist = ["^SPX", "^DJI"] myStart = "2023-01-01" # 替换成你的起始日期 myEnd = "2024-01-01" # 替换成你的结束日期 d = {} for name in stocklist: # 获取并整理单只股票数据 data = yf.Ticker(name).history(start=myStart, end=myEnd) df = pd.DataFrame(data) # 计算日涨跌幅(当日收盘价-前一日收盘价) df["Daily Gain"] = df["Close"].diff() # 拆分上涨/下跌幅度:上涨日保留涨幅,否则为0;下跌日保留跌幅绝对值,否则为0 df["Up"] = df["Daily Gain"].apply(lambda x: x if x > 0 else 0) df["Down"] = df["Daily Gain"].apply(lambda x: abs(x) if x < 0 else 0) # 计算14天滚动平均涨幅/跌幅 df["Avg Gain"] = df["Up"].rolling(window=14).mean() df["Avg Loss"] = df["Down"].rolling(window=14).mean() # 计算RSI,处理平均跌幅为0的极端情况(避免除以0) df["RSI"] = 100 - (100 / (1 + df["Avg Gain"] / df["Avg Loss"].replace(0, float('inf')))) # 添加股票代码前缀,避免多股票列名冲突 df = df.add_prefix(f"{name}_") d[name] = df # 拼接所有股票的计算结果 modelData = pd.concat(d.values(), axis=1)
关键问题修正说明
- 解决第一种方法的报错:你之前错误地对整个DataFrame做滚动平均,现在改为针对拆分后的
Up/Down列单独计算,避免了"Daily Gain是列表"的错误。 - 替代无效的apply函数:用lambda直接处理单条日涨跌幅数据,同时结合滚动窗口实现14天平均逻辑,比你之前只返回单个正收益的函数更完整。
- 极端情况处理:用
replace(0, float('inf'))处理14天全上涨的情况,此时RSI会自动计算为100,符合指标定义。
可选:RSI平滑计算方式
如果需要使用更标准的RSI平滑算法(后续窗口用前一期平均×13 + 当期值再÷14),可以替换滚动平均部分为:
# 初始14天用简单平均 df["Avg Gain"] = df["Up"].rolling(window=14).mean() df["Avg Loss"] = df["Down"].rolling(window=14).mean() # 从第15天开始应用平滑公式 for i in range(14, len(df)): df.loc[df.index[i], "Avg Gain"] = (df["Avg Gain"].iloc[i-1] * 13 + df["Up"].iloc[i]) / 14 df.loc[df.index[i], "Avg Loss"] = (df["Avg Loss"].iloc[i-1] * 13 + df["Down"].iloc[i]) / 14
内容的提问来源于stack exchange,提问作者Trav
相关产品推荐
相关产品推荐

