Advertisement
ne1ss

portfolio optimization - markowitz

Nov 5th, 2018
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.95 KB | None | 0 0
  1. import numpy as np
  2. from scipy import stats
  3. import pandas as pd
  4. from pandas_datareader import data as pdr
  5. import datetime
  6. import matplotlib.pyplot as plt
  7. import fix_yahoo_finance as yf
  8. yf.pdr_override()
  9. import scipy.optimize as optimization
  10.  
  11.  
  12. #Definições globais
  13. janelaMovel = 1800
  14. janelaMovelResultado = int (janelaMovel*0.69)
  15.  
  16. #esses são os ativos que escolhemos para nosso portifólio
  17.  
  18. stocks = ['PETR4.SA', 'ITUB4.SA', 'BBDC4.SA', 'BBAS3.SA', 'ABEV3.SA']
  19.  
  20.  
  21. #nós usamos a base historica para aproximar média e variância: MPT depende da base histórica !!!
  22. #fazer um parametro n para laço de repetição, mudar so n com intervalo que eu quero ~~ testar todos anos
  23.  
  24.  
  25.  
  26. #baixando a base de dados do Yahoo! Finance
  27. def download_data(stocks, comeco, fim):
  28.     data = pdr.get_data_yahoo(stocks, start=comeco, end=fim)['Adj Close']
  29.     return data
  30.  
  31.  
  32. #verificando se a distribuição de retornos é similar ao comportamento de uma normal
  33. def show_data(data):
  34.     data.plot(figsize=(10,5))
  35.     daily_returns = (data/data.shift(1))-1
  36.     daily_returns.hist(bins=100)
  37.     plt.show()
  38.  
  39.  
  40. #nos geralmente usamos logaritmo natural para normalizar os dados
  41. def calculate_returns(data):
  42.     returns = np.log(data/data.shift(1))
  43.     return returns;
  44.    
  45. def plot_daily_returns(returns):
  46.     returns.plot(figsize=(10,5))
  47.     plt.show()
  48.  
  49. #printando a media e a covariancia dos ativos entre as datas;
  50. def show_statistics(returns):
  51.     print(returns.mean()*janelaMovelResultado)
  52.     print(returns.cov()*janelaMovelResultado)
  53.  
  54. #definindo o peso dos ativos no portifolio de forma randomica
  55. def initialize_weights():
  56.     weights = np.random.random(len(stocks))
  57.     weights /= np.sum(weights)
  58.     return weights;
  59.    
  60. #retorno esperado com base nos pesos randomicos
  61. def calculate_portfolio_return(returns, weights):
  62.     portfolio_return = np.sum(returns.mean()*weights)*janelaMovelResultado
  63.     print("Retorno esperado do portfolio:", portfolio_return)
  64.  
  65. #variancia esperada do mesmo portifolio randomico
  66. def calculate_portfolio_variance(returns, weights):
  67.     portfolio_variance = np.sqrt(abs(np.dot(weights.T, np.dot(returns.cov()*janelaMovelResultado,weights))))
  68.     print("Variancia esperada do portfolio:", portfolio_variance)
  69.  
  70. def generate_portfolios(weights, returns):
  71.  
  72.     preturns = []
  73.     pvariances = []
  74.  
  75.     #simulaçao de Monte-Carlo: no vamos gerar portifolios randomicos, com diferentes pesos de ativos
  76.     for i in range(1000000):
  77.         weights = np.random.random(len(stocks))
  78.         weights/=np.sum(weights)
  79.         preturns.append(np.sum(returns.mean()*weights)*janelaMovelResultado)
  80.         pvariances.append(np.sqrt(np.dot(weights.T,np.dot(returns.cov()*janelaMovelResultado,weights))))
  81.    
  82.     preturns = np.array(preturns)
  83.     pvariances = np.array(pvariances)
  84.     return preturns,pvariances
  85.  
  86. def plot_portfolios(returns, variances):
  87.     plt.figure(figsize=(10,6))
  88.     plt.scatter(variances,returns,c=returns/variances,marker='o')
  89.     plt.grid(True)
  90.     plt.xlabel('Volatilidade Esperada')
  91.     plt.ylabel('Retorno Esperado')
  92.     plt.colorbar(label='Indice de Sharpe')
  93.     plt.show()
  94.  
  95. # Ook, temos um resultado para simulaçao ... nos temos que encontrar agora o portifolio otimo
  96. # Algumas tecnicas de otimização !!! scipy pode otimizar funções (minimo/maximo)
  97. def statistics(weights, returns):
  98.     portfolio_return=np.sum(returns.mean()*weights)*janelaMovelResultado
  99.     portfolio_volatility=np.sqrt(np.dot(weights.T,np.dot(returns.cov()*janelaMovelResultado,weights)))
  100.     return np.array([portfolio_return,portfolio_volatility,portfolio_return/portfolio_volatility])
  101.  
  102. # [2] media é o que queremos maximizar de acordo com o indice de sharpe
  103. # note: maximizando f(x) é o mesmo que minimizar -f(x) !!!
  104. def min_func_sharpe(weights,returns):
  105.     return  -statistics(weights,returns)[2]
  106.    
  107. # what are the constraints? The sum of weights = 1 !!!  f(x)=0 this is the function to minimize
  108. def optimize_portfolio(weights,returns):
  109.     constraints = ( {'type':'eq','fun': lambda x: np.sum(x)-1})#, #a soma dos pesos é 1
  110.                 #{'type':'ineq','fun': lambda x: (10  - np.sum((x>=0)))},
  111.             #{'type':'ineq','fun': lambda x: 8 - np.sum((x>=0))})
  112.  
  113.  #quantidade de ativos eh maior igual a 8
  114.     bounds = tuple((0,1) for x in range(len(stocks))) #quando o peso for 1, estaremos investindo 100% em um único ativo
  115.     optimum=optimization.minimize(fun=min_func_sharpe,x0=weights,args=returns,method='SLSQP',bounds=bounds,constraints=constraints)
  116.     return optimum
  117.    
  118. # portifolio otimo de acordo com os pesos: 0 significa que n temos parcela alocada nesse ativo
  119. def print_optimal_portfolio(optimum, returns):
  120.     print("Pesos Otimos:", optimum['x'].round(5))
  121.     print("Retorno esperado, volatilidade e indice de Sharpe:", statistics(optimum['x'].round(5),returns))
  122.  
  123. def print_result(optimum, returns):
  124.     print("Pesos Otimos:", optimum['x'].round(5))
  125.     print("Retorno, volatilidade e indice de Sharpe:", statistics(optimum['x'].round(5),returns))
  126.  
  127. def show_optimal_portfolio(optimum, returns, preturns, pvariances):
  128.     plt.figure(figsize=(10,6))
  129.     plt.scatter(pvariances,preturns,c=preturns/pvariances,marker='o')
  130.     plt.grid(True)
  131.     plt.xlabel('Volatilidade Esperada')
  132.     plt.ylabel('Retorno Esperado')
  133.     plt.colorbar(label='Indice de Sharpe')
  134.     plt.plot(statistics(optimum['x'],returns)[1],statistics(optimum['x'],returns)[0],'g*',markersize=20.0)
  135.     plt.show()
  136.  
  137. def future (optimum, stocks, inicio, fim):
  138.     data = download_data(stocks, inicio, fim)
  139.     returns2 = calculate_returns(data)
  140.     #print_result(optimum, returns2)
  141.     return statistics(optimum['x'].round(5), returns2)
  142.  
  143.  
  144.  
  145. if __name__ == "__main__":
  146.  
  147.     start = pd.to_datetime('2013-01-01')
  148.     end = pd.to_datetime('2017-12-31')
  149.  
  150.     valoresAbsolutos = [1,0]   
  151.     n = 0
  152.  
  153.  
  154.  
  155.     while (start < (end - datetime.timedelta(days=janelaMovel))):
  156.         base = pd.to_datetime(start - datetime.timedelta(days=janelaMovel))
  157.         check = pd.to_datetime(start + datetime.timedelta(days=janelaMovel))
  158.  
  159.         print (base)
  160.         print (check)
  161.    
  162.         print ("Realizando o download da base de dados")
  163.         data = download_data(stocks, base, start)
  164.         show_data(data)
  165.         returns = calculate_returns(data)
  166.         plot_daily_returns(returns)
  167.    
  168.         show_statistics(returns)                       
  169.         weights=initialize_weights()
  170.         calculate_portfolio_return(returns,weights)
  171.         calculate_portfolio_variance(returns,weights)
  172.         preturns,pvariances=generate_portfolios(weights, returns)
  173.         plot_portfolios(preturns,pvariances)
  174.  
  175.         #print ('\n')
  176.         print ("O portfolio otimo e: ")
  177.  
  178.         optimum=optimize_portfolio(weights,returns)
  179.         print_optimal_portfolio(optimum, returns)
  180.         show_optimal_portfolio(optimum, returns, preturns, pvariances)
  181.    
  182.         #print ('\n')
  183.         #print ('\n')
  184.         print ("O desempenho do portfolio otimo foi de: ")
  185.         gain = future(optimum, stocks, start, check)
  186.  
  187.    
  188.        
  189.         n = n+1
  190.         valoresAbsolutos[0] = valoresAbsolutos[0] + valoresAbsolutos[0]*gain[0]
  191.         valoresAbsolutos[1] = float ((valoresAbsolutos[1] + gain[1]))
  192.  
  193.  
  194.         start = check
  195.         print ("----------------------------------------")
  196.  
  197. valoresAbsolutos[0] = valoresAbsolutos[0] - 1
  198. valoresAbsolutos[1] = float ((valoresAbsolutos[1] + gain[1]))
  199.  
  200. print (valoresAbsolutos)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement