如何在 excel 和 google 工作表中动态计算 XIRR
how to calculate XIRR dynamically in excel and in google sheets
我正在尝试为我拥有的以下格式的数据计算 XIRR
PurchaseDate Script No.ofunits PurchNAVrate NetAmount ForXIRR TotalReturn
17/11/2014 A 2241 33 75000 -75000 96000
8/1/2015 B 53 649 35000 -35000 43000
14/1/2015 B 75 658 50000 -50000 61500
14/10/2014 C 2319 32 75000 -75000 108000
8/1/2015 D 318 109 35000 -35000 40000
14/1/2015 D 450 110 50000 -50000 57000
8/6/2015 D 175 114 20000 -20000 22000
我尝试了很多不同的排列和组合,但无法计算每个基金的 XIRR。有没有办法可以使用偏移量或搜索来做到这一点。
这是一个动态列表,它会根据买入或卖出的新基金不断变化
Values for Fund A should be around 14%
Values for Fund B should be around 13%
Values for Fund C should be around 21%
Values for Fund D should be around 8%
更新
鉴于@xor-lx 提到的解决方案在 ms excel 但在 google 工作表中工作得很好,我现在已经根据 @kyle 的建议修改了我的数据结构,现在我可以计算 XIRR每个基金作为一个整体很容易。参考以下
PurchaseDate Today Script No.ofunits PurchNAVrate NetAmount ForXIRR TotalReturn XIRR
17/11/14 31/08/2016 A 2241 33 75000 -75000 96000 "=XIRR(G2:H2,A2:B2)"
Total for above fund "=XIRR(G2:H3,A2:B3)"
8/1/2015 31/08/2016 B 53 649 35000 -35000 43000 "=XIRR(G4:H4,A4:B4)"
14/1/2015 31/08/2016 B 75 658 50000 -50000 61500 "=XIRR(G5:H5,A5:B5)"
Total for above fund "=XIRR(G4:H6,A4:B6)"
14 Oct 14 31/08/2016 C 2319 32 75000 -75000 108000 "=XIRR(G7:H7,A7:B7)"
Total for above fund "=XIRR(G7:H8,A7:B8)"
8 Jan 15 31/08/2016 D 318 109 35000 -35000 40000 "=XIRR(G9:H9,A9:B9)"
14 Jan 15 31/08/2016 D 450 110 50000 -50000 57000 "=XIRR(G10:H10,A10:B10)"
8/6/2015 31/08/2016 D 175 114 20000 -20000 22000 "=XIRR(G11:H11,A11:B11)"
Total for above fund "=XIRR(G9:H12,A9:B12)"
我会根据你的 table 假设日期是 A 列,基金(或 "Script")是 B 列,"ForXIRR" 是 F 列。下面将为你做:
{=XIRR(IF(B:B="A",F:F,0),IF(B:B="A",A:A,0))}
确保使用 Shift + Ctrl + Enter
输入它,因为它是一个数组公式。
注意:以上将为 "A" 计算,但将公式的该部分替换为任何其他基金,或使用单元格引用为其他基金计算。
编辑:
我意识到上面的方法只适用于序列中的第一个字母,请使用下面的方法,然后再次将 "B"
调整为您需要的任何值。这将适用于任何出现的字母。此外,调整所有范围以满足您的需要,我只做了行 1:10 用于测试目的。下面调整范围的开始,因此它始终是输入的基金的第一个值(即 "A"、"B"、"C")以允许计算。如果不进行此更改,除非它是列表中的第一个("A" 在 OP 示例中),否则上面的内容将始终以零开头,并且 XIRR 仅使用负数作为第一个值进行计算。
=XIRR(IF(OFFSET($B:$B,MATCH("B",$B:$B,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1)="B",OFFSET($F:$F,MATCH("B",$B:$B,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1),0),IF(OFFSET($B:$B,MATCH("B",B1:B10,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1)="B",OFFSET($A:$A,MATCH("B",$B:$B,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1),0))
假设您的 table 在 A1:G8
中(第 1 行中有 headers),并且您选择的基金,例如"B",在J2
,数组公式**:
=XIRR(INDEX(F:G,N(IF(1,MODE.MULT(IF(B:B=J2,{1,1}*ROW(B:B))))),N(IF(1,{1,2}))),CHOOSE({1,2},INDEX(A:A,N(IF(1,MODE.MULT(IF(B:B=J2,{1,1}*ROW(B:B)))))),TODAY()))
向下复制以给出 J3
、J4
等基金的类似结果
与涉及 OFFSET
的 set-ups 相比,我更喜欢这个;它不仅更简洁(因此更有效率),而且更重要的是,non-volatile.
感兴趣的可以看这里:
https://excelxor.com/2016/02/16/criteria-with-statistical-functions-growth-linest-logest-trend/
此致
**数组公式的输入方式与 'standard' 公式不同。您不是只按 ENTER,而是先按住 CTRL 和 SHIFT,然后再按 ENTER。如果操作正确,您会注意到 Excel 在公式周围放置了大括号 {}(但不要尝试自己手动插入)。
XIRR
需要两个参数数组——值和日期(带有可选的第三个 "guess" 参数)。要尝试将来自购买日期、总计 returns、购买金额和 "today's dates" 数量的非连续范围的数组拼接在一起,对于 Excel 公式来说将是一个相当大的挑战。因此,我提供了一个用 VBA.
编写的用户定义函数
该函数的参数是基金或脚本 (sFund
) 和您的数据 table 范围,如上例所示。
正如您在其中一条评论中所建议的,我使用 TODAY
作为对应于 Total Return
列的日期。如果不是这种情况,则很容易更改。
另外请注意,我没有使用 "forXIRR" 列,而只是使用了 NetAmount
列的负数。如果删除 forXIRR
列,则需要将引用更改为 .TotalReturn
我创建了一个自定义 Class 以使事情更容易理解。
插入 Class 模块后,必须重命名 cFUND
Class 模块
Option Explicit
'Rename cFUND
Private pFund As String
Private pPurchDt As Date
Private pPurchDts As Collection
Private pPurchAmt As Double
Private pPurchAmts As Collection
Private pTotalReturn As Double
Private pTotalReturns As Collection
Public Property Get Fund() As String
Fund = pFund
End Property
Public Property Let Fund(Value As String)
pFund = Value
End Property
Public Property Get PurchDt() As Date
PurchDt = pPurchDt
End Property
Public Property Let PurchDt(Value As Date)
pPurchDt = Value
End Property
Public Function ADDPurchDt(Value As Date)
pPurchDts.Add Value
End Function
Public Property Get PurchDts() As Collection
Set PurchDts = pPurchDts
End Property
Public Property Get PurchAmt() As Double
PurchAmt = pPurchAmt
End Property
Public Property Let PurchAmt(Value As Double)
pPurchAmt = Value
End Property
Public Function ADDPurchAmt(Value As Double)
pPurchAmts.Add Value
End Function
Public Property Get PurchAmts() As Collection
Set PurchAmts = pPurchAmts
End Property
Public Property Get TotalReturn() As Double
TotalReturn = pTotalReturn
End Property
Public Property Let TotalReturn(Value As Double)
pTotalReturn = Value
End Property
Public Function ADDTotalReturn(Value As Double)
pTotalReturns.Add Value
End Function
Public Property Get TotalReturns() As Collection
Set TotalReturns = pTotalReturns
End Property
Public Function CalcXIRR()
Dim v, d, w
Dim I As Long
With Me
ReDim d(.PurchDts.Count * 2 - 1)
ReDim v(UBound(d))
I = 0
For Each w In .PurchAmts
v(I) = w
I = I + 1
Next w
For Each w In .TotalReturns
v(I) = w
I = I + 1
Next w
I = 0
For Each w In .PurchDts
d(I) = w
I = I + 1
Next w
Do Until I > UBound(d)
d(I) = Date
I = I + 1
Loop
End With
CalcXIRR = WorksheetFunction.XIRR(v, d)
End Function
Private Sub Class_Initialize()
Set pPurchDts = New Collection
Set pPurchAmts = New Collection
Set pTotalReturns = New Collection
End Sub
常规模块
Option Explicit
Function fundXIRR(sFund As String, rTable As Range) As Double
Dim vSrc As Variant
Dim cF As cFUND
Dim I As Long
vSrc = rTable
Set cF = New cFUND
For I = 2 To UBound(vSrc, 1)
If vSrc(I, 2) = sFund Then
With cF
.PurchDt = vSrc(I, 1)
.ADDPurchDt .PurchDt
.Fund = vSrc(I, 2)
.PurchAmt = -vSrc(I, 5)
.ADDPurchAmt .PurchAmt
.TotalReturn = vSrc(I, 7)
.ADDTotalReturn .TotalReturn
End With
End If
Next I
fundXIRR = cF.CalcXIRR
End Function
根据上面的数据,B
的 XIRR
将计算为:
XIRR({-35000;-50000;43000;61500},{"1/8/2015";"1/14/2015";"8/29/2016";"8/29/2016"}
以下是您上述数据的结果:
我正在尝试为我拥有的以下格式的数据计算 XIRR
PurchaseDate Script No.ofunits PurchNAVrate NetAmount ForXIRR TotalReturn
17/11/2014 A 2241 33 75000 -75000 96000
8/1/2015 B 53 649 35000 -35000 43000
14/1/2015 B 75 658 50000 -50000 61500
14/10/2014 C 2319 32 75000 -75000 108000
8/1/2015 D 318 109 35000 -35000 40000
14/1/2015 D 450 110 50000 -50000 57000
8/6/2015 D 175 114 20000 -20000 22000
我尝试了很多不同的排列和组合,但无法计算每个基金的 XIRR。有没有办法可以使用偏移量或搜索来做到这一点。 这是一个动态列表,它会根据买入或卖出的新基金不断变化
Values for Fund A should be around 14%
Values for Fund B should be around 13%
Values for Fund C should be around 21%
Values for Fund D should be around 8%
更新 鉴于@xor-lx 提到的解决方案在 ms excel 但在 google 工作表中工作得很好,我现在已经根据 @kyle 的建议修改了我的数据结构,现在我可以计算 XIRR每个基金作为一个整体很容易。参考以下
PurchaseDate Today Script No.ofunits PurchNAVrate NetAmount ForXIRR TotalReturn XIRR
17/11/14 31/08/2016 A 2241 33 75000 -75000 96000 "=XIRR(G2:H2,A2:B2)"
Total for above fund "=XIRR(G2:H3,A2:B3)"
8/1/2015 31/08/2016 B 53 649 35000 -35000 43000 "=XIRR(G4:H4,A4:B4)"
14/1/2015 31/08/2016 B 75 658 50000 -50000 61500 "=XIRR(G5:H5,A5:B5)"
Total for above fund "=XIRR(G4:H6,A4:B6)"
14 Oct 14 31/08/2016 C 2319 32 75000 -75000 108000 "=XIRR(G7:H7,A7:B7)"
Total for above fund "=XIRR(G7:H8,A7:B8)"
8 Jan 15 31/08/2016 D 318 109 35000 -35000 40000 "=XIRR(G9:H9,A9:B9)"
14 Jan 15 31/08/2016 D 450 110 50000 -50000 57000 "=XIRR(G10:H10,A10:B10)"
8/6/2015 31/08/2016 D 175 114 20000 -20000 22000 "=XIRR(G11:H11,A11:B11)"
Total for above fund "=XIRR(G9:H12,A9:B12)"
我会根据你的 table 假设日期是 A 列,基金(或 "Script")是 B 列,"ForXIRR" 是 F 列。下面将为你做:
{=XIRR(IF(B:B="A",F:F,0),IF(B:B="A",A:A,0))}
确保使用 Shift + Ctrl + Enter
输入它,因为它是一个数组公式。
注意:以上将为 "A" 计算,但将公式的该部分替换为任何其他基金,或使用单元格引用为其他基金计算。
编辑:
我意识到上面的方法只适用于序列中的第一个字母,请使用下面的方法,然后再次将 "B"
调整为您需要的任何值。这将适用于任何出现的字母。此外,调整所有范围以满足您的需要,我只做了行 1:10 用于测试目的。下面调整范围的开始,因此它始终是输入的基金的第一个值(即 "A"、"B"、"C")以允许计算。如果不进行此更改,除非它是列表中的第一个("A" 在 OP 示例中),否则上面的内容将始终以零开头,并且 XIRR 仅使用负数作为第一个值进行计算。
=XIRR(IF(OFFSET($B:$B,MATCH("B",$B:$B,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1)="B",OFFSET($F:$F,MATCH("B",$B:$B,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1),0),IF(OFFSET($B:$B,MATCH("B",B1:B10,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1)="B",OFFSET($A:$A,MATCH("B",$B:$B,0)-1,0,ROWS($B:$B)-MATCH("B",$B:$B,0)+1,1),0))
假设您的 table 在 A1:G8
中(第 1 行中有 headers),并且您选择的基金,例如"B",在J2
,数组公式**:
=XIRR(INDEX(F:G,N(IF(1,MODE.MULT(IF(B:B=J2,{1,1}*ROW(B:B))))),N(IF(1,{1,2}))),CHOOSE({1,2},INDEX(A:A,N(IF(1,MODE.MULT(IF(B:B=J2,{1,1}*ROW(B:B)))))),TODAY()))
向下复制以给出 J3
、J4
等基金的类似结果
与涉及 OFFSET
的 set-ups 相比,我更喜欢这个;它不仅更简洁(因此更有效率),而且更重要的是,non-volatile.
感兴趣的可以看这里:
https://excelxor.com/2016/02/16/criteria-with-statistical-functions-growth-linest-logest-trend/
此致
**数组公式的输入方式与 'standard' 公式不同。您不是只按 ENTER,而是先按住 CTRL 和 SHIFT,然后再按 ENTER。如果操作正确,您会注意到 Excel 在公式周围放置了大括号 {}(但不要尝试自己手动插入)。
XIRR
需要两个参数数组——值和日期(带有可选的第三个 "guess" 参数)。要尝试将来自购买日期、总计 returns、购买金额和 "today's dates" 数量的非连续范围的数组拼接在一起,对于 Excel 公式来说将是一个相当大的挑战。因此,我提供了一个用 VBA.
该函数的参数是基金或脚本 (sFund
) 和您的数据 table 范围,如上例所示。
正如您在其中一条评论中所建议的,我使用 TODAY
作为对应于 Total Return
列的日期。如果不是这种情况,则很容易更改。
另外请注意,我没有使用 "forXIRR" 列,而只是使用了 NetAmount
列的负数。如果删除 forXIRR
列,则需要将引用更改为 .TotalReturn
我创建了一个自定义 Class 以使事情更容易理解。
插入 Class 模块后,必须重命名 cFUND
Class 模块
Option Explicit
'Rename cFUND
Private pFund As String
Private pPurchDt As Date
Private pPurchDts As Collection
Private pPurchAmt As Double
Private pPurchAmts As Collection
Private pTotalReturn As Double
Private pTotalReturns As Collection
Public Property Get Fund() As String
Fund = pFund
End Property
Public Property Let Fund(Value As String)
pFund = Value
End Property
Public Property Get PurchDt() As Date
PurchDt = pPurchDt
End Property
Public Property Let PurchDt(Value As Date)
pPurchDt = Value
End Property
Public Function ADDPurchDt(Value As Date)
pPurchDts.Add Value
End Function
Public Property Get PurchDts() As Collection
Set PurchDts = pPurchDts
End Property
Public Property Get PurchAmt() As Double
PurchAmt = pPurchAmt
End Property
Public Property Let PurchAmt(Value As Double)
pPurchAmt = Value
End Property
Public Function ADDPurchAmt(Value As Double)
pPurchAmts.Add Value
End Function
Public Property Get PurchAmts() As Collection
Set PurchAmts = pPurchAmts
End Property
Public Property Get TotalReturn() As Double
TotalReturn = pTotalReturn
End Property
Public Property Let TotalReturn(Value As Double)
pTotalReturn = Value
End Property
Public Function ADDTotalReturn(Value As Double)
pTotalReturns.Add Value
End Function
Public Property Get TotalReturns() As Collection
Set TotalReturns = pTotalReturns
End Property
Public Function CalcXIRR()
Dim v, d, w
Dim I As Long
With Me
ReDim d(.PurchDts.Count * 2 - 1)
ReDim v(UBound(d))
I = 0
For Each w In .PurchAmts
v(I) = w
I = I + 1
Next w
For Each w In .TotalReturns
v(I) = w
I = I + 1
Next w
I = 0
For Each w In .PurchDts
d(I) = w
I = I + 1
Next w
Do Until I > UBound(d)
d(I) = Date
I = I + 1
Loop
End With
CalcXIRR = WorksheetFunction.XIRR(v, d)
End Function
Private Sub Class_Initialize()
Set pPurchDts = New Collection
Set pPurchAmts = New Collection
Set pTotalReturns = New Collection
End Sub
常规模块
Option Explicit
Function fundXIRR(sFund As String, rTable As Range) As Double
Dim vSrc As Variant
Dim cF As cFUND
Dim I As Long
vSrc = rTable
Set cF = New cFUND
For I = 2 To UBound(vSrc, 1)
If vSrc(I, 2) = sFund Then
With cF
.PurchDt = vSrc(I, 1)
.ADDPurchDt .PurchDt
.Fund = vSrc(I, 2)
.PurchAmt = -vSrc(I, 5)
.ADDPurchAmt .PurchAmt
.TotalReturn = vSrc(I, 7)
.ADDTotalReturn .TotalReturn
End With
End If
Next I
fundXIRR = cF.CalcXIRR
End Function
根据上面的数据,B
的 XIRR
将计算为:
XIRR({-35000;-50000;43000;61500},{"1/8/2015";"1/14/2015";"8/29/2016";"8/29/2016"}
以下是您上述数据的结果: