diff --git a/setup.py b/setup.py index cc3c3bd..cfa8c05 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="turingquant", - version="0.1.2", + version="0.1.3", packages=find_packages(), install_requires=["pandas", "pandas_datareader", "numpy", "matplotlib", "alpha_vantage", "bs4", "plotly"], diff --git a/turingquant/metrics.py b/turingquant/metrics.py index b7233e3..15eafe1 100644 --- a/turingquant/metrics.py +++ b/turingquant/metrics.py @@ -63,19 +63,11 @@ def rolling_beta(returns, benchmark, window, plot=True): A série não possui os `window` primeiros dias. """ - returns = pd.DataFrame(returns) - benchmark = pd.DataFrame(benchmark) - merged = returns.merge(benchmark, left_index=True, right_index=True) - # one-liner meio ilegível mas: pega um array de NaN de numpy e junta com uma lista - # que itera entre (window, len) e calcula o beta pros últimos `window` dias - merged['rolling_beta'] = np.append(np.full(window, np.nan), - [beta(merged.iloc[i - window:i, 0], merged.iloc[i - window:i, 1]) - for i in range(window, len(merged))] - ) - merged = merged[window:] + rolling_beta = pd.Series([beta(returns[i-window:i], benchmark[i-window:i]) + for i in range(window, len(returns))], index=returns[window:].index) if plot: - fig = px.line(merged['rolling_beta'], title="Beta móvel") - overall_beta = beta(merged.iloc[:, 0], merged.iloc[:, 1]) + fig = px.line(rolling_beta, title="Beta móvel") + overall_beta = beta(returns, benchmark) fig.update_layout(shapes=[ dict( type='line', @@ -99,7 +91,53 @@ def rolling_beta(returns, benchmark, window, plot=True): fig.update_xaxes(title_text='Tempo') fig.update_yaxes(title_text='Beta móvel: ' + str(window) + ' períodos') fig.show() - return merged['rolling_beta'] + return rolling_beta + + +def rolling_sharpe(returns, window, risk_free=0, plot=True): + """ + Plota o beta móvel para um ativo e um benchmark de referência, na forma de séries de retornos. + + Parâmetros: + returns (array): série de retornos para o qual o Sharpe Ratio será calculado. + window (int): janela móvel para calcular o Sharpe ao longo do tempo. + risk_free (float): valor da taxa livre de risco para cálculo do Sharpe. + plot (bool): se `True`, plota um gráfico de linha com o Sharpe ao longo do tempo. + + Retorna: + rolling_beta (pd.Series): uma série com os valores do Beta para os últimos `window` dias. + A série não possui os `window` primeiros dias. + + """ + rolling_sharpe = pd.Series([sharpe_ratio(returns[i - window:i], risk_free) + for i in range(window, len(returns))], returns[window:].index) + if plot: + fig = px.line(rolling_sharpe, title="Sharpe móvel") + overall_sharpe = sharpe_ratio(returns, risk_free) + fig.update_layout(shapes=[ + dict( + type='line', + xref='paper', x0=0, x1=1, + yref='y', y0=overall_sharpe, y1=overall_sharpe, + line=dict( + color='grey', + width=2, + dash='dash' + ) + ) + ], annotations=[ + dict( + text='sharpe total: %.3f' % overall_sharpe, + xref='paper', x=0.05, + yref='y', y=overall_sharpe, + xanchor='left' + ) + ]) + fig.update_layout(showlegend=False) + fig.update_xaxes(title_text='Tempo') + fig.update_yaxes(title_text='Sharpe móvel: ' + str(window) + ' períodos') + fig.show() + return rolling_sharpe def rolling_sharpe(returns, window, risk_free=0, plot=True):