perf(metrics): rolling alpha/beta 向量化(O(n²)→O(n),治分钟级卡死)
CI/CD / test (push) Successful in 10s
CI/CD / nas-deploy (push) Successful in 29s
CI/CD / nas-verify (push) Successful in 5s

compute_metrics rolling alpha/beta 原 for 循环每点 iloc[:i+1].cov/var = O(n²)。日线 111 天没事,分钟级 daily_df(万行)卡死(cta_c287f4b5 卡 5min CPU88%)。改 pandas expanding 向量化(cov/var/mean O(n)),数值与原循环一致(beta/alpha diff<1e-15,NaN 位置匹配)。pytest 6 绿。触发:b2c41c7 降级让 compute_metrics 首次在 benchmark 有数据时真跑(此前 benchmark 空被 skip),暴露 rolling O(n²) 性能 bug。
This commit is contained in:
2026-08-02 20:54:50 +08:00
parent b2c41c73b8
commit 2ff8ecaf52
+7 -9
View File
@@ -69,15 +69,13 @@ def compute_metrics(
equity = empyrical.cum_returns(s)
bench_curve = empyrical.cum_returns(b)
# rolling alpha/beta (expanding window 用于画图,口径由 scalars 保证)
roll_beta = pd.Series(index=s.index, dtype=float)
roll_alpha = pd.Series(index=s.index, dtype=float)
for i in range(len(s)):
sub = aligned.iloc[: i + 1]
if len(sub) >= 2 and sub["b"].var() > 0:
beta = sub["s"].cov(sub["b"]) / sub["b"].var()
alpha = sub["s"].mean() - beta * sub["b"].mean()
roll_beta.iloc[i] = beta
roll_alpha.iloc[i] = alpha * period
# 向量化 expanding (O(n)) 替代原 for 循环 (O(n²))——分钟级 daily_df(万行)原循环卡死
# (cta_c287f4b5 卡 5min CPU88% 根因)。expanding.cov/.var/.mean 数值与原循环一致
# (ddof=1)var_b<=0(含单点 NaN)处 beta=NaN,与原 len>=2 且 var>0 守卫等价。
cov_sb = aligned["s"].expanding().cov(aligned["b"])
var_b = aligned["b"].expanding().var()
roll_beta = cov_sb / var_b.where(var_b > 0)
roll_alpha = (aligned["s"].expanding().mean() - roll_beta * aligned["b"].expanding().mean()) * period
# drawdown: 从峰值回落 (值 <= 0)
cummax = equity.cummax()
drawdown = (equity - cummax) / cummax