Skip to content

Commit 196829e

Browse files
Adiciona módulo de otimizadores com implementação de Markowitz
1 parent 4ffba0d commit 196829e

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

turingquant/optimizers.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
'''Módulo para otimização de portfólios.'''
2+
3+
import pandas as pd
4+
import numpy as np
5+
import matplotlib.pyplot as plt
6+
7+
8+
class Markowitz:
9+
'''
10+
Otimizador baseado na Teoria Moderna do Portfólio, de Harry Markowitz.
11+
A partir dos dados de fechamento, gera portfólios com pesos aleatórios e calcula
12+
os melhores pesos utilizando o risco e retorno da carteira.
13+
14+
Parâmetros:
15+
df_close (pd.DataFrame): DataFrame com os preços de fechamento dos ativos
16+
num_portfolios (int): números de portfólios gerados
17+
risk_free (float): taxa de risco livre utilizada para cálculo do sharpe ratio.
18+
19+
Atributos:
20+
wallets (dict): dicionário contendo os valores 'weights', 'returns', 'vol' e 'sharpe_ratio'
21+
de todos os portfólios gerados
22+
23+
'''
24+
def __init__(self, df_close, num_portfolios = 10000, risk_free = 0):
25+
self.df = df_close
26+
self.num_portfolios = num_portfolios
27+
self.risk_free = risk_free
28+
29+
# vetores de dados
30+
portfolio_weights = []
31+
portfolio_exp_returns = []
32+
portfolio_vol = []
33+
portfolio_sharpe = []
34+
35+
# retorno simples
36+
r = df.pct_change()
37+
mean_returns = r.mean() * 252
38+
39+
# matriz de covariância
40+
covariance = np.cov(r[1:].T)
41+
42+
for i in range(self.num_portfolios):
43+
# gerando pesos aleatórios
44+
k = np.random.rand(len(df.columns))
45+
w = k / sum (k)
46+
47+
# retorno
48+
R = np.dot(mean_returns, w)
49+
50+
# risco
51+
vol = np.sqrt(np.dot(w.T, np.dot(covariance, w))) * np.sqrt(252)
52+
53+
# sharpe ratio
54+
sharpe = (R - self.risk_free)/vol
55+
56+
portfolio_weights.append(w)
57+
portfolio_exp_returns.append(R)
58+
portfolio_vol.append(vol)
59+
portfolio_sharpe.append(sharpe)
60+
61+
self.wallets = {'weights': portfolio_weights,
62+
'returns': portfolio_exp_returns,
63+
'vol':portfolio_vol,
64+
'sharpe': portfolio_sharpe}
65+
66+
def plot_efficient_frontier(self, method = 'sharpe_ratio'):
67+
'''
68+
Plota gráfico com a fronteira eficiente dos portfólios gerados.
69+
70+
Args:
71+
method (string): Método utilizado para indicar o melhor portfólio
72+
'sharpe_ratio' - Portfólio com melhor Sharpe ratio
73+
'volatility' - Portfólio com menor volatilidade
74+
'return' - Portfólio com maior retorno
75+
76+
'''
77+
vol = self.wallets['vol']
78+
returns = self.wallets['returns']
79+
sharpe = self.wallets['sharpe']
80+
81+
if method == 'sharpe_ratio':
82+
83+
indice = np.array(sharpe).argmax()
84+
y_axis = returns[indice]
85+
X_axis = vol[indice]
86+
87+
elif method == 'volatility':
88+
89+
indice = np.array(vol).argmin()
90+
y_axis = returns[indice]
91+
X_axis = vol[indice]
92+
93+
elif method == 'return':
94+
95+
indice = np.array(returns).argmax()
96+
y_axis = returns[indice]
97+
X_axis = vol[indice]
98+
99+
plt.scatter(vol, returns, c = sharpe, cmap = 'viridis')
100+
plt.scatter(X_axis, y_axis, c = 'red', s = 50)
101+
plt.title("Efficient Frontier")
102+
plt.xlabel("Volatility")
103+
plt.ylabel("Expected return")
104+
plt.show()
105+
106+
def best_portfolio(self, method = 'sharpe_ratio'):
107+
'''
108+
Retorna os pesos do melhor portfólio de acordo com o método escolhido.
109+
110+
Args:
111+
method (string): Método utilizado para indicar o melhor portfólio
112+
'sharpe_ratio' - Portfólio com melhor Sharpe ratio
113+
'volatility' - Portfólio com menor volatilidade
114+
'return' - Portfólio com maior retorno
115+
Returns:
116+
weights (np.array): Numpy array contendo os pesos do melhor portfólio.
117+
118+
'''
119+
120+
vol = self.wallets['vol']
121+
returns = self.wallets['returns']
122+
sharpe = self.wallets['sharpe']
123+
weights = self.wallets['weights']
124+
125+
if method == 'sharpe_ratio':
126+
127+
indice = np.array(sharpe).argmax()
128+
129+
elif method == 'volatility':
130+
131+
indice = np.array(vol).argmin()
132+
133+
elif method == 'return':
134+
135+
indice = np.array(returns).argmax()
136+
137+
return weights[indice]

0 commit comments

Comments
 (0)