【问题标题】:How to update dependent values in KDB table如何更新 KDB 表中的依赖值
【发布时间】:2018-01-18 22:41:16
【问题描述】:

当它依赖于其他一些列 sAAsBB 的先前值时,我正在努力寻找一种有效的方法来更新列值 fv。这些又需要用新计算的当前日期的fv 版本更新,然后可以计算下一个fv,依此类推。

为了说明这个问题,考虑一个简单的例子:假设我有一个表格,其中包含一些股票的价格AABB,权重wAAwBB,每个交易日期td。此外,我有一个基金价值fv 和股票拥有的列sAAsBB

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,但其余时间未知。计算除第一行以外的任何其他行的fvAA*(prev sAA) + BB*(prev sBB),即取决于之前的sAAsBB 值..

sAAsBB 对于所有日期都设置为 0n,并计算为(伪代码)sAA : fv * wAA % AA。对于第一行,这很好,因为已知 fv(0)。但是对于连续的行,我遇到了问题,因为 KDB/Q 以列顺序运行,并且更新的内联执行直到最后才更新表。因此sAAsBB 仍然是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 中的错误形式)。因此,我的解决方案不可扩展或易于维护,多次计算相同的值,多​​次遍历数据,使用“全局”变量和其他糟糕的代码。在到达下面之前,我已经尝试了其他一些事情,例如在同一语句中执行更新语句更新fvsAAsBB,但是由于 KDB 在列上工作,它不会更新sAAsBB,然后转到下一个 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 的评论很有帮助。

标签: kdb q-lang


【解决方案1】:

认为你必须使用一个 over 来做到这一点http://code.kx.com/q/ref/adverbs/#over

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)
q)({update fv:fv^(AA*prev sAA) + BB*prev sBB,sAA:fv*wAA%AA,sBB:fv*wBB%BB from x}/)t
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.9 248.5745 629.5804
2001.01.04 126   116   0.4 0.6 104351.7 331.2753 539.7503
2001.01.05 129.2 119.2 0.5 0.5 107139   414.6246 449.4086
2001.01.06 130   120   0.9 0.1 107830.2 746.517  89.85852

虽然注意值与您的示例答案略有不同,但不确定原因

【讨论】:

  • 不错。但请注意,此解决方案的迭代次数是看起来的两倍(每行两次迭代)。如下调整它会使迭代次数减半:({update fv:fv^prev(sAA*next[AA])+sBB*next[BB] from update sAA:fv*wAA%AA,sBB:fv*wBB%BB from x}/)t
  • 两种解决方案也通过每个循环遍历整个表。可以这样做,只传递单个行并计算相关值,但它不会那么清晰
  • 谢谢大家。只是对阅读本文的任何人的不同值的评论:在 R 和 Excel 中独立检查了值,它是 emc211 的解决方案产生了正确的数字,而我的数字略有偏差。不知道为什么,但我猜有些变量没有及时更新或类似的。无论如何,非常感谢您的 cmets 和帮助。
猜你喜欢
  • 2020-06-22
  • 2021-09-29
  • 2018-03-27
  • 2020-04-30
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多