Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stats.py: res = abs(total + 1.0) ** (1.0 / years) - 1 <-- ZeroDivisionErrorZeroDivisionError #334

Open
normanlmfung opened this issue Feb 22, 2024 · 1 comment

Comments

@normanlmfung
Copy link

hi Team,

stats.py: res = abs(total + 1.0) ** (1.0 / years) - 1 <-- ZeroDivisionError

 3 import quantstats as qs
      5 RISK_FREE_RATE = 0.05 # 5%
----> 7 qs.reports.full(
      8     returns=pd_total_equity['interval_return'], 
      9     rf=RISK_FREE_RATE,
     10     title="Tear Sheet"
     11     )


File ~\AppData\Roaming\Python\Python39\site-packages\quantstats\reports.py:839, in metrics(returns, benchmark, rf, display, mode, sep, compounded, periods_per_year, prepare_returns, match_dates, **kwargs)
    836 else:
    837     metrics["Total Return %"] = (df.sum() * pct).map("{:,.2f}".format)
--> 839 metrics["CAGR﹪%"] = _stats.cagr(df, rf, compounded) * pct
    841 metrics["~~~~~~~~~~~~~~"] = blank
    843 metrics["Sharpe"] = _stats.sharpe(df, rf, win_year, True)

File ~\AppData\Roaming\Python\Python39\site-packages\quantstats\stats.py:531, in cagr(returns, rf, compounded, periods)
    527     total = _np.sum(total)
    529 years = (returns.index[-1] - returns.index[0]).days / periods
--> 531 res = abs(total + 1.0) ** (1.0 / **years**) - 1
    533 if isinstance(returns, _pd.DataFrame):
    534     res = _pd.Series(res)

**ZeroDivisionError**: float division by zero

To reproduce, use this sample file: singlelegta_total_equity_cache_4.csv

from datetime import datetime
import arrow
import pandas as pd
import numpy as np
src_file = './total_equity/singlelegta_total_equity_cache_4.csv'
pd_total_equity = pd.read_csv(src_file)
pd_total_equity['datetime'] = pd.to_datetime(pd_total_equity['interval'])
pd_total_equity.set_index('datetime', inplace=True)
pd_total_equity['interval_return'] = pd_total_equity['total_equity'].pct_change()
pd_total_equity['cumulative_interval_return'] = (1 + pd_total_equity['interval_return']).cumprod()
pd_total_equity = pd_total_equity[~pd_total_equity.interval_return.isna()]
pd_total_equity

%matplotlib inline
import quantstats as qs

RISK_FREE_RATE = 0.05 # 5%

qs.reports.full(
    returns=pd_total_equity['interval_return'], 
    rf=RISK_FREE_RATE,
    title="Tear Sheet"
    )



@normanlmfung
Copy link
Author

I temporarily fixed by setting 'res' to zero when year==0:

def cagr(returns, rf=0.0, compounded=True, periods=252):
    """
    Calculates the communicative annualized growth return
    (CAGR%) of access returns

    If rf is non-zero, you must specify periods.
    In this case, rf is assumed to be expressed in yearly (annualized) terms
    """
    total = _utils._prepare_returns(returns, rf)
    if compounded:
        total = comp(total)
    else:
        total = _np.sum(total)

    # Bug: https://github.com/ranaroussi/quantstats/issues/334
    years = (returns.index[-1] - returns.index[0]).days / periods

    res = abs(total + 1.0) ** (1.0 / years) - 1 if years!=0 else 0
    
    if res and isinstance(returns, _pd.DataFrame):
        res = _pd.Series(res)
        res.index = returns.columns

    return res

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant