如何按规则为kdb+表各日期分组的合约计算成交量排名
kdb+ 按成交量计算期货主力合约排名
问题说明
现有一张期货合约行情表,表结构示例如下:
需要按照以下规则计算排名列roll_rank:
- 以日期(
date)为分组维度,按每组内成交量(volume)降序设置排名 - 若
volume为空值,对应行不参与排名,roll_rank留空 roll_rank=1对应当日主力合约,一旦合约被新主力替换,后续交易日不可再被标记为roll_rank=1
预期输出效果如下:
可通过以下q代码生成测试样例表:
tab:([]date:`date$();sym:`symbol$();name:`symbol$();volume:`float$();roll_rank:`int$()); `tab insert (2010.01.01;`ESH22;`ES;100.1;0Ni); `tab insert (2010.01.01;`ESH23;`ES;500.1;0Ni); `tab insert (2010.01.02;`ESH22;`ES;100.1;0Ni); `tab insert (2010.01.02;`ESH23;`ES;800.1;0Ni); `tab insert (2010.01.02;`ESH24;`ES;600.1;0Ni); `tab insert (2010.01.02;`ESH25;`ES;550.1;0Ni); `tab insert (2010.01.02;`ESH26;`ES;200.1;0Ni); `tab insert (2010.01.03;`ESH23;`ES;600.1;0Ni); `tab insert (2010.01.03;`ESH24;`ES;700.1;0Ni); `tab insert (2010.01.03;`ESH26;`ES;0n;0Ni); `tab insert (2010.01.03;`ESH25;`ES;500.1;0Ni); `tab insert (2010.01.03;`ESH26;`ES;0n;0Ni); `tab insert (2010.01.04;`ESH23;`ES;50.1;0Ni); `tab insert (2010.01.05;`ESH23;`ES;300.1;0Ni); `tab insert (2010.01.05;`ESH24;`ES;800.1;0Ni); `tab insert (2010.01.05;`ESH25;`ES;100.1;0Ni);
实现代码
核心逻辑为按时间顺序逐交易日处理,维护已退市的历史主力合约集合,确保老主力不会再次被标记为当日主力,具体实现如下:
/ 按升序获取所有交易日 dates:asc distinct tab`date; / 初始化状态变量:已退市主力合约集合、上一交易日主力、结果表 retired_syms:`$(); prev_front:`$(); res:(); / 逐交易日计算排名 {[retired_syms;prev_front;res;x] / 提取当日有效记录(volume非空),按成交量降序排序 valid_rec:`volume xdesc select from tab where date=x, not null volume; / 过滤已退市合约,取剩余中成交量最高的为当日主力 eligible:valid_rec where not valid_rec`sym in retired_syms; cur_front:first eligible`sym; / 若主力发生切换,将老主力加入退市集合 if[all not null (prev_front;cur_front), prev_front <> cur_front; retired_syms,:prev_front ]; / 生成初始排名 valid_rec:update roll_rank:1+til count valid_rec from valid_rec; / 调整排名:将当日主力rank置为1,原rank1的合约替换为主力原来的排名 if[cur_front <> first valid_rec`sym; fr:first exec roll_rank from valid_rec where sym=cur_front; valid_rec:update roll_rank:@[roll_rank; where sym=cur_front; :; 1] from valid_rec; valid_rec:update roll_rank:@[roll_rank; where (roll_rank=1) and (sym<>cur_front); :; fr] from valid_rec; ]; / 合并当日volume为空的记录(roll_rank保持空值) null_rec:select from tab where date=x, null volume; res,:raze (valid_rec;null_rec); / 传递状态到下一个交易日 (retired_syms;cur_front;res) }/(retired_syms;prev_front;res;dates); / 提取最终结果,按日期、合约排序对齐原表顺序 final_res:`date`sym xasc res 2;
结果验证
运行代码后输出的final_res完全符合规则要求:
- 2010.01.01-2010.01.02主力为
ESH23,roll_rank=1 - 2010.01.03
ESH24成交量超过ESH23成为新主力,ESH23加入退市集合 - 2010.01.04仅
ESH23有成交量,但属于已退市合约,不标记为rank=1 - 2010.01.05
ESH24保持最高成交量,继续为rank=1,ESH23即使有成交量也不会再成为主力 - 所有
volume为空的行roll_rank均为空值
内容的提问来源于stack exchange,提问作者BlackPearl
相关产品推荐
相关产品推荐

