Usando o método Monte Carlo para criar um portfólio

Os investidores iniciantes (e não apenas) costumam se perguntar como escolher a proporção ideal de ativos incluídos no portfólio. Frequentemente (ou não muito, mas sei com certeza dois) para alguns corretores, essa função é executada por um robô de negociação. Mas os algoritmos incorporados neles não são divulgados.

Este post abordará como otimizar um portfólio usando simulações em Python e Monte Carlo. A otimização de portfólio é entendida como uma proporção de pesos que satisfaz uma das condições:

  • Um portfólio com um nível mínimo de risco com a lucratividade desejada;
  • Carteira com rentabilidade máxima com risco estabelecido;
  • Portfólio com rendimento máximo

Para o cálculo, tomaremos nove ações recomendadas pelo robô de negociação de uma das corretoras no início de janeiro de 2020 e também definiremos os pesos ideais para eles no portfólio: 'ATVI', 'BA', 'CNP', 'CMA', 'STZ', 'GPN', 'MPC', 'NEM' e 'PKI'. Para análise, coletaremos os dados dos últimos três anos.

# 

import pandas as pd
import yfinance as yf
import numpy as np
import matplotlib.pyplot as plt

#    
ticker = ['ATVI','BA','CNP','CMA', 'STZ','GPN','MPC','NEM', 'PKI']

stock = yf.download(ticker,'2017-01-01', '2019-01-31') 


Se você adicionar a parcela de todas as ações incluídas no portfólio, o valor deverá tender a um (ou melhor, igual). Então, como sempre, prepararemos os dados para os cálculos:

#    
all_adj_close = stock[['Adj Close']]

#  
all_returns = all_adj_close.pct_change()

#       
mean_returns = all_returns.mean()
cov_matrix = all_returns.cov()

Agora você pode calcular os pesos oferecidos pelo robô de negociação e descobrir a lucratividade desse portfólio nos últimos três anos e o desvio padrão.

#    
robot = np.array([0.0441, 0.1030, 0.1086, 0.2070, 0.1525, 0.0714, 0.0647, 0.1828, 0.0661])

# ,     
portfolio_return_robot = np.sum(mean_returns * robot)
portfolio_std_dev_robot = np.sqrt(np.dot(robot.T,np.dot(cov_matrix, robot)))
sharpo_robot = portfolio_return_robot/portfolio_std_dev_robot

#         
robot_result = np.array([portfolio_return_robot, portfolio_std_dev_robot, sharpo_robot])
robot_result = np.array([portfolio_return_robot, portfolio_std_dev_robot, sharpo_robot])
robot_result = np.concatenate((robot_result, robot), axis=0)
robot_sim_result = pd.DataFrame(robot_result, columns=['Robot'], index=['ret','stdev','sharpe',ticker[0],ticker[1],ticker[2],ticker[3],ticker[4],ticker[5],ticker[6],ticker[7],ticker[8]])

print(robot_sim_result) 

imagem

Simulação de Monte Carlo


Inicialmente, uma pequena introdução de como o método de Monte-Carlo é usado para otimizar o portfólio.Primeiro

, os pesos recebem pesos aleatórios, após os quais são calculados o rendimento e o desvio padrão. Os valores resultantes são salvos. O próximo passo é alterar aleatoriamente os pesos (o principal é não esquecer que a soma deve ser uma) e tudo se repete - calculando e salvando o valor obtido. O número de iterações depende do tempo, das capacidades do computador para cálculo e dos riscos que o investidor está pronto para aceitar. Desta vez, tentaremos fazer 10.000 cálculos para identificar um portfólio com uma perda mínima e uma taxa Sharpe máxima.

#   
num_iterations = 10000
simulation_res = np.zeros((4+len(ticker)-1,num_iterations))

#  
for i in range(num_iterations):
        #    ,    1
        weights = np.array(np.random.random(9))
        weights /= np.sum(weights)
        
        #    
        portfolio_return = np.sum(mean_returns * weights)
        portfolio_std_dev = np.sqrt(np.dot(weights.T,np.dot(cov_matrix, weights)))
        
        #     
        simulation_res[0,i] = portfolio_return
        simulation_res[1,i] = portfolio_std_dev
        
        #    
        simulation_res[2,i] = simulation_res[0,i] / simulation_res[1,i]
        
        # 
        for j in range(len(weights)):
                simulation_res[j+3,i] = weights[j]

#     DataFrame     .
sim_frame = pd.DataFrame(simulation_res.T,columns=['ret','stdev','sharpe',ticker[0],ticker[1],ticker[2],ticker[3],ticker[4],ticker[5],ticker[6],ticker[7],ticker[8]])

Agora você pode calcular o portfólio com a proporção Sharpe máxima ou risco mínimo.

#   Sharpe Ratio
max_sharpe = sim_frame.iloc[sim_frame['sharpe'].idxmax()]

#    
min_std = sim_frame.iloc[sim_frame['stdev'].idxmin()]

print ("The portfolio for max Sharpe Ratio:\n", max_sharpe)
print ("The portfolio for min risk:\n", min_std)

imagem

imagem

Bem, a idéia mais importante pode ser obtida quando você visualiza os dados:

fig, ax = plt.subplots(figsize=(10, 10))

#    scatter plot        x      y

plt.scatter(sim_frame.stdev,sim_frame.ret,c=sim_frame.sharpe,cmap='RdYlBu')
plt.xlabel('Standard Deviation')
plt.ylabel('Returns')
plt.ylim(0,.0015)
plt.xlim(0.007,0.012)

plt.scatter(max_sharpe[1],max_sharpe[0],marker=(5,1,0),color='r',s=600)

plt.scatter(min_std[1],min_std[0],marker=(5,1,0),color='b',s=600)

plt.scatter(portfolio_std_dev_robot, portfolio_return_robot,marker=(5,1,0),color='g',s=600)

plt.show()

imagem

O portfólio com a proporção máxima de Sharpe é mostrado por uma estrela vermelha, azul - com um desvio padrão mínimo e verde - proposta pelo robô. Como você pode ver, o portfólio proposto pelo robô não coincide com esses indicadores, mas o investidor fica com a escolha do portfólio. E tentarei no final do ano voltar a comparar portfólios. E agora todos os três portfólios estão em rebaixamento.

All Articles