Utilisation de la méthode Monte Carlo pour créer un portfolio

Les investisseurs débutants (et pas seulement) se demandent souvent comment choisir le ratio idéal d'actifs inclus dans le portefeuille. Souvent (ou pas très, mais j'en connais deux à coup sûr) pour certains courtiers, cette fonction est réalisée par un robot de trading. Mais les algorithmes qui y sont intégrés ne sont pas divulgués.

Cet article couvrira comment optimiser un portefeuille en utilisant des simulations Python et Monte Carlo. L'optimisation de portefeuille est comprise comme un tel ratio de pondérations qui satisfera à l'une des conditions:

  • Un portefeuille avec un niveau de risque minimum avec la rentabilité souhaitée;
  • Portefeuille avec une rentabilité maximale à risque établi;
  • Portefeuille à rendement maximal

Pour le calcul, nous prendrons neuf actions recommandées par le robot de négociation de l'un des courtiers au début du mois de janvier 2020 et définirons également les pondérations optimales pour eux dans le portefeuille: «ATVI», «BA», «CNP», «CMA», «STZ», «GPN», «MPC», «NEM» et «PKI». Pour l'analyse, nous prendrons les données de stock pour les trois dernières années.

# 

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 vous additionnez la part de toutes les actions incluses dans le portefeuille, alors le montant devrait tendre à un (ou plutôt être égal). Ensuite, comme d'habitude, nous préparerons les données pour les calculs:

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

#  
all_returns = all_adj_close.pct_change()

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

Vous pouvez maintenant calculer les poids offerts par le robot de trading et connaître la rentabilité de ce portefeuille pour les trois dernières années et l'écart-type.

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

image

Simulation de Monte Carlo


Initialement, une petite introduction à la façon dont la méthode de Monte-Carlo est utilisée pour optimiser le portefeuille.

Premièrement, les pondérations sont attribuées de façon aléatoire, après quoi le rendement et l'écart-type sont calculés. Les valeurs résultantes sont enregistrées. L'étape suivante consiste à modifier aléatoirement les poids (l'essentiel est de ne pas oublier que leur somme doit être un) et tout se répète - calculer et enregistrer la valeur obtenue. Le nombre d'itérations dépend du temps, des capacités informatiques de calcul et des risques que l'investisseur est prêt à accepter. Cette fois, nous allons essayer de faire 10 000 calculs pour identifier un portefeuille avec une perte minimum et un ratio Sharpe maximum.

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

Vous pouvez maintenant calculer le portefeuille avec le ratio de Sharpe maximum ou le risque minimum.

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

image

image

Eh bien, l'idée la plus importante peut être obtenue lorsque vous visualisez les données:

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

image

Le portefeuille avec le ratio Sharpe maximum est représenté par une étoile rouge, bleue - avec un écart type minimum et verte - proposée par le robot. Comme vous pouvez le voir, le portefeuille proposé par le robot ne coïncide pas avec ces indicateurs, mais l'investisseur se retrouve avec le choix du portefeuille. Et je vais essayer à la fin de l'année de revenir à la comparaison des portefeuilles. Et maintenant, les trois portefeuilles sont en retrait.

All Articles