滚动平均线默认右对齐,金融场景需左对齐(用shift(1))或居中(center=true);rsi计算须设ewm(alpha=1/14, adjust=false);复权价慎用ffill,优先limit=1或业务标识插值;groupby后应直接链式调用rolling等向量化方法而非apply。

用 rolling() 计算移动平均线时,窗口对齐方式容易出错
默认 rolling(window=5) 是右对齐(即当前行包含自身及前4个值),但金融场景常需左对齐或居中——比如计算“过去5日均价”应不含当日,否则会引入未来信息。解决方法是配合 shift() 或设置 center=True。
- 右对齐(默认):
df['ma5'] = df['close'].rolling(5).mean()—— 第5行才开始有值 - 左对齐(不含当前):
df['ma5_lag'] = df['close'].rolling(5).mean().shift(1) - 居中对齐(第3行为中心):
df['ma5_center'] = df['close'].rolling(5, center=True).mean()—— 首尾两行是NaN
注意:shift(1) 后首5行全为 NaN,回测时若未过滤会导致信号误发。
计算RSI时,ewm() 和手动实现的衰减系数不一致
RSI依赖14日平均涨跌幅,标准做法是用指数加权(Wilders平滑),等价于 alpha=1/14 的 ewm(),但 Pandas 默认 adjust=True 会引入偏差。必须显式设 adjust=False 才与TradingView等平台一致。
- 正确写法:
gain.ewm(alpha=1/14, adjust=False).mean() - 错误写法:
gain.ewm(span=14)—— 默认adjust=True,初始权重分配不同 - 验证点:对纯上涨序列
[1,1,1,...],第14期 Wilders 均值应为1;用adjust=True会略小于1
处理复权价格时,fillna(method='ffill') 可能掩盖除权缺口
从接口拉取的前复权价本身已连续,但若混用后复权+前复权数据,或自行拼接历史数据,ffill() 会把除权日的跳空直接抹平,导致收益率计算失真。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
- 先检查是否有真实缺失:
df['price'].isna().sum(),再决定是否填充 - 若确需填充且知悉是除权日,优先用
limit=1控制最多前向填充1行:df['price'].fillna(method='ffill', limit=1) - 更安全的做法:用业务标识列(如
ex_date)定位除权日,单独插值或保持NaN
一个典型坑:用 ffill() 处理月线数据时,若某月无交易,填充会跨月拉平,使月收益率恒为0。
groupby().apply() 在多股票指标计算中性能断崖下降
对千只股票逐个算MACD,用 df.groupby('symbol').apply(lambda x: calc_macd(x)) 看似简洁,但Python层循环+重复索引开销极大。Pandas原生向量化操作(如 rolling()、diff())在分组后仍有效,应优先利用。
- 高效写法:先排序
df.sort_values(['symbol', 'date'], inplace=True),再用groupby('symbol')['close'].rolling(12).ema()—— Pandas 1.4+ 支持分组后滚动 - 避免 apply + 自定义函数,除非逻辑无法向量化(如动态窗口长度)
- 内存敏感时,用
chunksize分批读取CSV,而非一次性 load 全量再 groupby
真正卡住的往往不是公式本身,而是没意识到 rolling() 在 groupby 下也能批量并行计算——这点文档里藏得深,但实测提速5倍以上。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










