Skip to content

Commit 4dfd0e9

Browse files
authored
Merge pull request #16 from GrupoTuring/feature/rolling_beta
Implementa beta móvel
2 parents ca25dd7 + 31a267a commit 4dfd0e9

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
name="turingquant",
88
version="0.1.2",
99
packages=find_packages(),
10-
install_requires=["pandas", "pandas_datareader", "numpy", "matplotlib", "alpha_vantage", "bs4"],
10+
install_requires=["pandas", "pandas_datareader", "numpy", "matplotlib", "alpha_vantage", "bs4", "plotly"],
1111

1212
author="Grupo Turing",
1313
author_email="[email protected]",

turingquant/benchmark.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# %%
21
import pandas as pd
32
import matplotlib.pyplot as plt
43
from matplotlib.ticker import PercentFormatter

turingquant/metrics.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import numpy as np
2+
import pandas as pd
3+
import plotly.express as px
24

35

46
def sharpe_ratio(returns, risk_free=0):
@@ -25,7 +27,6 @@ def beta(returns, benchmark):
2527
2628
benchmark [pd.series]: série com o retorno do benchmark
2729
"""
28-
2930
concat = np.matrix([returns, benchmark])
3031
cov = np.cov(concat)[0][1]
3132
benchmark_vol = np.var(benchmark)
@@ -47,6 +48,62 @@ def alpha(end_price, dps, start_price):
4748
return(end_price + dps - start_price) / start_price
4849

4950

51+
# %%
52+
def rolling_beta(returns, benchmark, window, plot=True):
53+
"""
54+
Plota o beta móvel para um ativo e um benchmark de referência, na forma de séries de retornos.
55+
56+
Parâmetros:
57+
returns (array): série de retornos para o qual o beta será calculado.
58+
benchmark (array): série de retornos para usar de referência no cálculo do beta.
59+
window (int): janela móvel para calcular o beta ao longo do tempo.
60+
plot (bool): se `True`, plota um gráfico de linha com o beta ao longo do tempo.
61+
62+
Retorna:
63+
rolling_beta (pd.Series): uma série com os valores do Beta para os últimos `window` dias.
64+
A série não possui os `window` primeiros dias.
65+
66+
"""
67+
returns = pd.DataFrame(returns)
68+
benchmark = pd.DataFrame(benchmark)
69+
merged = returns.merge(benchmark, left_index=True, right_index=True)
70+
# one-liner meio ilegível mas: pega um array de NaN de numpy e junta com uma lista
71+
# que itera entre (window, len) e calcula o beta pros últimos `window` dias
72+
merged['rolling_beta'] = np.append(np.full(window, np.nan),
73+
[beta(merged.iloc[i - window:i, 0], merged.iloc[i - window:i, 1])
74+
for i in range(window, len(merged))]
75+
)
76+
merged = merged[window:]
77+
if plot:
78+
fig = px.line(merged['rolling_beta'], title="Beta móvel")
79+
overall_beta = beta(merged.iloc[:, 0], merged.iloc[:, 1])
80+
fig.update_layout(shapes=[
81+
dict(
82+
type='line',
83+
xref='paper', x0=0, x1=1,
84+
yref='y', y0=overall_beta, y1=overall_beta,
85+
line=dict(
86+
color='grey',
87+
width=2,
88+
dash='dash'
89+
)
90+
)
91+
], annotations=[
92+
dict(
93+
text='beta total: %.3f' % overall_beta,
94+
xref='paper', x=0.05,
95+
yref='y', y=overall_beta,
96+
xanchor='left'
97+
)
98+
])
99+
fig.update_layout(showlegend=False)
100+
fig.update_xaxes(title_text='Tempo')
101+
fig.update_yaxes(title_text='Beta móvel: ' + str(window) + ' períodos')
102+
fig.show()
103+
return merged['rolling_beta']
104+
105+
106+
# %%
50107
def test_metrics():
51108
"""
52109
Essa função define uma série aleatória de 50 elementos de retornos de um ativo fictício e de um índice de mercado e, a partir deles,

0 commit comments

Comments
 (0)