Usando el método de Monte Carlo para crear una cartera

Los inversores principiantes (y no solo) a menudo se preguntan cómo elegir la proporción ideal de activos incluidos en la cartera. A menudo (o no muy, pero sé que hay dos) para algunos corredores, esta función la realiza un robot comercial. Pero los algoritmos incrustados en ellos no se revelan.

Esta publicación cubrirá cómo optimizar una cartera utilizando simulaciones de Python y Monte Carlo. La optimización de la cartera se entiende como una relación de pesos que satisfará una de las condiciones:

  • Una cartera con un nivel mínimo de riesgo con la rentabilidad deseada;
  • Cartera con máxima rentabilidad a riesgo establecido;
  • Portafolio con máximo rendimiento

Para el cálculo, tomaremos nueve acciones recomendadas por el robot comercial de uno de los corredores a principios de enero de 2020 y también estableceremos los pesos óptimos para ellos en la cartera: 'ATVI', 'BA', 'CNP', 'CMA', 'STZ', 'GPN', 'MPC', 'NEM' y 'PKI'. Para el análisis, tomaremos datos de existencias de los últimos tres años.

# 

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') 


Si suma la participación de todas las acciones incluidas en la cartera, entonces el monto debería tender a uno (o más bien ser igual). Luego, como de costumbre, prepararemos los datos para los 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()

Ahora puede calcular los pesos ofrecidos por el robot comercial y descubrir la rentabilidad de esta cartera durante los últimos tres años y la desviación estándar.

#    
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) 

imagen

simulación del Monte Carlo


Inicialmente, una pequeña introducción sobre cómo se utiliza el método de Montecarlo para optimizar la cartera.

Primero, se otorgan ponderaciones aleatorias a las acciones, luego de lo cual se calcula el rendimiento y la desviación estándar. Los valores resultantes se guardan. El siguiente paso es cambiar aleatoriamente los pesos (lo principal es no olvidar que su suma debe ser uno) y todo se repite, calculando y guardando el valor obtenido. El número de iteraciones depende del tiempo, las capacidades informáticas para el cálculo y los riesgos que el inversor está listo para aceptar. Esta vez intentaremos hacer 10.000 cálculos para identificar una cartera con una pérdida mínima y una relación máxima de Sharpe.

#   
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]])

Ahora puede calcular la cartera con la relación máxima de Sharpe o el riesgo 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)

imagen

imagen

Bueno, la idea más importante se puede obtener cuando visualiza los datos:

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()

imagen

La cartera con la relación máxima de Sharpe se muestra con una estrella roja, azul, con una desviación estándar mínima y verde, propuesta por el robot. Como puede ver, la cartera propuesta por el robot no coincide con estos indicadores, pero el inversor tiene la opción de elegir la cartera. E intentaré a fin de año volver a comparar carteras. Y ahora las tres carteras están en baja.

All Articles