Skip to content

Commit 203d8eb

Browse files
Merge pull request #47 from GrupoTuring/optimzers/Markowitz
Adiciona módulo de otimizadores com implementação de Markowitz
2 parents 4ffba0d + 3c01173 commit 203d8eb

File tree

2 files changed

+150
-1
lines changed

2 files changed

+150
-1
lines changed

turingquant/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from . import benchmark, metrics, support
1+
from . import benchmark, metrics, support, optimizers
22

turingquant/optimizers.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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+
self.wallets = self._generate_wallets()
29+
30+
def _generate_wallets(self):
31+
'''
32+
Gera carteiras com pesos aleatórios.
33+
34+
Returns:
35+
wallets (dict): dicionário contendo os valores 'weights', 'returns', 'vol' e 'sharpe_ratio'
36+
de todos os portfólios gerados
37+
'''
38+
# vetores de dados
39+
portfolio_weights = []
40+
portfolio_exp_returns = []
41+
portfolio_vol = []
42+
portfolio_sharpe = []
43+
44+
# retorno simples
45+
r = self.df.pct_change()
46+
mean_returns = r.mean() * 252
47+
48+
# matriz de covariância
49+
covariance = np.cov(r[1:].T)
50+
51+
for i in range(self.num_portfolios):
52+
# gerando pesos aleatórios
53+
k = np.random.rand(len(self.df.columns))
54+
w = k / sum (k)
55+
56+
# retorno
57+
R = np.dot(mean_returns, w)
58+
59+
# risco
60+
vol = np.sqrt(np.dot(w.T, np.dot(covariance, w))) * np.sqrt(252)
61+
62+
# sharpe ratio
63+
sharpe = (R - self.risk_free)/vol
64+
65+
portfolio_weights.append(w)
66+
portfolio_exp_returns.append(R)
67+
portfolio_vol.append(vol)
68+
portfolio_sharpe.append(sharpe)
69+
70+
wallets = {'weights': portfolio_weights,
71+
'returns': portfolio_exp_returns,
72+
'vol':portfolio_vol,
73+
'sharpe': portfolio_sharpe}
74+
75+
return wallets
76+
77+
def plot_efficient_frontier(self, method = 'sharpe_ratio'):
78+
'''
79+
Plota gráfico com a fronteira eficiente dos portfólios gerados.
80+
81+
Args:
82+
method (string): Método utilizado para indicar o melhor portfólio
83+
'sharpe_ratio' - Portfólio com melhor Sharpe ratio
84+
'volatility' - Portfólio com menor volatilidade
85+
'return' - Portfólio com maior retorno
86+
87+
'''
88+
vol = self.wallets['vol']
89+
returns = self.wallets['returns']
90+
sharpe = self.wallets['sharpe']
91+
92+
if method == 'sharpe_ratio':
93+
94+
indice = np.array(sharpe).argmax()
95+
y_axis = returns[indice]
96+
X_axis = vol[indice]
97+
98+
elif method == 'volatility':
99+
100+
indice = np.array(vol).argmin()
101+
y_axis = returns[indice]
102+
X_axis = vol[indice]
103+
104+
elif method == 'return':
105+
106+
indice = np.array(returns).argmax()
107+
y_axis = returns[indice]
108+
X_axis = vol[indice]
109+
110+
plt.scatter(vol, returns, c = sharpe, cmap = 'viridis')
111+
plt.scatter(X_axis, y_axis, c = 'red', s = 50)
112+
plt.title("Efficient Frontier")
113+
plt.xlabel("Volatility")
114+
plt.ylabel("Expected return")
115+
plt.show()
116+
117+
def best_portfolio(self, method = 'sharpe_ratio'):
118+
'''
119+
Retorna os pesos do melhor portfólio de acordo com o método escolhido.
120+
121+
Args:
122+
method (string): Método utilizado para indicar o melhor portfólio
123+
'sharpe_ratio' - Portfólio com melhor Sharpe ratio
124+
'volatility' - Portfólio com menor volatilidade
125+
'return' - Portfólio com maior retorno
126+
Returns:
127+
weights (np.array): Numpy array contendo os pesos do melhor portfólio.
128+
129+
'''
130+
131+
vol = self.wallets['vol']
132+
returns = self.wallets['returns']
133+
sharpe = self.wallets['sharpe']
134+
weights = self.wallets['weights']
135+
136+
if method == 'sharpe_ratio':
137+
138+
indice = np.array(sharpe).argmax()
139+
140+
elif method == 'volatility':
141+
142+
indice = np.array(vol).argmin()
143+
144+
elif method == 'return':
145+
146+
indice = np.array(returns).argmax()
147+
148+
return weights[indice]
149+

0 commit comments

Comments
 (0)