Add article on action portfolio with firefly
This commit is contained in:
parent
368ee09953
commit
d69ddb02a5
3 changed files with 157 additions and 5 deletions
10
config.toml
10
config.toml
|
@ -92,11 +92,11 @@ logoText = "Hello there!"
|
|||
logoHomeLink = "/fr/"
|
||||
|
||||
[menu]
|
||||
# [[menu.main]]
|
||||
# identifier = "blog"
|
||||
# name = "Blog"
|
||||
# url = "/posts"
|
||||
# weight = 1
|
||||
[[menu.main]]
|
||||
identifier = "blog"
|
||||
name = "Blog"
|
||||
url = "/posts"
|
||||
weight = 1
|
||||
|
||||
[[menu.main]]
|
||||
identifier = "about_me"
|
||||
|
|
BIN
content/fr/posts/firefly-action-management/euronext.png
Normal file
BIN
content/fr/posts/firefly-action-management/euronext.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
152
content/fr/posts/firefly-action-management/index.md
Normal file
152
content/fr/posts/firefly-action-management/index.md
Normal file
|
@ -0,0 +1,152 @@
|
|||
---
|
||||
title: "Gérer son épargne en action sous Firefly"
|
||||
date: 2023-12-19T20:10:42+02:00
|
||||
draft: 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](https://live.euronext.com/fr/product/etfs/fr0011869353-xpar/lyxor-msci-wor-pea/ewld)
|
||||
- On obtient facilement les mêmes informations sur [Google Finance](https://www.google.com/finance/quote/EWLD:EPA?hl=fr) ou [Yahoo Finance](https://fr.finance.yahoo.com/quote/EWLD.PA/profile/?guccounter=1)
|
||||
|
||||
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](https://live.euronext.com/fr/product/etfs/fr0011869353-xpar/lyxor-msci-wor-pea/ewld).
|
||||
|
||||
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€.
|
||||
|
||||
![Bandeau des valeurs de l'action MSCI world sur le site Euronext](euronext.png)
|
||||
|
||||
En observant le contenu de la page web, on obtient d'ailleurs ceci :
|
||||
|
||||
```html
|
||||
<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):
|
||||
|
||||
```json
|
||||
[
|
||||
{"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
|
||||
|
||||
```python
|
||||
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ésultat
|
||||
- `fr0011869353-XPAR` renverra le résultat attendu
|
||||
- `FR0011869353-XPAR` renverra aussi le résultat attendu
|
||||
- `FR0011869353-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 ?
|
||||
|
||||
## Lien avec Firefly
|
Loading…
Reference in a new issue