跨 K 路场所成交磁带的 running VWAP 流式计算
Running VWAP Across Merged K-Venue Trade Tapes
开始编码一位交易员的 TCA 仪表盘会消费来自 K 个执行场所的原始成交磁带。每个场所 k(即输入列表 tapes 中从 0 起的下标)落下一条按 timestamp 升序的事件流 tapes[k],每条事件是 [timestamp, price, size],其中 size > 0。每当一条合并事件落入统一磁带时,仪表盘需要给出截至当前所有事件的 running 成交量加权平均价 (VWAP),跨场所统一计算。
请实现 solution(tapes: list[list[list[float]]]) -> list[float]。将所有 venue 合并成单一时间序流——不同 venue 的事件 timestamp 相等时,venue_id 更小者先输出;同一 venue 内部保持输入顺序。处理完合并后第 i 条事件后计算
vwap_i = (j=1..i 求和 price_j * size_j) / (j=1..i 求和 size_j)并将 vwap_i 追加进输出。返回列表的长度 N 等于所有磁带事件总数;第 i 项即第 i 条事件处理完之后的 running VWAP。
边界情况:
tapes == [](即 K = 0)时返回[]。- 某条
tapes[k] == []是合法的,不贡献任何事件、也不贡献任何 VWAP 项。 - 所有磁带都为空时返回
[]。
例
3 条磁带:
tapes = [
[[1.0, 100.5, 10], [3.0, 100.7, 5]],
[[1.0, 200.1, 7], [2.0, 200.2, 3]],
[[2.0, 300.0, 1]],
]合并后的时间序为 venue 0 @ t=1.0、venue 1 @ t=1.0、venue 1 @ t=2.0、venue 2 @ t=2.0、venue 0 @ t=3.0。逐步累计:
- 第 1 条 (price=100.5, size=10):vwap = 1005.0 / 10 = 100.5
- 第 2 条 (price=200.1, size=7): vwap = (1005 + 1400.7) / 17 ≈ 141.5118
- 第 3 条 (price=200.2, size=3): vwap = (1005 + 1400.7 + 600.6) / 20 ≈ 150.315
- 第 4 条 (price=300.0, size=1): vwap = (… + 300.0) / 21 ≈ 157.443
- 第 5 条 (price=100.7, size=5): vwap = (… + 503.5) / 26 ≈ 146.5308
solution(tapes) 即返回这条 5 元素的 running VWAP 列表:
[100.5, 141.51176470588236, 150.315, 157.44285714285714, 146.5307692307692]。
实践背景
跨场所 running VWAP 是合并磁带上的头号 TCA 指标:每打印一笔,台面截至当前在所有场所成交的成交量加权均价是多少?它驱动子单滑点归因、监管基准报送、以及实时的 "我们打过 arrival-VWAP 了吗" 面板。两个实现陷阱使它并不平凡:第一,必须按时间序合并 K 条磁带并采用确定的并列规则——否则同时间戳的 VWAP 在不同运行下会不一致;第二,必须增量维护累加量——每条事件从头重算 VWAP 是 O(N^2),磁带一长就垮。
约束条件
- 0 ≤ len(tapes) ≤ 100;每条磁带长度 0 ≤ len(tapes[k]) ≤ 200;所有磁带事件总数 ≤ 500。算法仍应保持 O(N log K) 复杂度,从而在更大 N 下也能在时限内通过。
- 每条磁带内部按 timestamp 升序预排序;磁带的 venue_id 即其在 `tapes` 中的下标(从 0 起)。
- 每条事件是一个 3 元素列表 `[timestamp, price, size]`:`timestamp` 是非负浮点数,`price` 是正浮点数,`size` 是正整数。
- 当来自不同 venue 的两条事件 timestamp 相等时,venue_id 更小的那条先输出;同一 venue 内部保持输入顺序(不要重排同一 venue 内 timestamp 相等的事件)。
- 输出是长度为 N 的 `list[float]`——第 i 项是消化第 i 条合并事件之后的 running VWAP。比较容差 rel_tol 1e-9、abs_tol 1e-12。
- i 之后的 VWAP 定义为 `(Σ_{j ≤ i} price_j · size_j) / (Σ_{j ≤ i} size_j)`,其中累加范围是合并时间序中前 i 条事件。
- 若 `tapes == []`(即 K = 0)或所有磁带为空则返回 `[]`;空内层磁带不贡献任何事件,也不贡献任何 VWAP 项。
样例
Case 1 · statement-example: three venues with tied timestamps
输入: [[[[1,100.5,10],[3,100.7,5]],[[1,200.1,7],[2,200.2,3]],[[2,300,1]]]]
期望: [100.5,141.51176470588234,150.315,157.44285714285712,146.5307692307692]
题面例题:合并 5 条事件后逐步发布 running VWAP;每一步都是 sum(price*size)/sum(size)。
Case 2 · typical: two venues, fully interleaved, no ties
输入: [[[[0.5,10,1],[1.5,11,2]],[[1,20,3],[2,21,4]]]]
期望: [10,17.5,15.333333333333334,17.6]
两个 venue 完全交错;输出 4 个 running VWAP,依次累计 size 和 price*size。
Case 3 · typical: four venues all at same timestamp, lower venue_id first
输入: [[[[1,10,1]],[[1,20,2]],[[1,30,3]],[[1,40,4]]]]
期望: [10,16.666666666666668,23.333333333333332,30]
四个 venue 同时戳;按 venue_id 升序合并,VWAP 在该步单调累积。
Case 4 · typical: one large-size event dominates running VWAP
输入: [[[[1,100,1]],[[2,200,1000]],[[3,100,1]]]]
期望: [100,199.9000999000999,199.8003992015968]
第二条事件 size 极大,几乎决定后续 running VWAP 接近 200。
Case 5 · adversarial: tied timestamps both within and across venues
输入: [[[[1,10,1],[1,11,1]],[[1,20,2]]]]
期望: [10,10.5,15.25]
同一 venue 内并列时间戳保持原顺序;跨 venue 时按 venue_id 升序。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: three venues with tied timestamps
输入: [[[[1,100.5,10],[3,100.7,5]],[[1,200.1,7],[2,200.2,3]],[[2,300,1]]]]
期望: [100.5,141.51176470588234,150.315,157.44285714285712,146.5307692307692]
题面例题:合并 5 条事件后逐步发布 running VWAP;每一步都是 sum(price*size)/sum(size)。
Case 2 · typical: two venues, fully interleaved, no ties
输入: [[[[0.5,10,1],[1.5,11,2]],[[1,20,3],[2,21,4]]]]
期望: [10,17.5,15.333333333333334,17.6]
两个 venue 完全交错;输出 4 个 running VWAP,依次累计 size 和 price*size。
Case 3 · typical: four venues all at same timestamp, lower venue_id first
输入: [[[[1,10,1]],[[1,20,2]],[[1,30,3]],[[1,40,4]]]]
期望: [10,16.666666666666668,23.333333333333332,30]
四个 venue 同时戳;按 venue_id 升序合并,VWAP 在该步单调累积。
Case 4 · typical: one large-size event dominates running VWAP
输入: [[[[1,100,1]],[[2,200,1000]],[[3,100,1]]]]
期望: [100,199.9000999000999,199.8003992015968]
第二条事件 size 极大,几乎决定后续 running VWAP 接近 200。
Case 5 · adversarial: tied timestamps both within and across venues
输入: [[[[1,10,1],[1,11,1]],[[1,20,2]]]]
期望: [10,10.5,15.25]
同一 venue 内并列时间戳保持原顺序;跨 venue 时按 venue_id 升序。