Vous êtes sur la page 1sur 33

ABDALLAH ABDELKARIM

Analyse du marché boursier


avec Python
Analyse simple et analyse avance

1 : Analyse Simple

Le marché boursier est un système complexe et en constante


évolution. Il peut être difficile de garder une trace de tous les
différents facteurs qui peuvent affecter les cours des actions.
Cependant, avec l'aide de Python, vous pouvez analyser les données
boursières et prendre de meilleures décisions d'investissement.
Photo de Yiorgos Ntrahas sur Unsplash

Dans cette histoire, nous allons apprendre à télécharger les données


boursières avec Python. Nous apprendrons également à calculer la
performance du portefeuille. Cela vous donnera les outils dont vous
avez besoin pour commencer à analyser le marché boursier et à
prendre des décisions d'investissement éclairées. Les sujets suivants
seront abordés :

• Téléchargement des données boursières avec Python


• Calcul de la performance des actions
• Évaluation de la performance du portefeuille

Pour suivre cette histoire, vous aurez besoin d'une compréhension


de base de Python, ainsi que d'un IDE Python, tel que Jupyter
Notebook ou Visual Studio Code (VSC).
Téléchargement des données boursières avec
Python

Tout d'abord, nous devons télécharger les données sur les prix de
Yahoo Finance. Assurez-vous d'avoir installé la bibliothèque
suivante :
#bibliothèques préalables
# ! pip installer yfinance
importer yfinance comme yf
importer des pandas en tant que pd
importer numpy comme np

À titre d'illustration, j'ai choisi 3 tickers pour télécharger leurs


données de prix. Pour obtenir des valeurs de ticker, jetez un coup
d'œil à la liste des entreprises S&P 500.

• MSFT = Société Microsoft


• AAPL = Apple Inc.
• SPY = SPDR S&P 500 ETF Trust

Utilisez le code ci-dessous pour télécharger les données sur les prix
quotidiens :
stocknames = ['MSFT', 'AAPL', 'SPY'] #ticker
date de début = '2019-01-01'
date de fin = '2022-12-31'
intervalle = '1d'

pour le stock dans les noms de stock :


df = yf.download(stock, interval=interval, period='max')
df.to_csv('stocks_data\\{}.csv'.format(stock))

The price data will be saved in respective CSV files. The next step is
to combine them into a single DataFrame df with only the “Adjusted
Close” prices.
def appending(cols=[], startdate='', enddate='') :
dates = pd.date_range(start=startdate, end=enddate)
df = pd.DataFrame(index=dates)
pour le stock dans les noms de stock :
df_stock = pd.read_csv('stocks_data\\{}.csv'.format(stock), index_col='Date', parse_dates=True,
usecols=cols, na_values=['NaN'])
df_stock = df_stock.rename(columns = {'Adj Close': stock})
df = df.join(df_stock)
df = df.loc[dates]
df.index.names = ['Date']
df = df.dropna()
retour df

df = appending(['Date', 'Adj Close'], date de début, date de fin)


print(df.head())

'''
MSFT AAPL SPY
Date
2019-01-02 96.633 38.047 233.172
2019-01-03 93.078 34.257 227.608
2019-01-04 97.407 35.720 235.231
2019-01-07 97.531 35.640 237.086
2019-01-08 98.238 36.320 239.314
'''

Jetons un coup d'œil rapide aux prix dans une parcelle en utilisant
le code ci-dessous :
# ! pip install plotly --user
de plotly import express comme px

px.line(data_frame=df, title='Tickers Adj. Close Prices', width=1500, height=400)


Sortie du code ci-dessus

Nous devons observer le mouvement relatif des actions, c'est-à-dire


dans quelle mesure les actions ont augmenté ou baissé par rapport
aux autres actions. Par conséquent, nous devons « normaliser »
les cours des actions pour commencer par « 1 $ ». La normalisation
est un processus de conversion des données en une échelle
commune, ce qui peut faciliter la comparaison de différents stocks.

Pour ce faire, nous diviserons les prix de chaque colonne par le prix
du premier jour, de sorte que le prix de chaque jour (qu'il soit plus
élevé ou inférieur) soit relatif au prix du premier jour.
de matplotlib import pyplot comme plt

norm = df / df.iloc[0,:]
norm.plot(figsize=(10, 4.5))
plt.title('Plan de normalisation à l'aide de matplotlib')
plt.xlabel('Date')
plt.ylabel('Prix normalisé')
plt.tight_layout()
Le code tracera le graphique ci-dessous pour visualiser les prix
normalisés des 3 actions au fil du temps. Dans ce cas, les prix des
actions ont été normalisés en divisant chaque prix par le prix du
premier jour de l'ensemble de données. Cela signifie que tous les
prix de l'intrigue sont sur la même échelle, ce qui facilite la façon
dont ils ont changé au fil du temps.

Sortie du code ci-dessus

L'intrigue montre que les prix des 3 actions ont augmenté au fil du
temps. Cependant, les prix des actions n'ont pas augmenté au même
rythme. L'action avec le symbole "AAPL" a augmenté le plus (de
1,00 $ à 3,40 $), tandis que l'action avec le symbole "SPY" a
augmenté le moins (de 1,00 $ à 1,60 $).

Calcul de la performance des actions

Il y a quelques mesures pour calculer la performance d'une action :

• Rendements annualisés = gain annuel moyen du cours de


l'action au fil du temps, plus c'est élevé, mieux c'est
• Volatilité annualisée = fluctuations annuelles moyennes du
cours de l'action au fil du temps, plus c'est bas, mieux c'est

Rendements annualisés

Pour calculer le rendement annualisé d'une action, nous devons


savoir combien le prix a augmenté ou diminué un jour donné par
rapport à la veille, usingdfdf.pct_change(), qui est le ratio de
rendement quotidien.

Après cela, calculez la moyenne du ratio de rendement quotidien et


multipliez-la par 252 (environ le nombre de jours de négociation
dans une année) pour obtenir les rendements annualisés.
annualized_returns = df.pct_change().mean().apply(lambda x: x*252)
print(annualized_returns)

'''
MSFT 0.277
AAPL 0,367
SPY 0,148
'''

Nous pouvons voir que SPY devrait augmenter de 14,8 % par an, de
sorte que sur 3 ans (1 * 1,148 * 1,148 * 1,148), nous obtenons 1,51, ce
qui est proche des 1,60 $ que nous avons vus précédemment.

D'un autre côté, pour que l'AAPL augmente de 36,7 % par an, c'est-
à-dire sur 3 ans (1 * 1,367 * 1,367 * 1,367), nous n'otenons que 2,55,
ce qui est différent de l'augmentation réelle du prix à 3,40 $.
La raison en est que, bien que les rendements annualisés puissent
donner les rendements (moyens) attendus par an, la volatilité de
l'action l'amettra à des prix différents. Le montant de
l'investissement perdu ou gagné au cours d'une année donnée est
interdépendant avec le montant des autres années.

Volatilité annualisée

Pour calculer la volatilité annualisée d'une action, nous calculons


d'abord l'écarttype du ratio de rendement quotidien qui est la
volatilité quotidienne.

Après cela, nous supposons qu'il y a 252 jours de négociation dans


une année civile, nous multiplions donc la volatilité quotidienne par
la racine carrée de 252 pour obtenir la volatilité annualisée.
annualized_volatility = df.pct_change().std().apply(lambda x: x*np.sqrt(252))
print(annualized_volatility)

'''
MSFT 0,317
AAPL 0,346
SPY 0.225
'''

En résumé,

• MSFT vs APPL
MSFT a un rendement plus faible et une volatilité légèrement
inférieure à celle de l'AAPL
• APPL vs SPY
APPL a un rendement plus élevé et une plus grande volatilité
que SPY
• SPY vs MSFT
SPY a un rendement et une volatilité plus faibles que MSFT

Évaluation de la performance du portefeuille

Un portefeuille est un ensemble d'un certain nombre d'actions avec


des allocations différentes. Avant de construire un portefeuille, nous
devons comprendre le concept de corrélations.

La corrélation est une mesure statistique qui décrit la mesure


dans laquelle deux variables sont liées. Dans le contexte de
l'investissement, la corrélation fait référence à la relation entre les
prix de deux actifs ou plus.

Une corrélation positive signifie que les deux actifs ont tendance à
se déplacer dans la même direction. Par exemple, si le prix de
l'action A augmente, le prix de l'action B est susceptible
d'augmenter également. Une corrélation négative signifie que les
deux actifs ont tendance à se déplacer dans des directions opposées.
Par exemple, si le prix de l'action A augmente, le prix de l'action B
est susceptible de baisser.

Le coefficient de corrélation est un nombre compris entre -1 et 1 qui


mesure la force de la corrélation entre deux variables. Un coefficient
de corrélation de 1 indique une corrélation positive parfaite, un
coefficient de corrélation de -1 indique une corrélation négative
parfaite, et un coefficient de corrélation de 0 indique aucune
corrélation.
Examinons la corrélation des 3 actions dans cette histoire :
# ! pip installer seaborn
importer de la mer comme sns

#prenez le triangle du bas car il se répète


mask = np.zeros_like(daily_returns.corr())
mask[np.triu_indices_from(mask)] = True
sns.heatmap(daily_returns.corr(), annot=True, vmin=0.1, mask=mask, linewidths=2.5)

Sortie du code ci-dessus

Les corrélations entre les 3 actions sont très élevées (environ 0,8),
ce qui signifie qu'elles ont tendance à se déplacer dans la même
direction. Cela signifie que si le marché boursier est haussier, le prix
des 3 actions est susceptible d'augmenter. Inversement, si le marché
boursier est baissier, les 3 actions sont susceptibles de baisser de
prix. Ce n'est pas surprenant car ces 3 actions sont dans la même
industrie technologique.
Étant donné que le marché boursier de la technologie est plutôt
haussier entre 2019 et 2022, toute combinaison de ces 3 actions se
traduira par des bénéfices. Cependant, différentes allocations
(proportion) d'actions produiront des niveaux de profit différents.

Portefeuille 1 vs Portefeuille 2

construisons 2 portefeuilles avec des allocations différentes avec


une valeur initiale (d'investissement) de 1 000 $.

Portefeuille 1 : (ligne de base)


20 % MSFT, 10 % APPL, 70 % ESPION

Portefeuille 2 :
30 % MSFT, 40 % AAPL, 30 % ESPION
def portval (allocations = [], start_value = 0) :
''' pour obtenir la valeur quotidienne du portefeuille en fonction de l'allocation'''
allocs = norm.copy() * allocations
pos_val = allocs * start_value
port_val = pos_val.sum(axis=1)
retour port_val

fig, ax = plt.subplots(1, 2, figsize=(15, 4.5), sharex=True, sharey=True)

#supposons que notre valeur de départ = 1000 $


#allocation de base : 20 % MSFT, 10 % APPL, 70 % SPY
port_val1 = portval([0.2, 0.1, 0.7], 1000)
port_val1.plot(ax=ax[0], color='skyblue')
ax[0].axhline(np.mean(port_val1), linestyle='--', c='g')
ax[0].set_title('Portfolio 1 values')

#nouvelle allocation : 30 % MSFT, 40 % AAPL, 30 % SPY


port_val2 = portval([0.3, 0.4, 0.3], 1000)
port_val2.plot(ax=ax[1], color='orange')
ax[1].axhline(np.mean(port_val2), linestyle='--', c='g')
ax[1].set_title('Portfolio 2 values')
plt.tight_layout()
Sortie du code ci-dessus

Calculons les mesures de performance du portefeuille suivantes :

• Valeurs du portefeuille
• Ratio de rendement cumulé
• Rendements annualisés
• Volatilité annualisée
• Ratio de Sharpe

Valeurs du portefeuille

Les deux portefeuilles commencent avec la valeur initiale de 1 000


$. Au bout de 3 ans, le portefeuille 1 est passé à environ 2 000 $,
tandis que le portefeuille 2 est passé à environ 2 600 $.
print('Portfolio 1 Value: $', round(port_val1[-1], 2))
print('Portfolio 2 Value: $', round(port_val2[-1], 2))

'''
Portefeuille 1 Valeur : 1979,81 $
Valeur du portefeuille 2 : 2596,75 $
'''
Ratio de rendement cumulé

Le ratio de rendement cumulé est défini comme le ratio profit-perte


du portefeuille sur une période donnée. Il est calculé comme suit :
bénéfice (qui est le prix final moins le prix initial) divisé par le prix
initial.
cum_return1 = ((port_val1.iloc[-1] / port_val1.iloc[0]) -1) * 100
print('Le rendement cumulé du portefeuille 1 est {:.1f} %'.format(cum_return1))
cum_return2 = ((port_val2.iloc[-1] / port_val2.iloc[0]) -1) * 100
print('Le rendement cumulé du portefeuille 2 est {:.1f} %'.format(cum_return2))

'''
Le rendement cumulé du portefeuille 1 est de 98,0 %
Le rendement cumulé du portefeuille 2 est de 159,7 %
'''

Rendements annualisés

The Annualized Return is calculated from the daily portfolio value


port_val1and port_val2. Find their returns ratio, and their mean, then
multiply by 252.
annualized_returns1 = port_val1.pct_change().mean() * 252
annualized_returns2 = port_val2.pct_change().mean() * 252

print('Portfolio 1 Annualized Returns: ', round(annualized_returns1, 3))


print('Portfolio 2 Annualized Returns: ', round(annualized_returns2, 3))

'''
Portefeuille 1 Rendements annualisés : 0,203
Portefeuille 2 Rendements Annualisés : 0,282
'''

Volatilité annualisée

Similarly, the Annualized Volatility is calculated from the daily


portfolio value port_val1 and port_val2. Find their returns ratio, and their
standard deviation, then multiply by the square root of 252.
annualized_volatility1 = port_val1.pct_change().std() * np.sqrt(252)
annualized_volatility2 = port_val2.pct_change().std() * np.sqrt(252)
print('Portfolio 1 Annualized Volatility: ', round(annualized_volatility1, 3))
print('Portfolio 2 Annualized Volatility: ', round(annualized_volatility2, 3))

'''
Portefeuille 1 Volatilité annualisée : 0,252
Volatilité annualisée du portefeuille 2 : 0,294
'''

Nous pouvons remarquer clairement que le rendement du


portefeuille 2 est supérieur à celui du portefeuille 1, mais le risque
(volatilité) est également plus élevé. Cela est attendu car un risque
élevé s'accompagne généralement de rendements élevés.

Ratio de Sharpe

Sharpe Ratio est une mesure qui évalue le risque et les rendements
ensemble, afin d'aider les investisseurs dans la sélection d'un tel
investissement qui génère des rendements plus élevés pour le risque
optimal pris. Plus le ratio de Sharpe est élevé, meilleurs sont les
rendements.
portfolio_daily_returns1 = port_val1.pct_change()
SR1 = np.sqrt(252) * np.mean(portfolio_daily_returns1) / np.std(portfolio_daily_returns1)
print('Sharpe Ratio Portfolio 1 = {:.3f}%'.format(SR1))

portfolio_daily_returns2 = port_val2.pct_change()
SR2 = np.sqrt(252) * np.mean(portfolio_daily_returns2) / np.std(portfolio_daily_returns2)
print('Sharpe Ratio Portfolio 2 = {:.3f}%'.format(SR2))

'''
Portefeuille Sharpe Ratio 1 = 0,805 %
Portefeuille Sharpe Ratio 2 = 0,960%
'''

Jetons un coup d'œil aux deux portefeuilles après la normalisation.


Cela donnera une bonne comparaison pour le mouvement des
valeurs. Nous nous attendons à ce que le portefeuille 2 avec un ratio
de Sharpe plus élevé fonctionne mieux.
fig, ax = plt.subplots(figsize=(15, 8))
port_val1.plot(ax=ax, color='skyblue')
port_val2.plot(ax=ax, color='orange')
plt.legend(['Portfolio 1', 'Portfolio 2'])
plt.title('Comparaison entre nos 2 portefeuilles (Normalisé)')
plt.text('2020-07', 1000, 'Portfolio 1 value = ${:.0f}'.format(port_val1[-1]), color='skyblue')
plt.text('2020-07', 1200, 'Portfolio 2 value = ${:.0f}'.format(port_val2[-1]), color='orange')
plt.tight_layout()

Sortie du code ci-dessus

Finons. Les résultats de notre analyse montrent que le portefeuille 2


a un ratio Sharpe plus élevé que le portefeuille 1. Cela signifie que le
portefeuille 2 a généré des rendements plus élevés pour un niveau
de risque donné. Cependant, le portefeuille 2 est également plus
risqué, car il a une volatilité plus élevée que le portefeuille 1. Cela
signifie que le portefeuille 2 pourrait être plus susceptible de perdre
de l'argent dans un autre laps de temps !
Photo par Tech Daily sur Unsplash

Dans cette histoire, nous avons appris à télécharger des données


boursières avec Python, à calculer la performance des actions et à
calculer la performance du portefeuille. Nous avons également vu
comment différentes allocations dans les portefeuilles peuvent
conduire à des performances de portefeuille différentes. Python
peut être utilisé pour analyser les données boursières en
comprenant les concepts de corrélation, de rendement, de risque et
de volatilité.

Mais veuillez noter que jusqu'à présent, nous avons examiné de


justes 3 actions similaires dans le secteur de la technologie au cours
d'une série haussière de 3 ans.Dans la prochaine etape je vais
partager comment construire un portefeuille diversifié d'actions,
avec une allocation recommandée pour maximiser les profits !
Voici quelques réflexions supplémentaires sur l'histoire :

• Les résultats de notre analyse sont basés sur des données


historiques. Il est important de se rappeler que les
performances passées ne sont pas nécessairement indicatives
des résultats futurs.
• L'analyse de cette histoire ne tient pas compte des frais ou
commissions qui peuvent être associés à la négociation
d'actions.
• L'analyse de cette histoire est uniquement à des fins de
partage et d'éducation. Il n'est pas destiné à fournir des
conseils d'investissement.

2 ANALYSE AVANCE

Dans mon histoire précédente, nous avons discuté de la façon de


télécharger les données boursières avec Python, de calculer la
performance des actions et de calculer la performance du
portefeuille. Dans cette histoire, nous discuterons de la façon
d'allouer des actions d'un portefeuille à l'aide de diverses techniques
et de suivre la performance du portefeuille.
Qu'est-ce qu'un portefeuille ?

Un portefeuille d'actions est un ensemble d'actions qu'un


investisseur possède. L'objectif d'un portefeuille est de générer des
rendements au fil du temps tout en minimisant le risque. La
quantité de risque qu'un investisseur est prêt à prendre affectera la
composition de son portefeuille.

Il existe de nombreuses façons de constituer un portefeuille


d'actions. Certains investisseurs choisissent de se concentrer sur
une industrie ou un secteur spécifique, tandis que d'autres
choisissent de diversifier leur portefeuille entre différentes
industries. Une fois qu'un portefeuille est créé, il est important de
suivre sa performance au fil du temps. Cela peut être fait en
calculant le rendement, le risque et la volatilité du portefeuille.
• Rendement : Le montant total d'argent que le portefeuille a
généré au cours d'une période donnée. Une bonne mesure à
utiliser est le rendement annualisé.
• Volatilité : la mesure dans laquelle la valeur du portefeuille
fluctue au fil du temps. Une bonne mesure à utiliser est la
volatilité annualisée.
• Risque : La probabilité que le portefeuille perde de l'argent.
Avec le rendement historique et la volatilité donnés, nous
pourrions utiliser différentes techniques pour minimiser ce
risque.

Sollons les données de prix pour les actions dans les différentes
industries en utilisant yf.download().

• Soins de santé : Moderna (ARNM), Pfizer (PFE), Johnson &


Johnson (JNJ)
• Technologie : Google (GOOGL), Facebook (META), Apple
(AAPL), Microsoft (MSFT)
• Commerce de détail : Costco (COST), Walmart (WMT),
Kroger Co (KR)
• Finances : JPMorgan Chase & Co (JPM), Bank of America
(BAC), HSBC Holding (HSBC)
• Autres : SPDR S&P 500 ETF Trust (SPY), SPDR Gold Trust
(GLD), Nikkei 225 (^N225), Pétrole brut (CL=F), Bitcoin
(BTC-USD)
# ! pip installer yfinance
importer yfinance comme yf
importer des pandas en tant que pd
importer numpy comme np
pd.options.display.float_format = '{:,.3f}'.format

stocknames = ['MRNA', 'PFE', 'JNJ', 'GOOGL', 'META', 'AAPL', 'MSFT', 'COST', 'WMT', 'KR', 'JPM', 'BAC',
'HSBC', 'SPY', 'GLD', '^N225', 'CL=F', 'BTC-USD'] #ticker
date de début = '2019-01-01'
date de fin = '2022-12-31'
intervalle = '1d'

pour le stock dans les noms de stock :


df = yf.download(stock, interval=interval, period='max')
df.to_csv('stocks_data\\{}.csv'.format(stock))

def appending(cols=[], startdate='', enddate='') :


'''ajouchez les données de stocks dans un fichier, puis sélectionnez la colonne 'Adj Close''''
dates = pd.date_range(start=startdate, end=enddate)
df = pd.DataFrame(index=dates)
pour le stock dans les noms de stock :
df_stock = pd.read_csv('stocks_data\\{}.csv'.format(stock), index_col='Date', parse_dates=True,
usecols=cols, na_values=['NaN'])
df_stock = df_stock.rename(columns = {'Adj Close': stock})
df = df.join(df_stock)
df = df.dropna()
retour df

df = appending(['Date', 'Adj Close'], date de début, date de fin)

Sortie du code ci-dessus

La diversification est une technique de gestion des risques qui


implique l'investissement dans une variété d'actifs. En diversifiant
votre portefeuille, vous pouvez réduire votre risque en répartissant
votre argent sur différents actifs qui ne sont pas parfaitement
corrélés. Cela signifie que si un actif perd de la valeur, les autres
actifs de votre portefeuille peuvent ne pas être autant affectés.
Un portefeuille diversifié est un panier de placements qui ne sont
pas fortement corrélés les uns avec les autres. Cela signifie qu'ils ne
sont pas susceptibles de monter ou de baisser leur prix en même
temps. Cela aide à réduire le risque global du portefeuille, car une
baisse d'un investissement peut être compensée par une
augmentation d'un autre.

Lors de la construction d'un portefeuille diversifié, il est important


de tenir compte de la corrélation entre les actifs de votre
portefeuille. Si vous investissez dans deux actifs qui sont fortement
corrélés, vous ne diversifiez pas réellement votre risque. Au lieu de
cela, vous augmentez simplement votre exposition au même facteur
de risque.

1. Parité de risque hiérarchique (HRP)

La méthode de parité des risques hiérarchiques (HRP) fonctionne


en trouvant des sous-groupes d'actifs similaires sur la base des
rendements et en construisant une hiérarchie à partir de ces
grappes pour générer des pondérations pour chaque actif.

HRP ne nécessite pas l'inversion d'une matrice de covariance, qui


est une mesure de la façon dont les rendements des actions se
déplacent dans la même direction. HRP n'est pas sensible aux
valeurs aberrantes. Voici le code pour exécuter HRP :
# ! pip install PyPortfolioOpt
de pypfopt import HRPOpt
daily_returns = df.pct_change()

#exécuter l'algorithme d'optimisation pour obtenir les poids :


hrp = HRPOpt(daily_returns)
hrp_weights = hrp.optimize()

#performance du portefeuille et des poids :


hrp.portfolio_performance(verbose=True)
hrp_weights = dict(hrp_weights)
print(hrp_weights)

'''
Retour annuel attendu : 14,9 %
Volatilité annuelle : 12,0 %
Ratio de pointu : 1,07
{'GLD': 0.3285574294579892,
'^N225' : 0.20417293938457295,
'JNJ' : 0,0689269229258587,
'KR': 0.06353536844150041,
'PFE' : 0.05782346160864427,
'WMT' : 0.05636163167063827,
« COÛT » : 0.04601434327046138,
'HSBC' : 0.030885367472990262,
'JPM' : 0.021543028668782396,
'GOOGL' : 0.020846539574785265,
'SPY' : 0.020217120714651118,
'AAPL' : 0.01608647346814868,
'BAC': 0.014154600282063617,
'META': 0.012991563530249668,
'MRNA' : 0.012946352437141694,
'BTC-USD' : 0.011999189095048452,
'MSFT' : 0.010361598261625025,
'CL=F': 0.002576069734848656}
'''

The output of HRPOpt library seems to place a high emphasis on Gold


(GLD) and Nikkei 225 Index (^N225). Let’s calculate the discrete
allocation using these weights with an initial investment of
$10,000. The DiscreteAllocation library will provide the number of
shares to buy for each stock at their latest prices. For more
information about allocation see this link.
de pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices

latest_prices = get_latest_prices(df)
da_hrp = DiscreteAllocation(hrp_weights, latest_prices, total_portfolio_value=10000)

allocation_hrp, leftover_hrp = da_hrp.greedy_portfolio()


print("Allocation discrète (HRP) :", allocation_hrp)
print("Fonds restants (HRP): ${:.2f}".format(leftover_hrp))

'''
Allocation discrète (HRP) : {'GLD' : 19, 'JNJ' : 4, 'KR' : 14, 'PFE' : 11, 'WMT' : 4, 'COST' : 1, 1, 'HSBC' :
10, 'JPM': 2, 'GOOGL' : 2, 2, 'SPY': 1, 1, 'AAPL': 2, 'BAC': 4, 'META': 1, 1, 'MRNA': 1, 'MSFT': 1, 1, 1CL=F':
1}
Fonds restants (HRP) : 1768,03 $
'''

2. Optimisation efficace de la frontière

Efficient Frontier est un graphique avec des « retours » sur l'axe Y


et une « volatilité » sur l'axe des X. Il montre l'ensemble des
portefeuilles optimaux qui offrent le rendement attendu le plus
élevé pour un niveau de risque donné ou le risque le plus faible pour
un niveau donné de rendement attendu. Les portefeuilles qui se
trouvent en marge de la frontière efficace sont les plus optimaux
parce qu'ils offrent un rendement suffisant pour le niveau de risque
(ou ont un risque plus faible pour le taux de rendement défini).

Pour comprendre comment fonctionne la frontière efficace, nous


devons faire une boucle 10 000 fois. Dans chaque itération, nous
considérons les pondérations d'une combinaison aléatoire d'actifs et
calculons le rendement et la volatilité de cette combinaison de
portefeuille particulière.
p_ret = [] #définir un tableau vide pour les rendements de portefeuille
p_vol = [] #dfine un tableau vide pour la volatilité du portefeuille
p_weights = [] #définir un tableau vide pour les poids des actifs
num_assets = len(df.columns)
num_portfolios = 10000

#matrice de covariance des rendements quotidiens (relation et co-mouvement entre différents


stocks)
cov_matrix = daily_returns.cov()

pour le portefeuille dans la gamme (num_portfolios) :


poids = np.random.random(num_assets)
poids = poids/np.somme(poids) #la somme des poids doit être 1, nous divisons donc ces poids par
leur somme cumulative
p_weights.append(poids)
returns = np.dot(weights, annualized_returns) #returns sont le produit des rendements attendus
individuels de l'actif et de ses pondérations

p_ret.append(returns)
var = cov_matrix.mul(weights, axis=0).mul(weights, axis=1).sum().sum() #portfolio variance
sd = np.sqrt(var) #écart-type quotidien
ann_sd = sd*np.sqrt(250) #écart-type annuel = volatilité
p_vol.append(ann_sd)

data = {'Returns': p_ret, 'Volatility': p_vol}


pour le compteur, symbole dans enumerate(df.columns.tolist()) :
data[symbol + 'weight'] = [w[counter] pour w dans p_weights]
portefeuilles = pd.DataFrame(data)

Sortie du code ci-dessus

Avec ce code, nous avons créé 10 000 combinaisons de différentes


allocations de stocks. Chaque ligne (combinaison) produira un
certain rendement et une certaine volatilité, et sera représentée par
un seul point dans le graphique Rendements-Volatilité. Tracons et
visualisons-le :
#Frontière efficace du complot
portfolios.plot.scatter(x='Volatility', y='Returns', marker='x', s=10, alpha=0.3, grid=True,
figsize=[10,6], color='darkblue')

#définir divers portefeuilles


min_vol_port = portfolios.iloc[portfolios['Volatility'].idxmin()]
rf = 0,01 #facteur de risque
worst_risky_port = portfolios.iloc[((portfolios['Returns']-rf) / portfolios['Volatility']).idxmin()]
optimal_risky_port = portfolios.iloc[((portfolios['Returns']-rf) / portfolios['Volatility']).idxmax()]
given_volatility = 0,18
portfolios_temp = portfolios.loc[(portfolios['Volatility'] > given_volatility-0.004) &
(portfolios['Volatility'] < given_volatility+0.004].reset_index(drop=True)
given_volatility_port = portfolios_temp.iloc[((portfolios_temp['Returns']-rf) /
portfolios_temp['Volatility']).idxmax()]
Sortie du code ci-dessus

Pour plonger plus profondément, trouvons ce qui suit (défini dans


le code ci-dessus) :

• min_vol_port = le portefeuille avec une volatilité minimale


• worst_risky_port = le pire portefeuille (rapport retour-
volatilité le plus bas)
• optimal_risky_port = le portefeuille optimal (rapport
retour-volatilité le plus élevé)
• given_volatility_port = le portefeuille avec les rendements
maximaux avec une volatilité donnée (fixe)

Localisons-les sur le graphique de la frontière efficace :


de matplotlib import pyplot comme plt

#plot frontière efficace avec un portefeuille optimal, etc.


plt.subplots(figsize=(10,6))
sharpe_err = portefeuilles['Retours'] / portefeuilles['Volalité']
plt.scatter(portfolios['Volatility'], portfolios['Returns'], c=sharpe_err, s=10, alpha=0.3)
plt.xlabel('Volatility')
plt.ylabel('Returns')
port_plot = {'min_vol_port': min_vol_port, 'worst_risky_port': worst_risky_port, 'optimal_risky_port':
optimal_risky_port, 'given_volatility_port': given_volatility_port}
port_color = {'min_vol_port': 'purple', 'worst_risky_port': 'black', 'optimal_risky_port': 'gold',
'given_volatility_port': 'cyan'}
pour k dans port_plot.keys() :
plt.scatter(port_plot[k][1], port_plot[k][0], color=port_color[k], marker='*', s=500)
plt.text(port_plot[k][1]+.01, port_plot[k][0], k, fontsize=9)

Sortie du code ci-dessus

Obtenons l'allocation discrète pour le portefeuille optimal


(optimal_risky_plot).
de pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices

#convertir les poids en valeurs d'allocation réelles (c'est-à-dire combien de chaque action à acheter)
avec un montant d'investissement de 10 000 $
latest_prices = get_latest_prices(df)

da_opt = DiscreteAllocation(optimal_risky_port.iloc[2:].to_dict(), latest_prices,


total_portfolio_value=10000)

allocation_opt, leftover_opt = da_opt.greedy_portfolio()


print("Allocation discrète:", allocation_opt)
print("Fonds restants : ${:.2f}".format(leftover_opt))

'''
Allocation discrète : {'PFE' : 14, 'BAC' : 12, 'KR' : 11, 'AAPL' : 8, 'MRNA' : 7, 'GLD' : 7, 7, 'WMT' : 7,
'HSBC' : 6, 6, 'GOOGL' : 5, 4, 'MSFT' : 4, 4, 4PM' : 4, 4, 'JNJ' : 2, 2A' : 'MA': 1, 1}
Fonds restants : 16,61 $
'''

3. Frontier efficace utilisant des bibliothèques


Python
Heureusement, il existe des bibliothèques Python prêtes pour la
méthode Efficient Frontier. Importez le module « EfficientFrontier
» et explorez les différentes méthodes pour calculer facilement les
poids.

Méthode (1). Un algorithme consiste à rechercher le ratio Sharpe


maximal, qui se traduit par le portefeuille avec le rendement le plus
élevé et le risque le plus faible.
de pypfopt import expected_returns
de pypfopt.risk_models import CovarianceShrinkage
à partir de pypfopt.efficient_frontier import EfficientFrontier

#calculer la matrice de covariance et stocker les rendements calculés dans les variables S et mu
mu = expected_returns.mean_historical_return(df)
S = CovarianceShrinkage(df).ledoit_wolf()

ef = EfficientFrontier(mu, S)
poids = ef.max_sharpe()
ef.portfolio_performance(verbose=True)
cleaned_weights = ef.clean_weights()

'''
Retour annuel attendu : 45,1 %
Volatilité annuelle : 25,5 %
Ratio de pointu : 1,69
{'MRNA': 0.26443,
'AAPL' : 0.17975,
'BTC-USD' : 0.13273,
« COÛT » : 0.10265,
'MSFT' : 0.08056,
'KR' : 0,06656,
'GLD' : 0.04455,
'WMT': 0.0364,
'^N225': 0.03203,
'JNJ' : 0.03103,
'SPY' : 0.00984,
'JPM' : 0.00816,
'CL=F': 0.00766,
'PFE': 0.00366,
'GOOGL' : 0,0,
'META' : 0,0,
'BAC' : 0,0,
'HSBC' : 0,0}
'''

Méthode (2). Une autre façon consiste à fixer la volatilité cible (par
exemple 0,184) et à trouver le rendement maximal possible.
#nouvelle instance de la performance du portefeuille
ef2 = EfficientFrontier(mu, S)
ef2.efficient_risk(target_volatility=0.184)
ef2.portfolio_performance(verbose=True)

cleaned_weights2 = ef2.clean_weights()
cleaned_weights2

'''
Retour annuel attendu : 30,8 %
Volatilité annuelle : 18,4 %
Ratio de Sharpe : 1,57
{'MRNA': 0.14281,
'AAPL' : 0.10654,
« COÛT » : 0,08471,
'GLD': 0.08422,
'BTC-USD' : 0,07792,
'KR': 0.07723,
'^N225' : 0,07316,
'MSFT': 0.06242,
'WMT': 0.06032,
'JNJ' : 0.05863,
'PFE': 0.04197,
'SPY': 0.03759,
'JPM': 0.03189,
'GOOGL': 0.02568,
'BAC' : 0.01852,
'HSBC' : 0.0085,
'CL=F': 0.00787,
'META': 0.0}
'''
Méthode (3). Une autre façon est de fixer le rendement cible (par
exemple 0,261) et de trouver les poids pour la plus faible volatilité
possible.
de pypfopt import EfficientSemivariance

historical_returns = expected_returns.returns_from_prices(df)
ef3 = Semi-variance efficace(mu, historical_returns)
ef3.return_efficient(0.261)
ef3.portfolio_performance(verbose=True)

cleaned_weights3 = ef3.clean_weights()
cleaned_weights3

'''
Retour annuel attendu : 26,1 %
Semi-déviation annuelle : 10,5 %
Ratio de Sortino : 2,29
{'GLD': 0.34766,
'AAPL': 0.18535,
'^N225': 0.17654,
'MRNA': 0.10715,
« COÛT » : 0,08781,
'KR' : 0.08172,
'BTC-USD' : 0.01377,
'PFE' : 0,0,
'JNJ' : 0,0,
'GOOGL' : 0,0,
'META' : 0,0,
'MSFT' : 0,0,
'WMT': 0.0,
'JPM' : 0,0,
'BAC' : 0,0,
'HSBC' : 0,0,
'SPY' : 0,0,
'CL=F': 0.0}
'''

With the above weights (cleaned_weights3), let’s get the discrete


allocations for all stocks.
de pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices

#convertir les poids en valeurs d'allocation réelles (c'est-à-dire combien de chaque action à acheter)
avec un montant d'investissement de 10 000 $
latest_prices = get_latest_prices(df)
da_ef = DiscreteAllocation(cleaned_weights3, latest_prices, total_portfolio_value=10000)

allocation_ef, leftover_ef = da_ef.greedy_portfolio()


print('Allocation discrète:', allocation_ef)
print('Fonds restants : ${:.2f}'.format(leftover_ef))

'''
Allocation discrète : {'GLD' : 20, 'KR' : 18, 'AAPL' : 14, 'MRNA' : 5, 'COST' : 2}
Fonds restants : 2192,27 $
'''

Comparaison des 3 allocations discrètes

Nous sommes maintenant prêts à comparer les 3 allocations


discrètes décrites jusqu'à présent.
#réorganiser les dicts pour avoir une séquence identique
allocation_hrp2, allocation_opt2, allocation_ef2 = {}, {}, {}
pour le nom dans les noms de stock :
allocation_hrp2[nom] = allocation_hrp.get(nom, 0)
allocation_opt2[nom] = allocation_opt.get(nom, 0)
allocation_ef2[name] = allocation_ef.get(name, 0)

#plot le graphique à barres de comparaison


idx = np.arange(len(stocknames))
largeur de barre = 0,25
fig, ax = plt.subplots(figsize=(18, 5))
ax.bar(idx-barwidth, allocation_hrp2.values(), barwidth, label="allocation_hrp")
ax.bar(idx, allocation_opt2.values(), barwidth, label="allocation_opt")
ax.bar(idx+barwidth, allocation_ef2.values(), barwidth, label="allocation_ef")
ax.set_title('Allocations discrètes d'actions')
ax.set_xlabel('Stocks')
ax.set_ylabel('Allocations discrètes')
ax.set_xticks(idx)
ax.set_xticklabels(['MRNA', 'PFE', 'JNJ', 'GOOGL', 'META', 'AAPL', 'MSFT', 'COST', 'WMT', 'KR', 'JPM',
'BAC', 'HSBC', 'SPY', 'GLD', '^N225', 'CL=F', 'BTC-USD'])
ax.legend()
plt.show()
Sortie du code ci-dessus

Les différentes approches d'allocation de portefeuille semblent être


en mesure d'identifier exactement la quantité de chaque action à
acheter pour construire un portefeuille diversifié. En utilisant le
principe de l'ensachat, je suggérerais le mélange de portefeuille
suivant :

• Soins de santé : Pfizer (PFE)


• Technologie : Apple (AAPL)
• Commerce de détail : Kroger Co (KR)
• Finances : HSBC Holding (HSBC)
• Autres : SPDR Gold Trust (GLD)

Veuillez ne pas supposer qu'un investissement continuera à bien


faire à l'avenir simplement parce qu'il a bien fait dans le passé. Et
méfiez-vous de l'étiquette d'avertissement commune dans les
brochures d'investissement :

« La performance passée n'est pas une garantie de résultats futurs


»
Jusqu'à présent, ce tutoriel fournit une base de base pour ceux qui
s'intéressent aux méthodes d'optimisation de portefeuille en
Python. Voici quelques conseils supplémentaires pour construire un
portefeuille diversifié :

• Considérez votre tolérance au risque. La quantité de


diversification dont vous avez besoin dépendra de votre
tolérance au risque individuelle. Si vous êtes plus aversion au
risque, vous voudrez peut-être investir dans un portefeuille
plus diversifié.
• Tenez compte de vos objectifs d'investissement. Vos objectifs
d'investissement affecteront également la quantité de
diversification dont vous avez besoin. Si vous épargnez pour la
retraite, vous voudrez peut-être investir dans un portefeuille
plus diversifié que si vous épargnez pour un objectif à plus
court terme, comme une mise de fonds sur une maison.
• Rééquilibrez régulièrement votre portefeuille. Au fur et à
mesure que vos investissements augmentent, vous devrez
rééquilibrer votre portefeuille pour vous assurer qu'il reste
diversifié. Cela signifie vendre certains de vos gagnants et
acheter un plus grand de vos perdants.

Au fur et à mesure que les prix du portefeuille se déplacent, les


allocations des avoirs varieront également. Vous devrez le
rééquilibrer pour vous assurer qu'il reste aligné sur les allocations
initiales (poids), qui sont alignés sur les objectifs d'investissement
initiaux. Nous discuterons du rééquilibrage d'un portefeuille dans
ma prochaine histoire !
Voici quelques réflexions supplémentaires sur l'histoire :

• Les résultats de notre analyse sont basés sur des données


historiques. Il est important de se rappeler que les
performances passées ne sont pas nécessairement indicatives
des résultats futurs.
• L'analyse de cette histoire ne tient pas compte des frais ou
commissions qui peuvent être associés à la négociation
d'actions.
• L'analyse de cette histoire est uniquement à des fins de
partage et d'éducation. Il n'est pas destiné à fournir des
conseils d'investissement.
Bon L’ecture

Vous aimerez peut-être aussi