累计 PnL 零交叉次数:回测净值曲线的符号翻转计数
Cumulative PnL Zero-Crossings: Count Sign Flips of the Backtest Equity Curve
开始编码实现 solution(returns: list[float]) -> int。给定一段长度为 N 的逐期收益流 returns,构造累计 PnL 路径 P[i] = sum(returns[0..i]),并统计该路径穿越零的符号翻转次数。
一次交叉是指 P 的符号在严格正与严格负之间发生切换;P 等于零的样本应当被跳过而不是单独计一次。具体地:扫描 P[0], P[1], ..., P[N-1] 中所有非零样本的符号序列,答案为该过滤后子序列里相邻不同符号的对数。
示例:solution([1.0, -2.0, 2.0, -2.0, 2.0]) 返回 4。累计路径为 P = [1, -1, 1, -1, 1],非零符号序列为 +, -, +, -, +,相邻发生 4 次符号切换。
需明确的若干细节:solution([]) 返回 0;solution([1.0, -1.0, 1.0]) 对应 P = [1, 0, 1],跨过 0 但跳过零之后两侧都是 +,因此答案为 0;solution([1.0, -1.0, 0.0, 0.0, 1.0, -2.0]) 对应 P = [1, 0, 0, 0, 1, -1],非零符号为 +, +, -,答案为 1。
朴素的 O(N^2) 双重循环每次在下标区间上重新累加 returns 在小样本下没问题,但在隐藏的大用例下会超时。预期解法是单趟线性扫描:维护当前累计和、上一个非零符号、以及整数计数器。
实现细节由 stubs/stub.py 提供。
实践背景
在回测报告中,累计 PnL 曲线的"零交叉次数"是快速衡量策略颠簸程度的一个诊断指标:净值线反复穿越起点的策略往往在交易成本里被磨损殆尽,更像是被噪声触发的伪信号而不是被捕捉到的某个 regime。研究侧会在 walk-forward 多折切片之间、或同一组合内不同标的之间对比这个计数,挑出那种平均收益虽然为正但起点穿越次数过多、在真实滑点下很可能完全失效的策略。把"踩到 0"的样本当成跳过而不是翻转之所以重要,是因为实盘净值在预热阶段、空仓日尾盘以及任何再平衡检查点都会停在 0 上——这些都不是 regime 切换,不该被计入翻转次数。
约束条件
- 0 <= N <= 1500,其中 N 为 solution(returns) 的输入长度
- 每个 returns[i] 为 [-1000.0, 1000.0] 区间内的有限 float
- 空输入返回 0
- 累计路径 P[i] = sum(returns[0..i]) 从 P[0] = returns[0] 开始,按 0-based 处理;不在前面再补一个 P[-1] = 0
- 输出为非负整数,使用精确比对
样例
Case 1 · statement-example: P=[1,-1,1,-1,1] gives 4 crossings
输入: [[1,-2,2,-2,2]]
期望: 4
累积 PnL 序列 P=[1,-1,1,-1,1],相邻非零符号 +,-,+,-,+ 之间发生 4 次符号切换。
Case 2 · visible: P=[1,0,1] (touches zero, no crossing)
输入: [[1,-1,1]]
期望: 0
P=[1,0,1],跨过 0 但前后非零符号都是 +,没有方向反转,结果 0。
Case 3 · visible: P=[1,0,0,0,1,-1] gives 1
输入: [[1,-1,0,0,1,-2]]
期望: 1
P=[1,0,0,0,1,-1];最后一个非零符号在 -1 处由 + 翻到 -,记一次。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: P=[1,-1,1,-1,1] gives 4 crossings
输入: [[1,-2,2,-2,2]]
期望: 4
累积 PnL 序列 P=[1,-1,1,-1,1],相邻非零符号 +,-,+,-,+ 之间发生 4 次符号切换。
Case 2 · visible: P=[1,0,1] (touches zero, no crossing)
输入: [[1,-1,1]]
期望: 0
P=[1,0,1],跨过 0 但前后非零符号都是 +,没有方向反转,结果 0。
Case 3 · visible: P=[1,0,0,0,1,-1] gives 1
输入: [[1,-1,0,0,1,-2]]
期望: 1
P=[1,0,0,0,1,-1];最后一个非零符号在 -1 处由 + 翻到 -,记一次。