kdb - 求解 IRR 的求解器函数

kdb - solver function to solve for IRR

无法执行 return 计算的比率来与 Excel 的 XIRR 计算进行比较,后者本质上是一种求解器算法,用于查找投资 NPV 为零时的贴现率在 table.

中提供现金流量和日期

根据 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

这是我的虚拟数据示例,以在单个 table

中匹配上述内容
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/ 以进行比较。

提前致谢!

我怀疑 excel 在这里使用 Newton's Method,而不是 运行 通过 100 个等间距猜测的列表。要使用此方法进行计算,我们可以从您的 table 开始,加上初始猜测值 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