Python IRR函数提供与Excel XIRR不同的结果

问题描述

我正在使用以下函数通过Python执行IRR计算:

from scipy.optimize import newton

def xnpv(rate,values,dates):
    
    if rate <= -1.0:
        return float('inf')
    min_date = min(dates)
    return sum([
        value / (1 + rate)**((date - min_date).days / 365)
        for value,date
        in zip(values,dates)
     ])


def xirr(values,dates):
    return newton(lambda r: xnpv(r,dates),0)

函数来源:https://2018.pycon.co/talks/personal-pynance/personal-pynance.pdf

几个月来,此功能与各种不同的现金流量和日期完美配合,而我得到的效果与Excel的XIRR功能相同。但是,突然有了下面的现金流量和日期列表,它就停止了工作,并且我得到的结果与Excel的IRR公式(这是正确的和预期的)不同:

import pandas as pd
import datetime
import numpy as np
from decimal import *

# Input Data
dates = [datetime.date(2020,8,31),datetime.date(2020,5,5),2,28),datetime.date(2018,6,30)]
values = [50289.0,-75000.0,0.0,0.0]

# Create Dataframe from Input Data
test = pd.DataFrame({"dates" : dates,"values" : values})

# Filter all rows with 0 cashflows
test = test[test['values'] != 0]

# Sort dataframe by date
test = test.sort_values('dates',ascending=True)
test['values'] = test['values'].astype('float')

# Create separate lists for values and dates
test_values = list(test['values'])
test_dates = list(test['dates'])

# Calculate IRR
xirr(test_values,test_dates)

我在Python中得到的结果是 0.0001 ,而在Excel中我得到的结果是 -0.71 ,我不知道这里缺少什么。也许有人有主意?!?!!

解决方法

科学优化功能对局部极小值是错误的。将优化方法更改为其他内容,例如anderson,并达到您的期望。

证明

from scipy.optimize import anderson

def xnpv(rate,values,dates):
    
    if rate <= -1.0:
        return float('inf')
    min_date = min(dates)
    return sum([
        value / (1 + rate)**((date - min_date).days / 365)
        for value,date
        in zip(values,dates)
     ])


def xirr(values,dates):
    return anderson(lambda r: xnpv(r,dates),0)

import datetime
from decimal import *

# Input Data
dates = [datetime.date(2020,8,31),datetime.date(2020,5,5),2,28),datetime.date(2018,6,30)]
values = [50289.0,-75000.0,0.0,0.0]

# Create Dataframe from Input Data
test = pd.DataFrame({"dates" : dates,"values" : values})

# Filter all rows with 0 cashflows
test = test[test['values'] != 0]

# Sort dataframe by date
test = test.sort_values('dates',ascending=True)
test['values'] = test['values'].astype('float')

# Create separate lists for values and dates
test_values = list(test['values'])
test_dates = list(test['dates'])

# Calculate IRR
xirr(test_values,test_dates)
array(-0.70956212)