kdb - 求解 IRR 的求解器函数
kdb - solver function to solve for IRR
无法执行 return 计算的比率来与 Excel 的 XIRR 计算进行比较,后者本质上是一种求解器算法,用于查找投资 NPV 为零时的贴现率在 table.
中提供现金流量和日期
根据 MSFT 文档,函数循环 100 次(不限于此……我在下面的代码中使用 10,000 次来测试各种速率)
这是我的虚拟数据示例,以在单个 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
无法执行 return 计算的比率来与 Excel 的 XIRR 计算进行比较,后者本质上是一种求解器算法,用于查找投资 NPV 为零时的贴现率在 table.
中提供现金流量和日期根据 MSFT 文档,函数循环 100 次(不限于此……我在下面的代码中使用 10,000 次来测试各种速率)
这是我的虚拟数据示例,以在单个 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