在kdb/q中实现FIFO规则下的PnL计算
直接解决思路:用FIFO持仓队列跟踪计算PnL
不用生成分配矩阵,直接通过跟踪持仓队列逐笔处理交易,就能精准计算每笔开仓单的PnL,完全符合你的规则:
核心逻辑
- 用队列记录未平仓的开仓仓位,严格遵循FIFO顺序(先开仓的先平仓)
- 每笔平仓交易(反向交易)从队列头部开始匹配,计算对应开仓单的PnL,平仓单自身PnL为0
- 若反向交易的数量超过现有持仓,超出部分作为新的反向开仓加入队列,后续被平仓时再计算PnL
具体步骤(对应你的交易数据)
初始化:
- 持仓队列:空
- 每笔交易的PnL初始为0
- 净持仓量:0
1. 处理Id=1(Buy 6 @10.0)
- 净持仓为0,直接作为多头开仓加入队列:
[(Id1, 6, 10.0, 0.0)] - 净持仓变为6
- Id1的PnL暂记0,后续平仓时更新
2. 处理Id=2(Sell 5 @11.0)
- 从队列头部取Id1的6份多头,平仓5份:
- 计算PnL:
5*(11.0-10.0)=5.0,加到Id1的PnL中(Id1现在PnL=5.0) - Id1剩余未平仓数量:6-5=1,更新队列元素为
(Id1,1,10.0,5.0)
- 计算PnL:
- 净持仓变为6-5=1
- Id2的PnL=0.0
3. 处理Id=3(Buy4 @10.0)
- 净持仓为1(多头),新增多头开仓加入队列:
[(Id1,1,10.0,5.0), (Id3,4,10.0,0.0)] - 净持仓变为1+4=5
- Id3的PnL暂记0
4. 处理Id=4(Sell3 @12.0)
- 先平队列头部的Id1剩余1份:
- PnL:
1*(12.0-10.0)=2.0,加到Id1的PnL中(Id1现在PnL=5+2=7.0) - Id1剩余数量为0,从队列移除
- PnL:
- 剩余平仓量3-1=2,平队列头部的Id3的4份:
- PnL:
2*(12.0-10.0)=2.0,加到Id3的PnL中(Id3现在PnL=2.0) - Id3剩余数量4-2=2,更新队列元素为
(Id3,2,10.0,2.0)
- PnL:
- 净持仓变为5-3=2
- Id4的PnL=0.0
5. 处理Id=5(Sell8 @9.0)
- 先平队列头部的Id3剩余2份多头:
- 这部分按你的规则不计入Id5的PnL,仅作为平仓现有持仓处理
- Id3剩余数量为0,从队列移除
- 剩余卖出量8-2=6,作为空头开仓加入队列:
[(Id5,6,9.0,0.0)] - 净持仓变为2-8=-6(空头)
- Id5的PnL暂记0,后续平仓时更新
6. 处理Id=6(Buy7 @8.0)
- 从队列头部取Id5的6份空头,平仓6份:
- 计算PnL:
6*(9.0-8.0)=6.0,加到Id5的PnL中(Id5现在PnL=6.0) - Id5剩余数量为0,从队列移除
- 计算PnL:
- 剩余买入量7-6=1,作为多头开仓加入队列:
[(Id6,1,8.0,0.0)] - 净持仓变为-6+7=1(多头)
- Id6的PnL=0.0(剩余1份资产)
最终结果(完全匹配你的期望)
| Id | Verb | Qty | Price | PnL |
|---|---|---|---|---|
| 1 | Buy | 6 | 10.0 | 7.0 |
| 2 | Sell | 5 | 11.0 | 0.0 |
| 3 | Buy | 4 | 10.0 | 2.0 |
| 4 | Sell | 3 | 12.0 | 0.0 |
| 5 | Sell | 8 | 9.0 | 6.0 |
| 6 | Buy | 7 | 8.0 | 0.0(剩余1份资产) |
内容的提问来源于stack exchange,提问作者Pap
相关产品推荐
相关产品推荐

