quantstats icon indicating copy to clipboard operation
quantstats copied to clipboard

Update stats.py - fix cagr calculation

Open gnzsnz opened this issue 2 years ago • 21 comments

remove periods=252 parameter. cagr calculation done by dividing number of days by 365.

'years = (returns.index[-1] - returns.index[0]).days / periods' there is no rational for dividing number of days by anything other than 365.

fix 273 and 275

gnzsnz avatar Jul 15 '23 09:07 gnzsnz

The assumption is that the index only iterates over business days for which there are around 252 in year (by convention)

tschm avatar Jul 17 '23 03:07 tschm

The assumption is that the index only iterates over business days for which there are around 252 in year (by convention) years = (returns.index[-1] - returns.index[0]).days/252

if we use this assumption then period between 01/07/2005 -- 22/05/2023 will be approx 26 years. Hence this is essentially overestimating the years.

silvercrw1994 avatar Jul 17 '23 07:07 silvercrw1994

Hence this is essentially overestimating the years.

yes, this is exactly what is happening here.

num_days = returns.index[-1] - returns.index[0]).days the cagr function calculates the number of days like this. then does num_days/period to get years the problem is that using 252 gives the wrong number of years between 2 given dates. Using 365 fixes it.

the pull request is actually proposing to remove the periods parameter completely. the reason behind is that any value other than 365 will give the wrong number of years. And the wrong number of years impacts the CAGR. As the "A" in CARG stands for annual, then there is no need to have this as a parameter. Or at least, I can't think of a case where anything other than 365 would work. Unless the way of calculating num_days changes

gnzsnz avatar Jul 17 '23 11:07 gnzsnz

Unless the way of calculating num_days changes

Yes ".days" attribute does not consider trading days but calculates the actual number of days between two dates.

silvercrw1994 avatar Jul 17 '23 12:07 silvercrw1994

@gnzsnz, the period parameter shouldn't be removed because it will allow users to evaluate portfolios based on the time frame that's being observed. The value that is needed for the actual calculation is years = len(returns)/periods or res = abs(total + 1) ** (periods/len(returns)) - 1. The idea is based on the definition of CAGR discussed in the article linked below. This will allow users to calculate CAGR for any time period.

An alternative approach is to use log returns, but it's best to stick with normal returns because quantstats uses normal returns for most of its calculations. I compared log returns and normal CAGR approach on daily period, and I got approximately the same result. Using the CAGR function currently implemented in quantstats gives a different result.

If you could review your code and implement to version of CAGR discussed in the article, that would be great.

https://www.investopedia.com/terms/a/annualized-total-return.asp#:~:text=The%20main%20difference%20between%20them,two%20measures%20are%20the%20same.

tiloye avatar Jul 20 '23 17:07 tiloye

@tiloye thanks for your feedback. you really got me thinking. i did quite some reading to understand this better, but i have to say that I still think that we should remove the periods parameter. I think is the best alternative, and I've just realized that I got it right in the first place just by chance.

The thing is that Annualized Total Return and the Compound Annual Growth Rate (CAGR) are essentially the same. Now what really got me thinking was your point stating that we should be able to evaluate CAGR for any time period. And I realized that the periods parameter is not going to achieve that.

Basically we need to calculate the number of years for the returns time series (returns parameter) and we could do that in two different ways, one would be to use the current logic and get the actual number of days between start and end date. Another option is what you propose to get the length of the time series, or number of periods.

If we go for actual number of days as it's today, we need to use 365 as the denominator. if we use length we need use 252. But that's it it could be 365 or 252, and it should be aligned with the method used to calculate the number of days.

But in any case having a parameter for periods (which is basically our denominator) can only cause problems. Because anything other than the default will return a wrong number.

if we want to have the option to calculate returns over different periods, then we need to provide different periods in the returns series, not change the periods parameter.

Hope my point is clear. As I said before, I did not realize this until I really went into it.

gnzsnz avatar Jul 21 '23 10:07 gnzsnz

@gnzsnz, I get your point. If we are going to use the difference between the dates, then 365 should be the denominator. I also confirmed it holds for return series that isn't up to a year. Thanks for pointing that out.

tiloye avatar Jul 21 '23 13:07 tiloye

@ranaroussi are you OK with this PR?

gnzsnz avatar Aug 06 '23 17:08 gnzsnz

This looks good to me, does this also take care of some other possible metrics miscalculations introduced with the period parameter changes? If everything else looks properly calculated with this PR, please merge asap

Newtoniano avatar Aug 07 '23 21:08 Newtoniano

@ranaroussi kind reminder

gnzsnz avatar Sep 02 '23 07:09 gnzsnz

is this project abandoned? tons of unsolved PRs

jmy12k3 avatar Jan 27 '24 20:01 jmy12k3

#323 is still open

gnzsnz avatar Jan 27 '24 22:01 gnzsnz

Since this library no longer seems to be maintained, we have created a duplicate of it that we plan to maintain and improve over time. If you'd like to use our version check it out here: https://github.com/Lumiwealth/quantstats_lumi

Please feel free to fork and send your pull request to this new library, we will be actively monitoring the library and approving PRs

grzesir avatar Jan 31 '24 23:01 grzesir

Since this library no longer seems to be maintained, we have created a duplicate of it that we plan to maintain and improve over time. If you'd like to use our version check it out here: https://github.com/Lumiwealth/quanstats_lumi

Please feel free to fork and send your pull request to this new library, we will be actively monitoring the library and approving PRs

Cool library, Nice! I will surely take a look at it.

jmy12k3 avatar Feb 01 '24 07:02 jmy12k3

Sounds good. Feel free to send over and PRs to this new library, we will be monitoring and maintaining this library

Robert Grzesik 347-635-3416

On Thu, Feb 1, 2024 at 2:14 AM Kaho Fan @.***> wrote:

Since this library no longer seems to be maintained, we have created a duplicate of it that we plan to maintain and improve over time. If you'd like to use our version check it out here: https://github.com/Lumiwealth/quanstats_lumi

Please feel free to fork and send your pull request to this new library, we will be actively monitoring the library and approving PRs

Cool library, Nice! I will surely take a look at it.

— Reply to this email directly, view it on GitHub https://github.com/ranaroussi/quantstats/pull/281#issuecomment-1920651293, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIYQKZO3ZHJAFEWR2IH6HDYRM6HHAVCNFSM6AAAAAA2LFNQ4OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMRQGY2TCMRZGM . You are receiving this because you commented.Message ID: @.***>

grzesir avatar Feb 01 '24 20:02 grzesir

have you included this PR on your repo? or shall i create a new PR on yours

please let me know, i'm happy to help

On Thu, Feb 1, 2024 at 9:53 PM Robert Grzesik @.***> wrote:

Sounds good. Feel free to send over and PRs to this new library, we will be monitoring and maintaining this library

Robert Grzesik 347-635-3416

On Thu, Feb 1, 2024 at 2:14 AM Kaho Fan @.***> wrote:

Since this library no longer seems to be maintained, we have created a duplicate of it that we plan to maintain and improve over time. If you'd like to use our version check it out here: https://github.com/Lumiwealth/quanstats_lumi

Please feel free to fork and send your pull request to this new library, we will be actively monitoring the library and approving PRs

Cool library, Nice! I will surely take a look at it.

— Reply to this email directly, view it on GitHub < https://github.com/ranaroussi/quantstats/pull/281#issuecomment-1920651293>,

or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAIYQKZO3ZHJAFEWR2IH6HDYRM6HHAVCNFSM6AAAAAA2LFNQ4OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMRQGY2TCMRZGM>

. You are receiving this because you commented.Message ID: @.***>

— Reply to this email directly, view it on GitHub https://github.com/ranaroussi/quantstats/pull/281#issuecomment-1922224399, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB75CQWTAK4QWM6WEBIMDLTYRP6EBAVCNFSM6AAAAAA2LFNQ4OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMRSGIZDIMZZHE . You are receiving this because you were mentioned.Message ID: @.***>

gnzsnz avatar Feb 03 '24 10:02 gnzsnz

I believe the CAGR calculation is already fixed in the new library, but you can double check if you want. The main reason I duplicated the quantstats library was because of this issue.

Robert Grzesik 347-635-3416

On Sat, Feb 3, 2024 at 5:48 AM gnzsnz @.***> wrote:

have you included this PR on your repo? or shall i create a new PR on yours

please let me know, i'm happy to help

On Thu, Feb 1, 2024 at 9:53 PM Robert Grzesik @.***> wrote:

Sounds good. Feel free to send over and PRs to this new library, we will be monitoring and maintaining this library

Robert Grzesik 347-635-3416

On Thu, Feb 1, 2024 at 2:14 AM Kaho Fan @.***> wrote:

Since this library no longer seems to be maintained, we have created a duplicate of it that we plan to maintain and improve over time. If you'd like to use our version check it out here: https://github.com/Lumiwealth/quanstats_lumi

Please feel free to fork and send your pull request to this new library, we will be actively monitoring the library and approving PRs

Cool library, Nice! I will surely take a look at it.

— Reply to this email directly, view it on GitHub <

https://github.com/ranaroussi/quantstats/pull/281#issuecomment-1920651293>,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAIYQKZO3ZHJAFEWR2IH6HDYRM6HHAVCNFSM6AAAAAA2LFNQ4OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMRQGY2TCMRZGM>

. You are receiving this because you commented.Message ID: @.***>

— Reply to this email directly, view it on GitHub < https://github.com/ranaroussi/quantstats/pull/281#issuecomment-1922224399>,

or unsubscribe < https://github.com/notifications/unsubscribe-auth/AB75CQWTAK4QWM6WEBIMDLTYRP6EBAVCNFSM6AAAAAA2LFNQ4OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMRSGIZDIMZZHE>

. You are receiving this because you were mentioned.Message ID: @.***>

— Reply to this email directly, view it on GitHub https://github.com/ranaroussi/quantstats/pull/281#issuecomment-1925273766, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIYQK7OXUQBGPVHBMF5TELYRYIWLAVCNFSM6AAAAAA2LFNQ4OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMRVGI3TGNZWGY . You are receiving this because you commented.Message ID: @.***>

grzesir avatar Feb 04 '24 00:02 grzesir

I don't have a good solution to this problem, but just wanted to note that setting periods=365 will only make results more accurate, but will not fix the problem entirely.

This calculation: years = (returns.index[-1] - returns.index[0]).days / periods wrongly assumes that the first and the last day is a trading day.

If these are not trading days, doing returns.index[-1] - returns.index[0] will always result in a number less than 365 and the whole cagr calculation will be a slight overestimation.

For example, lets choose a period 2020-01-01 to 2020-12-31. 2020-01-01 was a non trading day, so when _yf downloads returns, the Series will start at 2020-01-02. Doing (returns.index[-1] - returns.index[0]).days will be equal to 364

matt-the-catt avatar Apr 09 '24 11:04 matt-the-catt

Thanks for letting me know. I think we already use periods=365 right?

Robert Grzesik 347-635-3416

On Tue, Apr 9, 2024 at 7:19 AM matt-the-catt @.***> wrote:

I don't have a good solution to this problem, but just wanted to note that setting periods=365 will only make results more accurate, but will not fix the problem entirely.

This calculation: years = (returns.index[-1] - returns.index[0]).days / periods wrongly assumes that the first and the last day is a trading day.

If these are not a trading days, doing returns.index[-1] - returns.index[0] will always result in a number less than 365 and the whole cagr calculation will result in a slight overestimation.

— Reply to this email directly, view it on GitHub https://github.com/ranaroussi/quantstats/pull/281#issuecomment-2044789387, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIYQK7YG6MKZMG37XER5ADY4PFDJAVCNFSM6AAAAAA2LFNQ4OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBUG44DSMZYG4 . You are receiving this because you commented.Message ID: @.***>

grzesir avatar Apr 09 '24 19:04 grzesir

Since this library no longer seems to be maintained, we have created a duplicate of it that we plan to maintain and improve over time. If you'd like to use our version check it out here: https://github.com/Lumiwealth/quantstats_lumi

Please feel free to fork and send your pull request to this new library, we will be actively monitoring the library and approving PRs

@grzesir have you considered PEP 541, you can keep pypi package name if you apply for it. I understand that you need to create an issue under pypi support and tag it as PEP 541, here is an example https://github.com/pypi/support/issues/3932

gnzsnz avatar Apr 22 '24 16:04 gnzsnz