quantstats icon indicating copy to clipboard operation
quantstats copied to clipboard

compare cagr result with another python package

Open sugizo opened this issue 7 months ago • 5 comments

env google colab

code

pip install -U QuantStats openseries okama

from openseries import OpenTimeSeries
import yfinance as yf
import quantstats as qs
import okama as ok

ticker = 'AAPL' 
period = '5y' # 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max, etc
asset_list = ['AAPL.US']
ccy = 'USD'
first_date = '2020-05'

# openseries
stock = yf.Ticker(ticker = ticker)
history = stock.history(period = period)
series = OpenTimeSeries.from_df(dframe = history.loc[:, "Close"] )
print('Compound Annual Growth Rate (CAGR) :', series.geo_ret) 

# quantstats
qs.extend_pandas()
stock = qs.utils.download_returns(ticker = ticker, period = period)
print('Compound Annual Growth Rate (CAGR) :', stock.cagr() )

# okama
x = ok.AssetList(asset_list, ccy = ccy, first_date = first_date)
#x.describe(years = [1, 2, 3, 4, 5] )
x.get_cagr()

result Image

question why the cagr result value differs is so far with another python module ?

thanks and best regards

sugizo avatar May 17 '25 01:05 sugizo

Found the same problem, I have the followig values: starting value: 171978000 ending value: 414839000 period = 5 CAGR = 0.193

the .cagr() function calculates 0.173

Can't find what doing this at first sight.

tomdlc avatar May 19 '25 17:05 tomdlc

Found the same problem, I have the followig values: starting value: 171978000 ending value: 414839000 period = 5 CAGR = 0.193

the .cagr() function calculates 0.173

Can't find what doing this at first sight.

So the fix is in the "periods" variable for the cagr() function, it defaults to 252 days assuming you have daily data for the input, so in the case you are giving whole year values use cagr(periods=365).

tomdlc avatar May 19 '25 17:05 tomdlc

you right but when you use another function it won't affect the cagr value result even you already set the periods value e.g.

qs.reports.metrics(stock, periods_per_year = 252)
qs.reports.basic(stock, periods_per_year = 252)

detail explained here : https://github.com/CaptorAB/openseries/issues/291#issuecomment-2888422892

best regards

sugizo avatar May 20 '25 00:05 sugizo

Yeah I think you would have to work around that, the focus isn't on stock valuation rather than risk and performance

tomdlc avatar May 20 '25 07:05 tomdlc

it defaults to 252 days assuming you have daily data for the input

The problem is here:

years = (returns.index[-1] - returns.index[0]).days / periods

If you get the number of days you should divide by 365 fullstop.

Either:

  • periods should be replaced by 365 here
  • it should count the number of rows instead of days and keep dividing by periods

From 2024-01-01 to 2024-12-31 you have 365 days. It makes no sense to divide by any other number than 365

xaviergilbert avatar Jun 04 '25 07:06 xaviergilbert

The bug where CAGR did not accept the periods dynamically was fixed in version 0.0.64. Thanks for bringing this to my attention.

ranaroussi avatar Jul 18 '25 15:07 ranaroussi