【问题标题】:kdb - solver function to solve for IRRkdb - 求解 IRR 的求解器函数
【发布时间】:2021-02-22 20:50:20
【问题描述】:

无法实现收益率计算以与 Excel 的 XIRR calc 进行比较,后者本质上是一种求解算法,用于使用提供的现金流和表格中的日期来找到投资 NPV 为零的贴现率。

根据 MSFT 文档,该函数循环 100 次(不限于此......我在下面的代码中使用 10,000 来测试各种速率)

https://support.microsoft.com/en-ie/office/xirr-function-de1242ec-6477-445b-b11b-a303ad9adc9d?ui=en-us&rs=en-ie&ad=ie

这是我的虚拟数据在单个表中匹配上述示例的示例

t: ([] id:`PROJ_1`PROJ_1`PROJ_1`PROJ_1`PROJ_1`PROJ_1`PROJ_2`PROJ_2`PROJ_2`PROJ_2`PROJ_2`PROJ_2;kdbdate:2021.04.01 2021.12.31 2022.12.31 2023.12.31 2024.12.31 2025.12.31 2021.04.01 2021.12.31 2022.12.31 2023.12.31 2024.12.31 2025.12.31; cf: -800 200 250 300 350 400 -500 150 170 178 250 300);
t: update cum_cf: sums cf by id from t;
t: update irr: count [t]# enlist `float$() from t;  // assign a float return value

calcIRR:{[t] update irr: first[irr_func] t by id from t};
updateTable: calcIRR ::; 
t: updateTable over t; 

irr_func:{[d];  //need to test various discount rates to compare to 0 ;
    Pi: exec sums cum_cf from d;
    D1: exec first kdbdate from d;
    Di: exec last kdbdate from d;
    r: .001* til 10000;  //create vector of discount rates 10,000 seems excessive but covers a wide range
    val:Pi % xexp[(1.0 + r);(Di - D1)%365];  // calculate the value at the different rates
    
    // look for value closest to zero and return the indexed r associated with it

  result: val
 };

我正在查看 kx 关于精度 https://code.kx.com/q/basics/precision/ 的文档以进行比较。

提前致谢!

【问题讨论】:

    标签: kdb


    【解决方案1】:

    我怀疑 excel 在这里使用 Newton's Method,而不是遍历 100 个等距猜测的列表。要使用这种方法进行计算,我们可以从您的表格开始,加上 0.5 的初始猜测:

    q)show t:([] id:`PROJ_1`PROJ_1`PROJ_1`PROJ_1`PROJ_1`PROJ_1`PROJ_2`PROJ_2`PROJ_2`PROJ_2`PROJ_2`PROJ_2;kdbdate:2021.04.01 2021.12.31 2022.12.31 2023.12.31 2024.12.31 2025.12.31 2021.04.01 2021.12.31 2022.12.31 2023.12.31 2024.12.31 2025.12.31; cf: -800 200 250 300 350 400 -500 150 170 178 250 300; irr:0.5)
    id     kdbdate    cf   irr
    --------------------------
    PROJ_1 2021.04.01 -800 0.5
    PROJ_1 2021.12.31 200  0.5
    PROJ_1 2022.12.31 250  0.5
    PROJ_1 2023.12.31 300  0.5
    PROJ_1 2024.12.31 350  0.5
    PROJ_1 2025.12.31 400  0.5
    PROJ_2 2021.04.01 -500 0.5
    PROJ_2 2021.12.31 150  0.5
    PROJ_2 2022.12.31 170  0.5
    PROJ_2 2023.12.31 178  0.5
    PROJ_2 2024.12.31 250  0.5
    PROJ_2 2025.12.31 300  0.5
    

    并定义以下应用牛顿法一步的函数:

    q)foo:{[t]update irr:irr-sum[cf*(1+irr) xexp neg[(kdbdate-first kdbdate)%365]]%sum[neg[(kdbdate-first kdbdate)%365]*cf*(1+irr) xexp neg[(kdbdate-first kdbdate)%365]-1] by id from t}
    

    这采用当前的 irr 猜测并将其更新为 irr-f(irr)%f'(irr),其中 f 是函数净现值函数,f' 是该函数的导数(对于每个 id,当然)。

    使用foo t 应用一次或foo over t 迭代应用使用foo over t

    q)foo over t
    id     kdbdate    cf   irr
    --------------------------------
    PROJ_1 2021.04.01 -800 0.2444791
    PROJ_1 2021.12.31 200  0.2444791
    PROJ_1 2022.12.31 250  0.2444791
    PROJ_1 2023.12.31 300  0.2444791
    PROJ_1 2024.12.31 350  0.2444791
    PROJ_1 2025.12.31 400  0.2444791
    PROJ_2 2021.04.01 -500 0.2966161
    PROJ_2 2021.12.31 150  0.2966161
    PROJ_2 2022.12.31 170  0.2966161
    PROJ_2 2023.12.31 178  0.2966161
    PROJ_2 2024.12.31 250  0.2966161
    PROJ_2 2025.12.31 300  0.2966161
    

    【讨论】:

    • 再次感谢豪尔赫!我只需要调整上面的 foo 函数并将 he (1+r) 更新为 (1+irr)。
    • 啊,很好。我从终端复制了错误的线路。顺便说一句,如果您想了解结果收敛的速度,您可以使用foo scan t 查看中间步骤。有了它,你可以看到我们只需要 6 次迭代就可以收敛上面的示例表。
    • 再次感谢帮助。我在我的 ETL 过程中导入了一个主要贴现率,因此我将其用作猜测(在我的情况下为 0.1),因此运行它并使用“扫描”它仍然会在 6 次迭代中将其淘汰。改变负值,所以我有一个 neg IRR 现在需要大约 19 次迭代。
    • 是的,通常牛顿法非常有效。这就是 Excel 在 100 次迭代后放弃的原因 - 如果该值到那时还没有收敛,则可能存在一些问题导致该值完全发散。这对于多项式来说应该很少见(如 irr 计算的情况),但有适当的保护是有意义的。
    • 是的,我还需要包装函数来处理我的非投资项目(例如,默认 IRR 为 NA 或硬编码 100%)一直在阅读,这对于我在各种折扣率下的盈亏平衡计算以及然后弄清楚如何在我现有的代码中实现至关重要。精彩的分享,豪尔赫!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多