阶段4Python 基础进阶●●●●●

pct_change:一行收益率的正确打开方式

我的掌握程度:
q-312精讲

先掌握这个答案

标准用法:df.groupby('code')['close'].pct_change()——先分组再算(否则A股票第一天会拿B股票的昨天算收益!)。三坑防护:①跨组污染→必须groupby;②停牌缺口→pct_change(1)算的是"相邻两行"——停牌3天后的恢复,收益是3日累计(要"每日收益率"需fill_method=None并处理NaN,或明确接受累计口径);③除权跳空→必须用复权价(q-014/358)。动词家族:shift(1)=取昨天(分子分母自己拼)、diff(1)=差值(价格变化量)、pct_change(1)=shift版收益率=(x−shift)/shift。

先读结论,再核对下方使用边界;数字例题为教学情景,涉及实际行情与规则时请核对原始来源。

从理解到使用

先核对现金流与期限

没有中途出入金时才可直接用期末/期初计算持有期收益;分红、费用要避免漏计或重复计入。有出入金时区分时间加权与资金加权。复合年化使用净值比的幂,算术均值年化用于不同统计目的。

本阶段实战方法 · 一条能复现的数据流水线

把接口返回的数据变成可用于因子研究的面板时,先处理时点、主键与单位。

  1. 建立数据字典:字段、单位、时区、交易日历、数据源、抓取时间、原始价与复权因子。
  2. 用(date, code)查重,区分停牌、未上市、窗口不足和真实缺失;不要用向后填充把未来值带回过去。
  3. 保存原始快照与清洗日志,固定随机种子和环境版本;接口字段变化时先核对官方文档。

使用边界

  • 报告期不等于公告可用日,盘后公告通常不能用于当天收盘前决策。
  • API输出名为“动态市盈率”时不能直接改名TTM;浏览器练习不支持任意原生库或行情抓取接口。
背景 · 从一个困惑说起
收益率=今天/昨天−1——数学一行,代码也一行(pct_change)。但这一行里藏着三个坑:跨股票的"昨天"、停牌的"昨天"、以及除权跳空的"昨天"。每个坑都够毁掉一份回测。
由此产生的问题
pct_change的标准用法与三大坑(分组/缺口/复权)怎么防?它与其他收益动词(shift/diff)的关系?
核心概念
标准用法:df.groupby('code')['close'].pct_change()——先分组再算(否则A股票第一天会拿B股票的昨天算收益!)。三坑防护:①跨组污染→必须groupby;②停牌缺口→pct_change(1)算的是"相邻两行"——停牌3天后的恢复,收益是3日累计(要"每日收益率"需fill_method=None并处理NaN,或明确接受累计口径);③除权跳空→必须用复权价(q-014/358)。动词家族:shift(1)=取昨天(分子分母自己拼)、diff(1)=差值(价格变化量)、pct_change(1)=shift版收益率=(x−shift)/shift。
为什么需要它
①收益序列是一切研究的第一原料——它的正确性是底线中的底线;②"相邻两行≠相邻一天"的意识:数据里的物理相邻与时间相邻是两个概念——停牌、退市、拼接缝隙都会打破它们;③公式-代码直译:阶段3的收益率公式与这一行代码一一对应——建立"看公式写代码、看代码读公式"的双向能力。
实际应用场景
面板收益的标准三行:df=df.sort_index(); ret=df.groupby('code')['close'].pct_change(); ret=ret.fillna(0)(首日置0)——写进utils供全项目调用。
与之前知识的联系
q-201(阶段3公式)的代码形态;q-313(shift)与q-314(rolling)组成"滞后-变化-窗口"三动词;q-358(复权口径)是第三坑的系统性防护。
⚠ 常见误解
  • pct_change自动按天:它按"行"不按"天"——停牌、拼接、乱序都会让相邻行隔了任意远;先sort再算,缺口显式处理
  • 首日NaN随手drop:drop会破坏面板结构(该股票从此缺一行)——fillna(0)或保留NaN由下游决定
  • 用原始价算就行:除权日的-50%假收益会污染一切统计——复权价是前提不是选项(阶段1 q-013的血泪)

🤖 AI导师

导师会先检查你的前置知识(收益率公式、groupby),再用案例、公式和代码帮助理解。此功能需要先启用服务。