正确计算移动平均线需先用rolling(window=...)构建窗口再调用mean(),window为整数或时间字符串(如'20D'),min_periods控制NaN数量,索引须为排序后的DatetimeIndex;EMA用ewm(span=)实现;多指标用agg()一次性计算。

用 rolling() 计算移动平均线,别直接套 mean()
移动平均线本质是窗口内均值,但直接对 Series 调用 mean() 不会生效——它没指定窗口。必须先用 rolling(window=...) 构建滚动窗口对象,再链式调用 mean()、std() 等聚合方法。
常见错误:写成 df['close'].mean().rolling(20)(顺序反了),或漏掉 min_periods 导致开头一堆 NaN。
-
window是整数,表示向前包含的期数(含当前行),比如rolling(20)表示 20 日均线 -
min_periods设为1可让首日就有值(用单日数据计算),设为None或不填则默认等于window,前window-1行全为NaN - 时间序列若未按时间排序,
rolling()仍按行序计算,不是按时间顺序——务必先用sort_index()或set_index('date').sort_index()
示例:
df['ma_20'] = df['close'].rolling(window=20, min_periods=1).mean()
处理非等距时间序列:用 rolling('20D') 替代固定行数
股价数据常有节假日缺失,固定 20 行 ≠ 20 个交易日。这时该用基于时间偏移的窗口,如 '20D'(20 天)、'3M'(3 个月)。
立即学习“Python免费学习笔记(深入)”;
前提:索引必须是 DatetimeIndex,且数据已按时间升序排列。否则 rolling('20D') 会静默失效,结果和 rolling(20) 一样。
-
'20D'包含当前时刻往前推 20 天内的所有数据点,不管中间有多少空值或缺失日期 - 注意单位大小写:
'20d'无效,必须大写'D';'20h'、'7D'、'1M'都合法 - 性能略低于固定窗口,尤其数据量大时,因需对每行重新定位时间范围
示例:
df.index = pd.to_datetime(df.index)<br>df = df.sort_index()<br>df['ma_20d'] = df['close'].rolling('20D').mean()
ewm() 计算指数加权移动平均(EMA),权重衰减更合理
传统 MA 对窗口外数据突然截断,EMA 用衰减系数让历史数据平滑影响递减,更符合金融场景直觉。Pandas 中用 ewm() 实现,核心参数是 span 或 alpha。
别混淆 span 和窗口长度:20 日 EMA 的 span=20,对应衰减系数 alpha = 2/(span+1) ≈ 0.095,不是简单除以 20。
-
adjust=True(默认)让权重归一化,更稳定;False则按原始指数公式,早期值影响略小 -
ignore_na=True(默认)跳过NaN计算,适合含缺失值的行情数据 - EMA 结果无前置
NaN(首行即有值),但首几项受初始化方式影响,和主流交易软件可能差 1–2 位小数
示例:
df['ema_20'] = df['close'].ewm(span=20, adjust=True).mean()
多个指标一次性计算:避免重复遍历,用 agg() 合并操作
如果同时要算 MA、标准差、最大值,别写三行 rolling(...).mean()、.std()、.max()——Pandas 会三次扫描数据,O(3n) 时间复杂度。用 agg() 一次搞定。
注意:agg() 返回的是 DataFrame,列名默认是函数名字符串,需手动重命名或用字典映射。
- 传入列表:
rolling(20).agg(['mean', 'std', 'max'])→ 列名为'mean'、'std'、'max' - 传入字典:
rolling(20).agg({'ma': 'mean', 'volatility': 'std'})→ 自定义列名 - 混合函数与 lambda:
rolling(20).agg({'range': lambda x: x.max() - x.min(), 'count': 'count'})
示例:
stats = df['close'].rolling(20).agg(['mean', 'std'])<br>df['ma_20'] = stats['mean']<br>df['std_20'] = stats['std']
实际跑起来你会发现,rolling('20D') 在跳空日多的 A 股数据里比 rolling(20) 更贴近实盘逻辑,但调试时容易忽略索引类型是否为 DatetimeIndex——一旦是 RangeIndex,带时间单位的窗口就退化成普通整数窗口,还不出错、不报警。


















