You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用Python ta库计算RSI时结果随起始位置变化?

问题

我有一个DataFrame,想要基于Close列以14为窗口计算RSI,代码如下:

from ta.momentum import RSIIndicator
import pandas as pd

data = pd.read_csv()
output = RSIIndicator(data.Close, 14).rsi()
print(output.head(20))

得到的RSI结果如下:

0           NaN
1           NaN
2           NaN
3           NaN
4           NaN
5           NaN
6           NaN
7           NaN
8           NaN
9           NaN
10          NaN
11          NaN
12          NaN
13    30.565576
14    30.565576
15    30.565576
16    36.847817
17    53.471152
18    53.471152
19    59.140918

但当我从任意其他位置开始计算,例如使用data.iloc[1:]时,我理解由于偏移了1个位置,原13索引会变为NaN,RSI从14索引开始,但为何结果值会改变?

window = 14
t = RSIIndicator(data.Close.iloc[1:], window).rsi()
print(t.head(20))

输出结果:

1           NaN
2           NaN
3           NaN
4           NaN
5           NaN
6           NaN
7           NaN
8           NaN
9           NaN
10          NaN
11          NaN
12          NaN
13          NaN
14    31.481498
15    31.481498
16    37.849374
17    54.534367
18    54.534367
19    60.171078
20    44.372719

RSI不是只需要前14个值吗?为何缺少最旧的第15个值会导致结果变化?这对我实时计算RSI很重要,我希望新数据到来时,仅传入前14个数据点就能得到下一个RSI值,但现在似乎必须传入完整数据集。

回答

核心原因是ta库的RSIIndicator默认用**平滑移动平均(EMA)**计算平均涨跌幅,而非简单移动平均(SMA)。EMA是带权重的计算方式,初始阶段会用到序列开头到当前窗口的所有历史数据,不是只取最近14个。当你砍掉原始序列的第一个数据点(用data.iloc[1:]),EMA的初始计算基础完全改变,后续所有RSI值自然会跟着变化。

针对你的实时计算需求,有两个可行方案:

1. 改用简单移动平均(SMA)实现RSI

SMA仅依赖最近N个周期的数据,完全符合你“只传前14个点算下一个RSI”的需求,手动实现代码如下:

def calculate_rsi_sma(prices, window=14):
    deltas = prices.diff()
    # 分离上涨和下跌幅度
    gains = deltas.where(deltas > 0, 0)
    losses = -deltas.where(deltas < 0, 0)
    
    # 用滚动窗口计算简单平均涨跌幅
    avg_gain = gains.rolling(window=window, min_periods=window).mean()
    avg_loss = losses.rolling(window=window, min_periods=window).mean()
    
    rs = avg_gain / avg_loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

# 测试:切片前后对应位置的RSI值会一致(仅索引偏移)
rsi_full = calculate_rsi_sma(data.Close, 14)
rsi_slice = calculate_rsi_sma(data.Close.iloc[1:], 14)

2. 保留EMA逻辑但维护滚动状态

如果一定要用EMA版本的RSI,不能每次切片从头计算,必须维护历史序列的状态:

# 初始化:先传入前14个数据建立初始EMA状态
historical_prices = data.Close.iloc[:14].copy()
rsi_indicator = RSIIndicator(historical_prices, 14)
initial_rsi = rsi_indicator.rsi()

# 实时更新:新数据到来时追加到历史序列后
new_price = data.Close.iloc[14]
historical_prices = pd.concat([historical_prices, pd.Series([new_price])])
# 取最新的RSI值
current_rsi = RSIIndicator(historical_prices, 14).rsi().iloc[-1]

简单总结:

  • 你看到的数值差异是因为ta的RSI用了EMA,依赖全部历史数据计算初始值
  • 实时计算要轻量化,优先选SMA版本的RSI,仅需最近N个数据点
  • 坚持用EMA的话,必须维护完整的历史滚动序列,不能切片从头算

内容的提问来源于stack exchange,提问作者bcsta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 16:00:59