sql - SQL 中的 XIRR 计算

标签 sql t-sql financial xirr

我正在尝试在 SQL 中找到 excel XIRR 计算的合适实现。

我在网上找到了以下函数:

CREATE TYPE dbo.MyXirrTable AS TABLE
        (
            theValue DECIMAL(19, 9) NOT NULL, 
            theDate DATETIME NOT NULL
        )
GO


CREATE FUNCTION dbo.XIRR
(
    @Sample MyXirrTable READONLY,
    @Rate DECIMAL(19, 9) = 0.1
)
RETURNS DECIMAL(38, 9)
AS
BEGIN
    DECLARE @LastRate DECIMAL(19, 9),
        @RateStep DECIMAL(19, 9) = 0.1,
        @Residual DECIMAL(19, 9) = 10,
        @LastResidual DECIMAL(19, 9) = 1,
        @i TINYINT = 0

    IF @Rate IS NULL
        SET @Rate = 0.1

    SET @LastRate = @Rate

    WHILE @i < 100 AND ABS((@LastResidual - @Residual) / @LastResidual) > 0.00000001
        BEGIN
            SELECT  @LastResidual = @Residual,
                @Residual = 0

            SELECT  @Residual = @Residual + theValue / POWER(1 + @Rate, theDelta / 365.0E)
            FROM    (
                    SELECT  theValue,
                        DATEDIFF(DAY, MIN(theDate) OVER (), theDate) AS theDelta
                    FROM    @Sample
                ) AS d

            SET @LastRate = @Rate

            If @Residual >= 0
                SET @Rate += @RateStep
            ELSE
                SELECT  @RateStep /= 2,
                    @Rate -= @RateStep

            SET @i += 1
        END

    RETURN  @LastRate
END
GO

(取自 here )

在测试此功能并取得很大成功后(结果与 Excel 匹配)。我意识到它似乎不适用于一组会导致负 XIRR 的交易。

我不完全理解算法的内部原理,并且尝试过调试但运气不佳。

这是一个失败的测试用例:

DECLARE @Test MyXirrTable

INSERT  @Test
VALUES  (-4471762.56680002, '2008-11-13 00:00:00.000'),
    (+2607759.77, '2008-11-14 00:00:00.000'),
    (+12263.33, '2008-11-25 00:00:00.000'),
    (+1658.89, '2008-11-25 00:00:00.000'),
    (+1834423.33, '2008-12-04 00:00:00.000'),
    (-0.000245418674579822,'2013-11-14 00:00:00.000')       

SELECT  dbo.XIRR(@Test, 0.1)    

计算值 = -0.000000001

预期值 = -0.12879

enter image description here

是否有人比我更了解金融算法,可以修复此测试用例或提供更好的 SQL 解决方案?

最佳答案

这与 Excel 值有关:

CREATE TYPE [dbo].[XIRRTable] AS TABLE(
    [Value] [decimal](19, 9) NOT NULL,
    [Date] [datetime] NOT NULL
)
GO   

CREATE FUNCTION [dbo].[CalcXIRR]
(
    @Sample XIRRTable READONLY,
    @Rate DECIMAL(19, 9) = 0.1
)
RETURNS DECIMAL(38, 9)
AS
BEGIN
    DECLARE @X DECIMAL(19, 9) = 0.0,
    @X0 DECIMAL(19, 9) = 0.1,
    @f DECIMAL(19, 9) = 0.0,
    @fbar DECIMAL(19, 9) = 0.0,
    @i TINYINT = 0,
    @found TINYINT = 0

IF @Rate IS NULL
    SET @Rate = 0.1

SET @X0 = @Rate

WHILE @i < 100
    BEGIN
        SELECT  @f = 0.0,
            @fbar = 0.0

        SELECT      @f = @f + value * POWER(1 + @X0, (-theDelta / 365.0E)),
        @fbar = @fbar - theDelta / 365.0E * value * POWER(1 + @X0, (-theDelta / 365.0E - 1))
        FROM    (
                SELECT  Value,
                    DATEDIFF(DAY, MIN(date) OVER (), date) AS theDelta
                FROM    @Sample
            ) AS d

        SET @X = @X0 - @f / @fbar

        If ABS(@X - @X0) < 0.00000001
        BEGIN
           SET @found = 1
           BREAK;
        END

        SET @X0 = @X
        SET @i += 1
   END

If @found = 1
    RETURN  @X

RETURN NULL
END

关于sql - SQL 中的 XIRR 计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20972209/

相关文章:

sql - 如何更改SQL插入语句的目标表?

相同限制的 MySQL SELECT 查询越来越慢

mysql - SQL Distinct - 获取所有值

sql - 从 SQL Server 中的字符串末尾删除连字符

sql - 运行后取消主触发器(更新后)触发器类型

python - 在 numpy 中获取日志返回的最有效方法是什么

matlab - 不等间隔时间序列的移动平均线

存储过程中的 SQL Server 变量范围

t-sql - 为什么在完全隔离的情况下运行时 @@rowcount 等于 1?

PHP IRR(内部 yield )财务函数