【发布时间】:2018-01-18 22:41:16
【问题描述】:
当它依赖于其他一些列 sAA 和 sBB 的先前值时,我正在努力寻找一种有效的方法来更新列值 fv。这些又需要用新计算的当前日期的fv 版本更新,然后可以计算下一个fv,依此类推。
为了说明这个问题,考虑一个简单的例子:假设我有一个表格,其中包含一些股票的价格AA 和BB,权重wAA 和wBB,每个交易日期td。此外,我有一个基金价值fv 和股票拥有的列sAA 和sBB。
q)t:([] td:2001.01.01 2001.01.02 2001.01.03 2001.01.04 2001.01.05 2001.01.06;
AA:121.5 125.0 127.0 126.0 129.2 130.0;
BB:111.0 115.3 117.0 116.0 119.2 120.0;
wAA: 0.2 0.2 0.3 0.4 0.5 0.9;
wBB: 0.8 0.8 0.7 0.6 0.5 0.1;
fv:100000 0N 0n 0n 0n 0n;
sAA: 0n; sBB: 0n;)
(Roundtrip: 000ms)
::
q) t
td AA BB wAA wBB fv sAA sBB
2001.01.01 121.5 111 0.2 0.8 100000 0n 0n
2001.01.02 125 115.3 0.2 0.8 0n 0n 0n
2001.01.03 127 117 0.3 0.7 0n 0n 0n
2001.01.04 126 116 0.4 0.6 0n 0n 0n
2001.01.05 129.2 119.2 0.5 0.5 0n 0n 0n
2001.01.06 130 120 0.9 0.1 0n 0n 0n
基金价值不断变化,例如,第一个初始日期 (td(0)) 设置为 1,000,000,但其余时间未知。计算除第一行以外的任何其他行的fv:AA*(prev sAA) + BB*(prev sBB),即取决于之前的sAA 和sBB 值..
sAA 和 sBB 对于所有日期都设置为 0n,并计算为(伪代码)sAA : fv * wAA % AA。对于第一行,这很好,因为已知 fv(0)。但是对于连续的行,我遇到了问题,因为 KDB/Q 以列顺序运行,并且更新的内联执行直到最后才更新表。因此sAA 和sBB 仍然是0n,连续的fv 值也是如此。
最终产品应如下所示:
td AA BB wAA wBB fv sAA sBB
2001.01.01 121.5 111 0.2 0.8 100000 164.6091 720.7207
2001.01.02 125 115.3 0.2 0.8 103675.2 165.8804 719.3425
2001.01.03 127 117 0.3 0.7 105229.7 248.574 629.5792
2001.01.04 126 116 0.4 0.6 104344.3 331.2519 539.7121
2001.01.05 129.2 119.2 0.5 0.5 107177.4 414.7732 449.5696
2001.01.06 130 120 0.9 0.1 107885.7 746.9007 89.90472
从起点t 到达上述终点的有效方法是什么?如果您重组数据,那么我将不胜感激一两行解释(我应该能够遵循其他代码)。
虽然我已经解决了它(我在下面提供了我的解决方案,尽管它可能是可耻的),但我的数据以及在某种程度上我自己的想法正遭受着经典的“又短又胖”和“逐行”的困扰思考和方法(Q 中的错误形式)。因此,我的解决方案不可扩展或易于维护,多次计算相同的值,多次遍历数据,使用“全局”变量和其他糟糕的代码。在到达下面之前,我已经尝试了其他一些事情,例如在同一语句中执行更新语句更新fv、sAA 和sBB,但是由于 KDB 在列上工作,它不会更新sAA 和sBB,然后转到下一个 fv。
我目前和糟糕的解决方案(想象一下添加另外 100 或 1000 只股票的开销......不利于利用任何人的时间):
t:([] td:2001.01.01 2001.01.02 2001.01.03 2001.01.04 2001.01.05 2001.01.06;
AA:121.5 125.0 127.0 126.0 129.2 130.0;
BB:111.0 115.3 117.0 116.0 119.2 120.0;
wAA: 0.2 0.2 0.3 0.4 0.5 0.9;
wBB: 0.8 0.8 0.7 0.6 0.5 0.1;
fv:100000 0N 0n 0n 0n 0n;
sAA: 0n;
sBB: 0n)
t
kt:`td xkey t
// Calculate the first row of shares owned
kt:update sAA:fv*wAA%AA, sBB:fv*wBB%BB from kt
kt
// Global variables for previous shares owned
gPrevSAA:1.0
gPrevSBB:1.0
// Function to calclate the FV. If any of the previous shares owned paraeters are
// null then use the global parameters.
calcFV:{[fv;pSAA;pxA;pSBB;pxB]
// The first time calcFV is called, pSAA will be defined. The remainder it will be null.
$[pSAA=0n;pSAA:gPrevSAA;pSAA:pSAA];
$[pSBB=0n;pSBB:gPrevSBB;pSBB:pSBB];
// Calculate the fund value
uFV:-1;
$[fv=0n;uFV:(pSAA*pxA)+(pSBB*pxB);uFV:fv];
// update global values
$[pSAA<>0n;`gPrevSAA set pSAA;];
$[pSBB<>0n;`gPrevSBB set pSBB;];
uFV
}
// Calculate the fund values
kt:update fv:calcFV ' [fv;prev sAA;AA;prev sBB;BB] from kt
// Update the shares owned columns with the newly calcualted fund values
kt:update sAA:fv*wAA%AA, sBB:fv*wBB%BB from kt
【问题讨论】:
-
请注意您对
$的使用 - 此条件将返回 一个值,因此您可以执行pSAA:$[pSAA=0n;gPrevSAA;pSAA]之类的操作,而不是在条件中分配变量这更清晰更清洁。此外,对于这个用例,您最好使用这样的填充:pSAA:gPrevSAA^pSAA- 请参阅code.kx.com/q/ref/lists/#fill -
谢谢 - 特别是关于
fill的评论很有帮助。