数学口径¶
以下规则在全包范围内成立。本页给出每个数字的确切算法,用于核对口径而非推导理论。
通用记号:
| 记号 | 含义 |
|---|---|
| \(r_1, \dots, r_n\) | 一维简单收益序列,即逐期组合收益;NaN 在进入指标前已剔除 |
| \(n\) | 期数 |
| \(P\) | 每年期数(analyzer.periods_per_year) |
| \(h\) | 一期的长度(engine.forward_return.horizon) |
| \(\bar r\) | 序列均值 \(\frac{1}{n}\sum_{t=1}^{n} r_t\) |
收益口径¶
截面加权只用简单收益
组合收益为 \(\sum_i w_i r_i\),其中 \(r_i\) 是简单收益。绝不在截面上平均对数收益——对数收益的 加权平均不等于组合的对数收益,跨资产平均会引入系统性偏差。
对数刻度只是可视化层的选择,不影响任何指标的计算。
实现收益¶
取价格口径(forward_return.source = "prices")时,逐资产计算纯价格收益:
该口径与 alpha 自身的预测期解耦——因子预测多久是因子的事,收益测多长单独声明。取信号口径
(= "signals")时直接使用信号自带的 fwd_ret 列,工具包不做任何再加工。
一期有多长¶
\(h\) 是全包唯一一处定义「一期有多长」的地方,为必填项。三处同时以它为准:前视收益的测量窗口、
日频基准的复利窗口、holding_days 未给出时的继承值。
它的单位则由 input.frequency 决定:日度口径下数交易日,月度口径下数自然月。月度口径的
close 取各月最后一个可用收盘价,因此上式中的 \(t\) 与 \(t+h\) 指的是两个月份的月末,而不是面板上
相隔 \(h\) 行的两条记录。
engine.holding_days 仅用于年化折算,不改变任何一期收益的测量方式。两者显式不等时发出
HoldingPeriodWarning。
调仓间隔应与测量期相等
input.calendar.rebalance_freq 与 \(h\) 不等时,相邻两期的持有窗口会重叠或留下空仓缺口:
- 间隔 < 测量期:窗口互相重叠,逐期累乘会把同一段行情重复计入
- 间隔 > 测量期:期间存在空仓缺口
两种情况下由累乘得到的 total_equity 与 max_drawdown 均失真。引擎就此告警但不拦截,
因为重叠窗口下的信息系数仍有分析价值。
年化因子¶
\(P\) 显式给出时直接采用,否则由持有期推导:
月频面板沿用默认的日度口径会让 \(P\) 偏离 21 倍,且不触发告警。
指标¶
summary 表中每一行是一个 (signal_model, bucket, weight) 组合,以下各式作用于该行对应的收益序列。
ann_ret —— 年化收益¶
算术年化,不是复合年化
该指标是逐期收益的算术平均乘以每年期数,不是 \(E_n^{P/n} - 1\)。后者是单独的指标
cagr。
两者可以相差很多,方向由 \(P\) 与波动共同决定:复利的凸性把结果往上推
(\((1+\bar r)^P - 1 > \bar r P\)),波动拖累把它往下拉(约 \(\sigma^2/2\))。月频面板
(\(P = 12\))上凸性通常占上风,cagr 明显高于 ann_ret;日频面板(\(P = 252\))上单期收益
极小,两者接近,波动大时 cagr 反而更低。
同一张 summary 里 ann_ret 走算术口径、total_equity 与 cagr 走几何累乘,
不可互相反推。对照外部文献的绩效表前先确认对方报的是哪一种:不少论文的 Ann. Ret. 是
cagr 口径,而 Sharpe 仍按算术口径算,因此表内 \(\mathrm{SR} \neq \mathrm{AnnRet} / \mathrm{AnnVol}\)。
cagr —— 复合年化收益¶
净值按简单收益逐期累乘后折回年度复合增长率,与 total_equity 同一套口径,只是换算成年率。
期末净值跌破 0 时无定义,返回 NaN。
该指标假设每期收益首尾相接、盈亏滚动再投入,因此只在 rebalance_freq 与 \(h\) 相等时有意义;
两者不等会触发 HoldingPeriodWarning,此时 cagr 与 total_equity、max_drawdown 一同失真。
ann_vol —— 年化波动¶
样本标准差(\(\mathrm{ddof} = 1\))。序列长度小于 2 时返回 NaN。
sharpe —— 夏普比率¶
\(r_f\)(analyzer.risk_free_rate)直接作用于年化收益,因此应填年化无风险利率。ann_vol
非有限或不为正时返回 NaN。
max_drawdown —— 最大回撤¶
取值为负数或 0,即全程最低点相对此前峰值的跌幅。
total_equity —— 期末净值¶
起点为 1.0 的净值终值,几何累乘口径。
n_periods —— 期数¶
该行实际参与指标计算的期数。某个桶在部分期上成分不足 min_names 时,其 \(n\) 会小于调仓日历长度。
曲线¶
两条曲线并列存在于 curves 表中,图表按类型选用其一。对数刻度是可视化选择,不构成另一套收益口径。
裁剪与原点¶
进入曲线计算前,收益按 analyzer.curves.clip_lower(默认 \(-0.99\))做下限裁剪:
防止单期 −100% 以下的异常值把净值打到 0 或负数后再也无法恢复。该裁剪只作用于曲线,不影响
summary 中的指标。
每条曲线前置一个零点(\(\mathrm{equity} = 1\)、\(\mathrm{cumlogret} = 0\)),横坐标取最早一期的前一个
工作日。analyzer.curves.shared_origin 打开时(默认)所有曲线共用同一原点,使不同起始期的序列
在图上可比。
诊断¶
turnover —— 换手率¶
相邻两期成分集合 \(S_t\) 与 \(S_{t-1}\) 的 Jaccard 距离:
多空的成分取多头端与空头端的并集后再算。首期无前一期可比,记 NaN。summary 中的
turnover 是逐期值的算术平均。
该定义衡量的是成分名单的变动比例,与权重变化无关——等权与市值加权在同一分位桶上得到相同的换手率。
ic_mean —— 信息系数¶
每期截面内 alpha 与实现收益的 Spearman 相关,即两者秩的 Pearson 相关:
截面有效样本数低于 analyzer.diagnostics.ic_min_names(默认 20)时该期记 NaN。ic_mean 按信号
分组,与桶和加权方案无关——因此同一信号的所有行共享同一个 ic_mean。
波动率缩放¶
analyzer.vol_rescale 打开后,每条收益序列乘以一个常数,使其全样本波动率对齐目标序列:
三条性质:
- 缩放系数是全样本单一常数,不随时间变化,因此不改变曲线形状
- 不改变夏普比率——分子分母同比例缩放
- 目标序列自身不缩放(\(c = 1\))
有效样本数低于 min_periods(默认 20)时该序列的标准差记 NaN,此时系数退化为 1,即不缩放。
整体替换,不是并列输出
打开该开关后,summary 与 curves 全部基于缩放后的序列。工具包不会同时给出缩放前后两套口径。
加权¶
每期每桶的组合收益为成分收益的加权和:
等权¶
桶内成分数为 0 时该桶收益记 NaN。
市值加权¶
缺市值或市值非正的成分权重记 0,等价于剔除后重新归一。
为何裁掉非正市值
不裁负值会让分母变小甚至跨零,权重随之出现杠杆与反向暴露。市值合计不为正时该桶收益记 NaN。
基准¶
基准一律由使用者声明(配置中的 input.references,backtest() 的 references= 参数),包内不
附带市场指数数据,也不存在绕过声明直接绘制的基准曲线。
frequency = "daily" 的序列按日收益 \(\rho_u\) 在持有窗口上复利,\(a_t\) 为第 \(t\) 期的调仓锚点,
\(\ell\) 为 reference_lag:
窗口长度取 \(h\) 而非 holding_days——基准与组合必须测同一个窗口才可比。frequency = "period"
的序列已是周期收益,直接按调仓日历对齐。
月度口径(input.frequency = "monthly")下窗口两端都取自然月末——起点为锚点所在月的月末,末端
为其后第 \(h\) 个月的月末,\(\ell = 1\) 时为左开右闭、\(\ell = 0\) 时为左闭右开;period 序列按自然月
对齐。组合那一期测的是月末收盘到月末收盘,逐日推算会在两端各错一截。
因此基准与组合走同一套周期化口径:rebalance_freq 与 \(h\) 不等时,基准同样受重叠持有期或空仓
缺口影响,不是一条独立于调仓节奏的买入持有曲线。
一条 references 会对每个加权方案各复制一行,因此 summary 中同一基准在 EW 与 VW 两行上取值
相同——基准序列本身与组合的加权方案无关。