6.7 KiB
title | date | draft |
---|---|---|
Gérer son épargne en action sous Firefly | 2023-12-19T20:10:42+02:00 | true |
Problématique
Gestion du portefeuille
Valeur d'une action
Comme énoncé précédemment, la valeur d'un portefeuille d'actions dépend de la composition de ce portefeuille (donc de quelles actions et en quelle quantité), et de la valeur unitaire de chacune de ces actions.
Cette valeur unitaire est définie par les marchés financiers et varie continuellement. On considère que la valeur d'une action est le prix du dernier ordre d'achat passé pour cette action sur les marchés financiers.
{{< callout type="example" >}} Considérons la valeur "MSCI World" (un ETF trackant les valeurs des plus grosses entreprises dans le monde entier). Au 10 décembre, les marchés financiers s'ouvrent avec la valeur de 27.13€ par part pour cette valeur. à 9h05, une personne passe un ordre d'achat de 15 actions au prix de 27.17€. Dès que cet ordre est exécuté, on considère que l'action "MSCI World" a la valeur de 27.17€ par action. {{< /callout >}}
Dans mon cas, je n'ai absolument pas besoin d'une mise à jour rapide des valeurs, une mise à jour quotidienne est largement suffisante pour mes besoins, et une mise à jour hebdomadaire pourrait même convenir à vrai dire.
J'ai choisi donc de considérer pour chaque action, sa valeur au moment de la cloture des marchés (17h). Mais comment calculer cette valeur ?
Obtenir la valeur d'une action
À la recherche d'une API
Pour le reste de cet article, je considèrerai l'action "MSCI Monde" en titre d'exemple. Avec un navigateur, on arrive facilement à obtenir les informations que l'on veut :
- La bourse européenne (Euronext) nous donne accès à son cours
- On obtient facilement les mêmes informations sur Google Finance ou Yahoo Finance
Cependant, il s'agit d'information destinées à un visionnage humain, aucune API n'est publiquement disponible pour obtenir ces informations de façon automatisée.
En faisant des recherches sur le sujet, je me heurte rapidement à deux problèmes :
- soit je trouve des services gratuits, mais limités, soit en quantité d'appels (5 appels par jour par exemple) soit en fonctionnalités (pas d'ETF)
- soit je trouve des services... chers. De l'ordre d'au moins plusieurs dizaines d'euros par mois, ce qui est complètement en dehors du cadre d'un projet de ce type.
De plus, la majorité des API disponibles sont basées sur les marchés américains. Étant dans des marchés européens, il est encore plus difficile d'obtenir les informations voulues.
Scraping d'Euronext
Finalement, la solution la plus simple revient à faire du scraping d'un site pertinent (cela expose aux protections anti-bot, mais je n'en ai pas vu sur le site d'Euronext que j'ai décidé d'utiliser, et le volume de requêtes est en pratique très faible).
Mon point de départ est la fiche d'une action: prenons notre habituel MSCI world.
Toutes les valeurs intéressantes se trouvent sur un bandeau de la fiche de la valeur. Ici il s'agit du dernier cours traité de 27.188€.
En observant le contenu de la page web, on obtient d'ailleurs ceci :
<div class="col text-ui-grey-0 font-weight-bold data-header-cash ">
<div class="lastprice_min_height pb-1 ">
<span class="data-50 " id="header-instrument-currency">€</span>
<span class="data-60" id="header-instrument-price">27,188</span>
</div>
</div>
Il suffirait donc de faire un petit script de scraping accédant à l'élément possédant l'id #header-instrument-price
pour obtenir directement la valeur voulue. Mais on peut faire encore mieux en observant les requêtes
AJAX effectués depuis le navigateur.
Une requête en particulier est intéressante, puisqu'elle interroge la route https://live.euronext.com/intraday_chart/getChartData/FR0011869353-XPAR/intraday
et renvoie un tableau JSON ayant la forme suivante (le tableau est tronqué, mais contient plus de 1000 éléments):
[
{"time":"2023-12-12 17:29","price":26.879999999999999,"volume":11},
{"time":"2023-12-13 09:04","price":26.974,"volume":1888},
...
{"time":"2023-12-19 17:35","price":27.187999999999999,"volume":32}
]
Chaque ligne du tableau contient un ordre d'achat passé au cours de la journée. La valeur intéressante correspond à la dernière ligne de ce tableau : il s'agit du dernier ordre passé, et correspond donc exactement à la valeur affichée sur la fiche de la valeur, et est donc la valeur que l'on souhaite obtenir.
À partir de là, la fonction Python suivante est suffisante pour obtenir la valeur d'une action donnée
EURONEXT_BASE_URL = "https://live.euronext.com/intraday_chart/getChartData"
class StoredAction(NamedTuple):
name: str
value: float
date: str
class Action(NamedTuple):
name: str
code: str
def get_last_value_for_action(action: Action) -> StoredAction:
url = f"{EURONEXT_BASE_URL}/{action.code}/intraday"
resp = requests.get(url)
resp_json = resp.json()
if len(resp_json) < 1:
raise ValueError("Empty list of values")
last_value = resp_json[-1]
try:
return StoredAction(
name=action.name,
value=last_value["price"],
date=last_value["time"],
)
except KeyError as exc:
raise ValueError("Invalid format for response") from exc
Il suffit de trouver le code associé à l'action voulue. Je le trouve à partir de l'URL de la fiche
produit de l'action cherchée. Dans notre exemple, il s'agit de https://live.euronext.com/fr/product/etfs/fr0011869353-xpar/lyxor-msci-wor-pea/ewld
.
Le code est donc fr0011869353-xpar
.
{{< callout type="warning" >}} De façon surprenante, la deuxième partie du code est sensible à la casse et doit être en majuscules :
fr0011869353-xpar
ne renverra aucun résultatfr0011869353-XPAR
renverra le résultat attenduFR0011869353-XPAR
renverra aussi le résultat attenduFR0011869353-xpar
ne renverra aucun résultat {{< /callout >}}
À partir de ces éléments, il m'est donc possible de calculer la valeur de mon portefeuille à partir de son contenu. Il me reste deux questions à résoudre :
- comment stocker le contenu de ce portefeuille, et le mettre à jour à chaque fois que j'achète une action ? (ou vend)
- comment mettre à jour la valeur totale de mon portefeuille telle qu'elle apparaît sur FireflyIII ?