← 返回编程题库
coding-net-position-from-trade-events中等免费版2000ms未尝试

由原始成交流水计算日终净头寸

End-of-Day Net Positions from a Raw Trade Tape

开始编码

实现 solution(events: list[list]) -> list[list]。给定一段成交流水 events,每条记录形如 [ticker, side, size],其中 side 取值为 "B""S"。处理完整段流水后,返回所有 ticker 的 [ticker, net_position] 配对列表,按 net_position 降序 排在前、相同 net 时再按 ticker 升序(字典序)作为 tiebreak。净头寸恰好为零(买卖正好抵消)的 ticker 必须从输出中剔除

例:solution([["TICK-1", "B", 100], ["TICK-2", "S", 30], ["TICK-1", "S", 40], ["TICK-2", "B", 30]]) 返回 [["TICK-1", 60]]。TICK-1 净头寸为 100 - 40 = 60;TICK-2 净头寸为 -30 + 30 = 0,被视为已打平而剔除,因此只剩下非零的 TICK-1 一行。

一些边界要明确:solution([]) 返回 [];若所有 ticker 都抵消到 0,输出同样是 [];同一个 ticker 可能在 events 中出现多次,必须聚合为输出中的单行;输出的每一行总是恰好 2 个元素 [ticker, net_position],不能多带其他字段。

预期解法:一次线性扫描进入字典累加(买入加、卖出减),随后对剩下的 K 个非零 ticker 用组合 key (-net, ticker) 做一次排序,整体 O(N + K log K),在 N 取上限时仍然轻松落入时限。

实现细节由 stubs/stub.py 提供。

实践背景

从原始成交流水做净头寸归集,是几乎所有日终交易台流水线的第一道工序:PnL、风险敞口、保证金和盘前合规检查都先要把一连串的买卖成交压缩成"每个标的留存几手"的有符号标量。这一层聚合刻意做得很"笨"——它不看价格、不看交易场所、不看时间戳,只关心收盘那一刻交易台手上还剩多少。按净头寸降序排让交易台最大的多头敞口排在报表最上面(风险经理最先想看的那几行),ticker 字典序做 tiebreak 则保证两台机器跑同一段流水会得到逐字节一致的输出,便于对账和 diff。

把净头寸为 0 的标的剔除是一个有意为之的契约:白天交易了一天但收盘打平的标的并不带任何隔夜风险,写进报表只会让敞口面板里多出噪声行。那些打平标的的逐笔 PnL 归因是在别处按笔做的,并不依赖这张净头寸汇总表。

约束条件

  • 0 <= N <= 50000,其中 N 为 len(events)
  • 每条事件为 [ticker: str, side: str, size: int]
  • side 严格取值 "B"(买入)或 "S"(卖出);1 <= size <= 1000000
  • ticker 为长度 1 到 16 的 ASCII 字符串(合成占位代号,非真实股票代码)
  • 输出为 [ticker, net_position] 二元列表,按净头寸降序、ticker 升序排列;净头寸为 0 的 ticker 不出现在输出中

样例

Case 1 · statement-example: TICK-2 flattens out, TICK-1 net=60

输入: [[["TICK-1","B",100],["TICK-2","S",30],["TICK-1","S",40],["TICK-2","B",30]]]

期望: [["TICK-1",60]]

TICK-1 净头寸为 100-40=60;TICK-2 为 -30+30=0 被剔除;输出仅留 ["TICK-1", 60]。

Case 2 · visible: tie on net broken by ticker ASC

输入: [[["SYM-B","B",50],["SYM-A","B",50],["SYM-C","B",30]]]

期望: [["SYM-A",50],["SYM-B",50],["SYM-C",30]]

SYM-A 与 SYM-B 净头寸均为 50,按字典序 SYM-A 排前;SYM-C 净 30 排最后。

Case 3 · visible: mixed long and short positions

输入: [[["TICK-1","B",200],["TICK-2","S",100],["TICK-3","B",50]]]

期望: [["TICK-1",200],["TICK-3",50],["TICK-2",-100]]

三个 ticker 都不为 0,按净头寸降序 200, 50, -100 排列。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · statement-example: TICK-2 flattens out, TICK-1 net=60

输入: [[["TICK-1","B",100],["TICK-2","S",30],["TICK-1","S",40],["TICK-2","B",30]]]

期望: [["TICK-1",60]]

TICK-1 净头寸为 100-40=60;TICK-2 为 -30+30=0 被剔除;输出仅留 ["TICK-1", 60]。

Case 2 · visible: tie on net broken by ticker ASC

输入: [[["SYM-B","B",50],["SYM-A","B",50],["SYM-C","B",30]]]

期望: [["SYM-A",50],["SYM-B",50],["SYM-C",30]]

SYM-A 与 SYM-B 净头寸均为 50,按字典序 SYM-A 排前;SYM-C 净 30 排最后。

Case 3 · visible: mixed long and short positions

输入: [[["TICK-1","B",200],["TICK-2","S",100],["TICK-3","B",50]]]

期望: [["TICK-1",200],["TICK-3",50],["TICK-2",-100]]

三个 ticker 都不为 0,按净头寸降序 200, 50, -100 排列。