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

Plotting "more than 9 assets" and "less than 126 days (daily frequency)" will cause index error #371

Open
daviddwlee84 opened this issue Oct 17, 2024 · 0 comments

Comments

@daviddwlee84
Copy link

Plotting more than 10 assets (i.e. passing DataFrame instead of Series) will cause the index out of range error because of not enough predefined colors

Code Tracing

_plots.returns(
returns,
benchmark,
grayscale=grayscale,
figsize=(8, 5),
subtitle=False,
savefig={"fname": figfile, "format": figfmt},
show=False,
ylabel=False,
cumulative=compounded,
prepare_returns=False,
)

fig = _core.plot_timeseries(
returns,
benchmark,
title,
ylabel=ylabel,
match_volatility=match_volatility,
log_scale=False,
resample=resample,
compound=compound,
cumulative=cumulative,
lw=lw,
figsize=figsize,
fontname=fontname,
grayscale=grayscale,
subtitle=subtitle,
savefig=savefig,
show=show,
)

Main Issue Part

elif isinstance(returns, _pd.DataFrame):
# color_dict = {col: colors[i+1] for i, col in enumerate(returns.columns)}
for i, col in enumerate(returns.columns):
ax.plot(returns[col], lw=lw, label=col, alpha=alpha, color=colors[i + 1])

_FLATUI_COLORS = [
"#FEDD78",
"#348DC1",
"#BA516B",
"#4FA487",
"#9B59B6",
"#613F66",
"#84B082",
"#DC136C",
"#559CAD",
"#4A5899",
]
_GRAYSCALE_COLORS = [
"#000000",
"#222222",
"#555555",
"#888888",
"#AAAAAA",
"#CCCCCC",
"#EEEEEE",
"#333333",
"#666666",
"#999999",
]
def _get_colors(grayscale):
colors = _FLATUI_COLORS
ls = "-"
alpha = 0.8
if grayscale:
colors = _GRAYSCALE_COLORS
ls = "-"
alpha = 0.5
return colors, ls, alpha

Reproducible Code

import pandas as pd
import numpy as np
import quantstats as qs

total_days = 10
returns = pd.DataFrame(np.random.randn(total_days, 11), index=pd.date_range('2024-01-01', periods=total_days, freq='D'))
qs.reports.full(returns) # failed

For the too less sample (days) data will cause another index error IndexError: index 0 is out of bounds for axis 0 with size 0

qs.reports.full(returns.iloc[:, :9])

Since we only have 10 days here, the default rolling period 126 which is much larger than it => returns got all NaN

def rolling_volatility(
returns, rolling_period=126, periods_per_year=252, prepare_returns=True
):
if prepare_returns:
returns = _utils._prepare_returns(returns, rolling_period)
return returns.rolling(rolling_period).std() * _np.sqrt(periods_per_year)

All NaN results will be dropped, thus try to set the title based on an empty DataFrame

elif isinstance(returns, _pd.DataFrame):
df = df[returns_label].dropna()
for i, col in enumerate(returns_label):
ax.plot(df[col], lw=lw, label=col, color=colors[i + 1])
# rotate and align the tick labels so they look better
fig.autofmt_xdate()
# use a more precise date string for the x axis locations in the toolbar
# ax.fmt_xdata = _mdates.DateFormatter('%Y-%m-%d')\
fig.suptitle(
title, y=0.94, fontweight="bold", fontname=fontname, fontsize=14, color="black"
)
if subtitle:
ax.set_title(
"%s - %s \n"
% (
df.index.date[:1][0].strftime("%e %b '%y"),
df.index.date[-1:][0].strftime("%e %b '%y"),
),
fontsize=12,
color="gray",
)

This works fine...

import pandas as pd
import numpy as np
import quantstats as qs

total_days = 126
returns = pd.DataFrame(np.random.randn(total_days, 9), index=pd.date_range('2024-01-01', periods=total_days, freq='D'))
qs.reports.full(returns)
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