Forum Discussion
Rolling XIRR Calculation
- 9 years ago
Hi v-ljerr-msft,
Thank you very much for your help!
The formula works great, although I have made a few tweaks to include:
- a terminal value (from the [equity repayment/(investment) on sale] column) to be calculated at the end of each period and calculated in the XIRR calc (i.e. if I sold the investment now, what would my XIRR be), and
- a check to ensure that there is at least one positive cashflow (another requirement of the XIRR formula along with the first periof being negative).
see my code as follows fyi....
ROLLING XIRR = VAR countpos = CALCULATE( COUNT('INVESTMENT RETURNS'[totalcashflow]), FILTER(ALL('INVESTMENT RETURNS'), 'INVESTMENT RETURNS'[totalcashflow]>0 && EARLIER ('INVESTMENT RETURNS'[Index] ) >= 'INVESTMENT RETURNS'[Index] && 'INVESTMENT RETURNS'[Name] = EARLIER ( 'INVESTMENT RETURNS'[Name] ) ) ) VAR minIndex = CALCULATE ( MIN ( 'INVESTMENT RETURNS'[Index] ), FILTER ( ALL ( 'INVESTMENT RETURNS' ), 'INVESTMENT RETURNS'[Name] = EARLIER ( 'INVESTMENT RETURNS'[Name] ) ) ) VAR firstValue = CALCULATE ( MIN ( 'INVESTMENT RETURNS'[FREE CASHFLOW FOR PERIOD (excl. sale)] ), FILTER ( ALL ( 'INVESTMENT RETURNS' ), 'INVESTMENT RETURNS'[Name] = EARLIER ( 'INVESTMENT RETURNS'[Name] ) && 'INVESTMENT RETURNS'[Index] = minIndex ) ) RETURN IF ( 'INVESTMENT RETURNS'[Index] > minIndex && firstValue < 0 && countpos >= 1 , XIRR ( UNION( SUMMARIZE( FILTER(ALL ( 'INVESTMENT RETURNS' ), EARLIER ('INVESTMENT RETURNS'[Index] ) >= 'INVESTMENT RETURNS'[Index] && 'INVESTMENT RETURNS'[Name] = EARLIER ( 'INVESTMENT RETURNS'[Name] )) ,'INVESTMENT RETURNS'[Index], "DATE1",MAX('INVESTMENT RETURNS'[DATE]), "CASHFLOW",MAX('INVESTMENT RETURNS'[FREE CASHFLOW FOR PERIOD (excl. sale)]) ), SUMMARIZE( FILTER(ALL ( 'INVESTMENT RETURNS' ), EARLIER ('INVESTMENT RETURNS'[Index] ) = 'INVESTMENT RETURNS'[Index] ), 'INVESTMENT RETURNS'[Index], "DATE1",MAX('INVESTMENT RETURNS'[DATE]), "CASHFLOW",MAX('INVESTMENT RETURNS'[EQUITY REPAYMENT/(INVESTMENT) ON SALE]) ) ), [CASHFLOW], [DATE1] ) )Thanks again for all your help. Much appreciated.
MJ
Hi v-ljerr-msft and mjfigg
I evaluated this post, and I think the solution would work for my purposes with one slight tweak that I can't seem to figure out. My data is in a PBIX table that is CROSSJOINED, so has, out of necessity, blanks or 0 values and I think the XIRR function is having trouble because of the blanks.
Link to sample excel data: https://www.dropbox.com/s/hc3qx9y9jvs4n4k/Rolling%20XIRR.xlsx?dl=0
Essentially my data looks like this (from Excel and the desired Rolling XIRR column, as calculated in Excel, is shown).
| Asset ID | Period | Cash Flow | Month | Rolling IRR |
| X | 0 | -1000 | 4/30/2019 | |
| X | 1 | 130 | 5/31/2019 | |
| X | 2 | 130 | 6/30/2019 | -100.0% |
| X | 3 | 130 | 7/31/2019 | -99.5% |
| X | 4 | 130 | 8/31/2019 | -94.7% |
| X | 5 | 525 | 9/30/2019 | 15.0% |
| X | 6 | 10/31/2019 | 15.0% | |
| X | 7 | 11/30/2019 | 15.0% | |
| X | 8 | 12/31/2019 | 15.0% | |
| X | 9 | 1/31/2020 | 15.0% | |
| Y | 0 | -2000 | 5/31/2019 | |
| Y | 1 | 250 | 6/30/2019 | |
| Y | 2 | 250 | 7/31/2019 | -100.0% |
| Y | 3 | 250 | 8/31/2019 | -99.6% |
| Y | 4 | 250 | 9/30/2019 | -95.6% |
| Y | 5 | 250 | 10/31/2019 | -83.2% |
| Y | 6 | 250 | 11/30/2019 | -61.4% |
| Y | 7 | 250 | 12/31/2019 | -32.5% |
| Y | 8 | 250 | 1/31/2020 | 0.0% |
| Y | 9 | 125 | 2/29/2020 | 16.6% |
| Z | 0 | -1500 | 6/30/2019 | |
| Z | 1 | 175 | 7/31/2019 | |
| Z | 2 | 175 | 8/31/2019 | -100.0% |
| Z | 3 | 175 | 9/30/2019 | -99.7% |
| Z | 4 | 175 | 10/31/2019 | -96.6% |
| Z | 5 | 175 | 11/30/2019 | -86.8% |
| Z | 6 | 175 | 12/31/2019 | -68.8% |
| Z | 7 | 550 | 1/31/2020 | 17.8% |
| Z | 8 | 2/29/2020 | 17.8% | |
| Z | 9 | 3/31/2020 | 17.8% |
Hey mrothschild ,
I managed to get it working for you!
see file here: MJFIGG Updated file
What I did was just use my original code which has two key differences to yours:
- Index - which I have found to be easier when using the EARLIER function, and
- Free Cashflow Capital - This is an optional column and is not strictly needed. For my purposes it was important because I needed to distinguish between Free Cashflow before Capital and potential capital payments. In your case I have just set this to 0 for all months. Essentially you now have two cashflow columns if you ever need it.
I could rewrite the code to remove the Free Cashflow Capital column, but I preferred to just get it finished for you.
Hopefully this helps!!
All the best,
MJ
- mrothschild7 years agoContinued Contributor
Thank you so much!
One question I have is that my actual table, as opposed to the sample data I posted, is calculated using CROSSJOIN, so doesn't actually show up in PowerQuery editor. As a result, there's no easy way to create the Index column you used. I'll search the forums for how to create this, but if you have any ideas without using PowerQuery, that would be the final piece.
Regardless, thanks again!
- mjfigg7 years agoFrequent Visitor
I updated the file again if you want to download it agin. I had a quick read online and it seems quite difficult to get an index in DAX rather than PowerQuery. I managed to come up with a very rough work around though for your case. Essentially arbitrarily allocating a greatly ascending value to your AssetID then multiplying that number by the period value. The result in this case being that each row has a unique value to it and then the RANK function can order them as an index would.
This solution works now but may not work for every instance of data that you want to report on :smileyfrustrated:. Only other thing I can suggest at the moment is to try and play around with your query so you can manipulate it in powerquery. Let me know if you need some help with that...
All the best...
- mrothschild7 years agoContinued Contributor
** Update **
I think what you did was this?
zzNew_Portfolio_Outputs[Period] + RANKX(zzNew_Portfolio_Outputs,zzNew_Portfolio_Outputs[Asset ID])
which creates an arbitrary index column.
Apologies and maybe I made a mistake, but the updated file (to me) looks like the original and I don't see a calculated index column or anything resembling RANK or transformation of Asset ID. Again, error is likely mine, but I think I'm missing something significant.
- mrothschild7 years agoContinued Contributor
Really appreciate your help. I tried to start with simple data and was triangulating to a solution as a result, but when I applied to the larger dataset, I'm getting an error that XIRR can't find a solution. Again, I'm assuming it has to do with blank cells and I'm respectful of your time, so if this is overwhelming or I'm crazy to try to do this in its current form, let me know and I'll try a different path.
Here's the link to the larger dataset that has your programming contained only changed by my attempt to create the calcualted DAX index.
https://www.dropbox.com/s/lo8m59ach4v3bf8/Rolling%20XIRR%20-%20new%20.pbix?dl=0