Optimisation du portefeuille d'investissement par la méthode de Markowitz





Un exemple d'implémentation standard en Python pour l'optimisation d'un portefeuille d'investissement à l'aide de la méthode Markowitz. Il existe de nombreuses implémentations de cette méthode. Y compris Python. Implémenté à nouveau (voir lien sur GitHub ).



Sources



Prenons une théorie à partir de ces sources:

Meilleur portefeuille d'investissement grâce à la simulation de Monte Carlo en Python

Théorie du portefeuille Markowitz (Wikipedia)



Téléchargement de données sur les devis



Nous utilisons les données du service Yahoo.Finance



! pip install yfinance
import yfinance as yf




Nous prenons plusieurs parts du marché américain au cours des 3 derniers mois.



data = yf.download(['AAPL','GE','BAC','AMD','PLUG','F'],period='3mo')




Taux de clôture



Nous utiliserons les taux de clôture quotidiens dans nos calculs



closeData = data.Close
closeData








Graphiques de cours



import matplotlib.pyplot as plt

for name in closeData.columns:
    closeData[name].plot()
    plt.grid()
    plt.title(name)
    plt.show()




























Changer de cours



Ensuite, vous avez besoin de modifications relatives par rapport à la veille.



dCloseData = closeData.pct_change()
dCloseData








Graphiques des changements de taux relatifs





for name in dCloseData.columns:
    dCloseData[name].plot()
    plt.title(name)
    plt.grid()
    plt.show()




























Rendement moyen



Rendement quotidien moyen de chaque action pour calculer le rendement du portefeuille.



dohMean = dCloseData.mean()
dohMean








Covariance





Pour calculer le risque du portefeuille, une matrice de covariance est nécessaire.



cov = dCloseData.cov()
cov








Portfolio aléatoire



Nous générerons des portefeuilles aléatoires. En eux, la somme des actions est égale à 1 (un).



import numpy as np

cnt = len(dCloseData.columns)

def randPortf():
    res = np.exp(np.random.randn(cnt))
    res = res / res.sum()
    return res

r = randPortf()
print(r)
print(r.sum())




[0.07519908 0.07594622 0.20932539 0.40973202 0.1234458  0.10635148]
1.0




Rendement du portefeuille



Le rendement du portefeuille est calculé comme la somme des parts des rendements de chaque action du portefeuille.



def dohPortf(r):
    return np.matmul(dohMean.values,r)

r = randPortf()
print(r)
d = dohPortf(r)
print(d)




[0.0789135  0.13031559 0.25977124 0.21157419 0.13506695 0.18435853]
0.006588795350151513




Risque de portefeuille¶



Nous calculons le risque du portefeuille au moyen de produits matriciels d'actions du portefeuille et de matrices de covariance.



def riskPortf(r):
    return np.sqrt(np.matmul(np.matmul(r,cov.values),r))

r = randPortf()
print(r)
rs = riskPortf(r)
print(rs)




[0.10999361 0.13739338 0.20412889 0.13648828 0.24021123 0.17178461]
0.02483674110724784




Nuage de portefeuille



Générons un ensemble de portefeuilles et affichons le résultat sur un graphique risque-rendement. Trouvons les paramètres du portefeuille optimal pour le risque minimum et le ratio de Sharpe maximum. Comparons avec les données du portefeuille moyen.




risk = np.zeros(N)
doh = np.zeros(N)
portf = np.zeros((N,cnt))

for n in range(N):
    r = randPortf()

    portf[n,:] = r
    risk[n] = riskPortf(r)
    doh[n] = dohPortf(r)

plt.figure(figsize=(10,8))

plt.scatter(risk*100,doh*100,c='y',marker='.')
plt.xlabel(', %')
plt.ylabel(', %')
plt.title(" ")

min_risk = np.argmin(risk)
plt.scatter([(risk[min_risk])*100],[(doh[min_risk])*100],c='r',marker='*',label=' ')

maxSharpKoef = np.argmax(doh/risk)
plt.scatter([risk[maxSharpKoef]*100],[doh[maxSharpKoef]*100],c='g',marker='o',label=' - ')

r_mean = np.ones(cnt)/cnt
risk_mean = riskPortf(r_mean)
doh_mean = dohPortf(r_mean)
plt.scatter([risk_mean*100],[doh_mean*100],c='b',marker='x',label=' ')

plt.legend()

plt.show()








Affiche les données des portefeuilles trouvés.



import pandas as pd

print('----------   ----------')
print()
print(" = %1.2f%%" % (float(risk[min_risk])*100.))
print(" = %1.2f%%" % (float(doh[min_risk])*100.)) 
print()
print(pd.DataFrame([portf[min_risk]*100],columns=dCloseData.columns,index=[', %']).T)
print()

print('----------    ----------')
print()
print(" = %1.2f%%" % (float(risk[maxSharpKoef])*100.))
print(" = %1.2f%%" % (float(doh[maxSharpKoef])*100.)) 
print()
print(pd.DataFrame([portf[maxSharpKoef]*100],columns=dCloseData.columns,index=[', %']).T)
print()

print('----------   ----------')
print()
print(" = %1.2f%%" % (float(risk_mean)*100.)) 
print(" = %1.2f%%" % (float(doh_mean)*100.)) 
print()
print(pd.DataFrame([r_mean*100],columns=dCloseData.columns,index=[', %']).T)
print()




----------   ----------

 = 1.80%
 = 0.59%

        , %
AAPL  53.890706
AMD   12.793389
BAC    4.117541
F     16.547201
GE    10.945462
PLUG   1.705701

----------    ----------

 = 2.17%
 = 0.88%

        , %
AAPL  59.257114
AMD    8.317192
BAC    2.049882
F      8.689935
GE     4.772159
PLUG  16.913719

----------   ----------

 = 2.33%
 = 0.68%

        , %
AAPL  16.666667
AMD   16.666667
BAC   16.666667
F     16.666667
GE    16.666667
PLUG  16.666667




conclusions



Nous avons repris la méthode classique de calcul des parts d'un portefeuille d'investissement. Nous avons obtenu des résultats très précis.



L'optimisation du portefeuille par la méthode de Markowitz suppose la préservation des paramètres dans le futur (corrélations entre les instruments individuels et leur niveau de rentabilité). Mais ce n'est pas garanti. Ceci doit être vérifié dans les travaux suivants.



Il est clair qu'il ne faut pas s'attendre à un résultat positif du test ci-dessus. Mais alors vous pouvez chercher comment modifier la méthode de Markowitz pour obtenir un revenu plus garanti à l'avenir. Voici un sujet pour une autre étude.



All Articles