KDB:FIFO方式的pnl

时间:2014-08-25 16:59:47

标签: fifo kdb

考虑下表:

Id Verb Qty Price
`1 Buy  6 10.0
`2 Sell 5 11.0
`3 Buy  4 10.0
`4 Sell 3 11.0
`5 Sell 8 9.0
`6 Buy  1 8.0
etc...

我想要的是将PNL与每个事务相关联,在FIFO上计算(先进先出)。因此,对于Id=`1,我希望PNL为-6*(10.0) +5*(11.0) + 1*(11.0) = +$6.00Id=`3,Pnl为-4*(10.0)+2*(11.0)+(2*9.0) = $0等。

通俗地说,对于6号的第一个买单,我希望将前6个卖出抵消,对于4号的第二个买单,将其与后续4个尚未出售的卖单抵消。包含在买入6订单的pnl计算中。

有什么建议吗?

4 个答案:

答案 0 :(得分:1)

这是第一次尝试让球滚动。效率不高。

q)t:([]id:1+til 6;v:`b`s`b`s`s`b;qty:6 5 4 3 8 1; px:10 11 10 11 9 8)
//how much of each sale offsets a given purchase
q)alloc:last each (enlist d`s){(fx-c;c:deltas y&sums fx:first x)}\(d:exec qty by v from t)`b
//revenues, ie allocated sale * appropriate price
q)revs:alloc*\:exec px from t where v=`s
q)(sum each revs)-exec qty*px from t where v=`b
6 0 1

答案 1 :(得分:0)

与JPC类似的方法,但保持表格:

q)tab:([] Id:`1`2`3`4`5`6;Verb:`Buy`Sell`Buy`Sell`Sell`Buy;Qty:6 5 4 3 8 1;Price:10.0 11.0 10.0 11.0 9.0 8.0)
q)tab
Id Verb Qty Price
-----------------
1  Buy  6   10
2  Sell 5   11
3  Buy  4   10
4  Sell 3   11
5  Sell 8   9
6  Buy  1   8

pnlinfo:{[x;y] 
    b:exec first'[(Qty;Price)] from x where Id=y;
    r:exec (remQty;fifo[remQty;b 0];Price) from x where Verb=`Sell;
    x:update remQty:r 1 from x where Verb=`Sell;
    update pnl:neg[(*) . b]+sum[r[2]*r[0]-r[1]] from x where Id=y
    };

fifo:{x-deltas y&sums x};

pnlinfo/[update remQty:Qty from tab where Verb=`Sell;exec Id from tab where Verb=`Buy]
Id Verb Qty Price remQty pnl
----------------------------
1  Buy  6   10           6
2  Sell 5   11    0
3  Buy  4   10           0
4  Sell 3   11    0
5  Sell 8   9     5
6  Buy  1   8            1

假设买入将抵消先前的卖出以及未来的卖出。

理论上你也可以使用其他发行版,例如

lifo:{x-reverse deltas y&sums reverse x}

但我没有测试过。

答案 2 :(得分:0)

稍微不同的方法而不使用over / scan(除了总和......)。

在这里,我们创建每个卖单的重复指数列表(每单位数量一个),并使用cut将它们分配到相应的买单,然后我们将这些卖出的价格编入索引并找出与价格的差异适当的买单。

这应该与表格大小一致,但是当数量很大时,内存会爆炸。

q)tab:([] Id:`1`2`3`4`5`6;Verb:`Buy`Sell`Buy`Sell`Sell`Buy;Qty:6 5 4 3 8 1;Price:10.0 11.0 10.0 11.0 9.0 8.0)

q)sideMap:`Buy`Sell!1 -1

q)update pnl:sum each neg Price - Price{sells:where neg 0&x; -1_(count[sells]&0,sums 0|x) _ sells}Qty*sideMap[Verb] from tab
Id Verb Qty Price pnl
---------------------
1  Buy  6   10    6  
2  Sell 5   11    0  
3  Buy  4   10    0  
4  Sell 3   11    0  
5  Sell 8   9     0  
6  Buy  1   8     1

答案 3 :(得分:0)

从您的示例中获取数据:

txn:([] t: til 6; side:`Buy`Sell`Buy`Sell`Sell`Buy; qty:6 5 4 3 8 1; px: 10.0 11.0 10.0 11.0 9.0 8.0)

最好在数据库中单独维护buyssells次交易/填充:

buys: select from txn where side=`Buy
sells: select from txn where side=`Sell

我们需要的功能[1]:

/ first-in first-out allocation of bid/buy and ask/sell fills
/ returns connectivity matrix of (b)id fills in rows and (a)sk fills in columns
fifo: {deltas each deltas sums[x] &\: sums[y]};

/ connectivity list from connectivity matrix
lm: {raze(til count x),''where each x};

/ realized profit & loss
rpnl: {[b;s]
    t: l,'f ./: l:lm (f:fifo[exec qty from b;exec qty from s])>0;
    pnl: (select bt:t, bqty:qty, bpx:px from b@t[;0]),'(select st:t, sqty:qty, spx:px from s@t[;1]),'([] qty: t[;2]);
    select tstamp: bt|st, rpnl:qty*spx-bpx from pnl
}

执行命令

q)rpnl[buys;sells]
tstamp rpnl
-----------
1      5   
3      1   
3      2   
4      -2  
5      1   

根据我的时间安排,应该比下一个最佳解决方案快2倍,因为它很好地被矢量化了。

<强>脚注:

fifo函数是来自Q for Mortals的教科书示例。在您的情况下,它看起来像这样:

q)fifo[exec qty from buys;exec qty from sells]
5 1 0
0 2 2
0 0 1

lm函数告诉哪些买入和卖出交叉(非零填充)。更多背景信息:[kdb+/q]: Convert adjacency matrix to adjacency list

q)lm fifo[exec qty from buys;exec qty from sells]>0
0 0
0 1
1 1
1 2
2 2

rpnl的隐秘第一行是上述两个概念的组合:

q)t: l,'f ./: l:lm (f:fifo[exec qty from buys;exec qty from sells])>0;
0 0 5
0 1 1
1 1 2
1 2 2
2 2 1