Files
extractions-actions/README.md
T

872 lines
16 KiB
Markdown

# extractions-actions
Routines PHP et script Bash permettant d'extraire automatiquement les cotations des actions composant le **CAC 40**, l'**IBEX 35** et le **Dow Jones**, puis de les enregistrer dans MySQL.
Le projet utilise principalement :
* PHP
* PDO
* MySQL
* cURL
* DOMDocument / DOMXPath
* Bash
* `cron`
* Investing.com comme source des cotations
Le dépôt est disponible sur :
https://www.phie-st-julien.com/jfgiraud/extractions-actions
---
# Fonctionnement général
Le système est organisé autour de deux tables principales :
```text
indice
│ Référentiel des valeurs
Scripts PHP
│ Extraction Investing.com
cours_actions
```
La table `indice` constitue le **référentiel de référence**.
Les scripts récupèrent les informations de marché sur Investing.com mais utilisent les informations de la table `indice` pour conserver les données d'identification des valeurs :
* nom
* ISIN
* symbole
* indice
Les cotations sont enregistrées dans `cours_actions`.
---
# Routines disponibles
Le dépôt contient actuellement quatre fichiers :
```text
extractions-actions/
├── import_cac40.php
├── import_ibex35.php
├── import_dowjones.php
├── import_indices.sh
└── README.md
```
Le dépôt contient actuellement 4 commits et une branche `main`.
---
# 1. import_cac40.php
Routine d'importation des actions du **CAC 40**.
Source Investing.com :
```text
https://www.investing.com/indices/france-40-components
```
Le script :
1. se connecte à MySQL ;
2. charge le référentiel CAC 40 depuis la table `indice` ;
3. sélectionne uniquement les valeurs avec `actif = 1` ;
4. récupère la page Investing.com avec cURL ;
5. analyse le HTML avec `DOMDocument` et `DOMXPath` ;
6. identifie le tableau contenant les cotations ;
7. récupère les données de marché ;
8. fait correspondre les valeurs avec le référentiel MySQL ;
9. enregistre les cotations dans `cours_actions`.
Le script vérifie également que le référentiel contient normalement **40 valeurs**.
---
# 2. import_ibex35.php
Routine d'importation des actions de l'**IBEX 35**.
Source Investing.com :
```text
https://www.investing.com/equities/spain
```
Le principe est identique à celui du CAC 40.
Le référentiel est chargé depuis :
```text
indice
```
avec :
```sql
WHERE indice = 'IBEX35'
AND actif = 1
```
Les informations de cotation sont ensuite récupérées sur Investing.com.
Le script précise notamment que :
* le nom Investing sert à retrouver la valeur dans `indice` ;
* le symbole Investing n'est pas utilisé comme référence ;
* le nom, l'ISIN et le symbole proviennent de `indice` ;
* la table `indice` n'est pas modifiée ;
* les dates sont générées en UTC.
---
# 3. import_dowjones.php
Routine d'importation des valeurs du **Dow Jones Industrial Average**.
Source Investing.com :
```text
https://www.investing.com/equities/americas
```
Le script utilise également la table `indice` comme référentiel.
Seules les valeurs :
```sql
indice = 'DOWJONES'
AND actif = 1
```
sont prises en compte.
Le script effectue la correspondance sur le **nom de la société**.
Une particularité du traitement consiste à supprimer `derived` du nom provenant d'Investing.com lorsque nécessaire afin de permettre la correspondance avec le référentiel.
---
# Identification des actions
Un principe important du projet est la séparation entre :
**référentiel**
```text
indice
```
et :
**source de cotation**
```text
Investing.com
```
Investing.com fournit principalement les informations de marché.
Le référentiel interne fournit les informations d'identification :
```text
nom
isin
symbole
indice
```
Ainsi, une modification du symbole utilisé par Investing.com ne modifie pas automatiquement le référentiel interne.
---
# Table `indice`
La table `indice` constitue le référentiel des valeurs.
Les principaux champs utilisés par les routines sont :
```text
indice
nom
isin
symbole
actif
```
Exemple conceptuel :
```text
indice : CAC40
nom : LVMH
isin : FR0000121014
symbole : MC
actif : 1
```
Le champ :
```text
actif
```
permet de préparer les changements de composition d'un indice sans modifier immédiatement les routines d'importation.
Une valeur peut ainsi être présente dans le référentiel mais ne pas être importée tant que :
```text
actif = 0
```
---
# Table `cours_actions`
Les cotations sont enregistrées dans :
```text
cours_actions
```
Les champs utilisés par les routines comprennent :
```text
indice
nom
isin
symbole
cours
plus_haut
plus_bas
variation
variation_pct
volume
date_cours
source
```
Le script CAC 40 utilise notamment une requête préparée sur ces colonnes.
---
# Mise à jour des cotations
Les routines utilisent :
```sql
ON DUPLICATE KEY UPDATE
```
Cela permet de mettre à jour une cotation existante plutôt que de créer inutilement un doublon.
Les informations mises à jour comprennent notamment :
```text
nom
isin
symbole
cours
plus_haut
plus_bas
variation
variation_pct
volume
date_cours
source
```
Ainsi, chaque nouvelle extraction actualise les informations correspondantes dans `cours_actions`.
---
# Données extraites
Les routines récupèrent notamment :
| Donnée | Description |
| --------------- | ----------------------------- |
| `cours` | Dernier cours |
| `plus_haut` | Plus haut |
| `plus_bas` | Plus bas |
| `variation` | Variation en valeur |
| `variation_pct` | Variation en pourcentage |
| `volume` | Volume |
| `date_cours` | Date et heure de l'extraction |
| `source` | Source de la cotation |
Les valeurs numériques sont nettoyées et converties avant insertion dans MySQL.
---
# Traitement des nombres
Les routines prennent en compte les formats rencontrés sur les pages de cotation.
Le traitement permet notamment de gérer :
* espaces ;
* espaces insécables ;
* `%` ;
* virgules décimales ;
* points décimaux ;
* suffixes `K` ;
* suffixes `M` ;
* suffixes `B`.
Exemple :
```text
1.25K
```
est converti en :
```text
1250
```
et :
```text
2.5M
```
en :
```text
2500000
```
---
# Gestion des erreurs
Les routines vérifient notamment :
* connexion MySQL ;
* récupération HTTP ;
* erreurs cURL ;
* contenu HTML vide ;
* présence du tableau recherché ;
* structure du tableau ;
* données non numériques ;
* valeurs non trouvées dans le référentiel.
En cas d'échec, un message est écrit dans la sortie du script.
Pour le CAC 40, la page HTML récupérée peut également être sauvegardée dans :
```text
/tmp/investing_cac40_error.html
```
lorsque le tableau attendu n'est pas trouvé.
---
# import_indices.sh
Le script :
```text
import_indices.sh
```
constitue le lanceur automatique des trois routines PHP.
Il permet d'éviter d'exécuter les imports lorsque les marchés concernés sont fermés.
Il utilise également un verrou `flock` afin d'empêcher plusieurs exécutions simultanées.
---
# Protection contre les exécutions simultanées
Le script utilise :
```bash
LOCK="/var/run/import_indices.lock"
```
puis :
```bash
exec 9>"$LOCK"
if ! flock -n 9; then
exit 0
fi
```
Ainsi, si une instance précédente est encore en cours, une nouvelle instance quitte immédiatement.
Cela est particulièrement important lorsque le script est appelé par `cron` toutes les minutes.
---
# Journalisation
Les logs sont enregistrés dans :
```text
/var/log/import_indices.log
```
Pour chaque import, le script écrit notamment :
```text
DATE - DEBUT CAC40
DATE - FIN CAC40 (CODE)
```
Même principe pour :
```text
IBEX35
DOW JONES
```
Le code retour PHP est conservé dans le journal.
---
# Horaires d'exécution
Le script utilise le fuseau :
```text
Europe/Paris
```
```bash
export TZ="Europe/Paris"
```
Il ne lance aucun import le week-end.
## CAC 40
Fenêtre d'extraction :
```text
09:00 → 17:30
```
## IBEX 35
Fenêtre d'extraction :
```text
09:00 → 17:30
```
## Dow Jones
Fenêtre d'extraction :
```text
15:30 → 22:00
```
Ces horaires sont contrôlés directement par `import_indices.sh`.
---
# Fonctionnement avec cron
Le principe recommandé est de faire tourner le script Bash régulièrement, par exemple toutes les minutes :
```cron
* * * * * /var/www/extractions/import_indices.sh
```
Le script décide ensuite lui-même si un marché est ouvert.
Cela signifie que `cron` peut être lancé chaque minute sans provoquer d'import lorsque :
* nous sommes le week-end ;
* l'heure est en dehors des horaires prévus ;
* une autre instance du script est déjà en cours.
---
# Flux complet
```text
CRON
┌─────────────────┐
│ import_indices.sh│
└────────┬────────┘
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
CAC 40 IBEX 35 DOW JONES
│ │ │
▼ ▼ ▼
Investing.com Investing.com Investing.com
│ │ │
└───────────┼───────────┘
Correspondance
avec `indice`
`cours_actions`
MySQL GF
```
---
# Principe de sécurité des données
Les scripts ne modifient pas le référentiel `indice`.
Le référentiel est considéré comme la source interne de vérité pour :
```text
ISIN
symbole
nom
indice
```
Les routines ont pour rôle de récupérer les cotations et de mettre à jour :
```text
cours_actions
```
Cette séparation permet d'éviter qu'une modification de la page Investing.com ne vienne écraser les informations de référence.
---
# Configuration MySQL
Les scripts utilisent actuellement la base :
```text
GF
```
avec une connexion locale MySQL.
La configuration est présente au début de chaque routine PHP.
Exemple :
```php
$dbHost = 'localhost';
$dbName = 'GF';
$dbUser = 'root';
```
**Attention : le mot de passe MySQL ne doit pas être stocké en clair dans un dépôt Git.**
Pour une installation de production, il est recommandé d'utiliser :
* un fichier de configuration hors dépôt ;
* des variables d'environnement ;
* un utilisateur MySQL dédié avec les droits minimum nécessaires.
---
# Dépendances PHP
Les routines utilisent notamment :
```text
PDO
PDO_MySQL
cURL
DOMDocument
DOMXPath
mbstring
```
Les extensions PHP nécessaires doivent donc être installées sur le serveur.
---
# Installation
Copier le projet dans le répertoire souhaité :
```bash
cd /var/www
git clone https://www.phie-st-julien.com/jfgiraud/extractions-actions.git
```
Rendre le script Bash exécutable :
```bash
chmod +x /var/www/extractions/import_indices.sh
```
Tester individuellement les routines :
```bash
php /var/www/extractions/import_cac40.php
```
```bash
php /var/www/extractions/import_ibex35.php
```
```bash
php /var/www/extractions/import_dowjones.php
```
Puis tester le lanceur :
```bash
/var/www/extractions/import_indices.sh
```
---
# Vérification des logs
Consulter le journal :
```bash
tail -f /var/log/import_indices.log
```
Pour rechercher les erreurs :
```bash
grep -i "erreur" /var/log/import_indices.log
```
Pour voir les derniers imports :
```bash
tail -100 /var/log/import_indices.log
```
---
# Vérification MySQL
Après une extraction, vérifier les dernières cotations :
```sql
SELECT *
FROM cours_actions
ORDER BY date_cours DESC
LIMIT 20;
```
Pour un indice donné :
```sql
SELECT *
FROM cours_actions
WHERE indice = 'CAC40'
ORDER BY date_cours DESC;
```
Pour l'IBEX 35 :
```sql
SELECT *
FROM cours_actions
WHERE indice = 'IBEX35'
ORDER BY date_cours DESC;
```
Pour le Dow Jones :
```sql
SELECT *
FROM cours_actions
WHERE indice = 'DOWJONES'
ORDER BY date_cours DESC;
```
---
# Vérification du nombre de valeurs
CAC 40 :
```sql
SELECT COUNT(*)
FROM indice
WHERE indice = 'CAC40'
AND actif = 1;
```
IBEX 35 :
```sql
SELECT COUNT(*)
FROM indice
WHERE indice = 'IBEX35'
AND actif = 1;
```
Dow Jones :
```sql
SELECT COUNT(*)
FROM indice
WHERE indice = 'DOWJONES'
AND actif = 1;
```
Cela permet de détecter rapidement une modification de composition ou une valeur manquante.
---
# Maintenance
Lorsqu'une entreprise entre ou sort d'un indice, la modification doit être effectuée dans :
```text
indice
```
et non directement dans les routines PHP.
Le principe est :
```text
Modification du référentiel
indice
Les routines utilisent automatiquement
le nouveau référentiel
```
Le champ `actif` permet notamment de préparer une modification future avant son activation.
---
# Ajout d'un nouvel indice
Pour ajouter un nouvel indice, le principe consiste à :
1. créer le référentiel dans `indice` ;
2. ajouter une routine PHP dédiée ;
3. identifier la page source ;
4. adapter le parsing HTML ;
5. utiliser le référentiel interne pour l'ISIN et le symbole ;
6. écrire les cotations dans `cours_actions` ;
7. ajouter la routine au script `import_indices.sh` ;
8. définir les horaires de marché ;
9. tester manuellement ;
10. intégrer l'exécution dans `cron`.
---
# Limites
Les routines dépendent de la structure HTML des pages Investing.com.
Une modification du site source peut donc nécessiter une adaptation du parsing :
```text
DOMDocument
DOMXPath
```
Il est donc important de conserver les tests et les contrôles de cohérence présents dans les scripts.
---
# Évolution prévue
Le projet peut progressivement intégrer :
* Nasdaq-100 ;
* S&P 500 ;
* DAX ;
* FTSE 100 ;
* Euro Stoxx 50 ;
* autres indices ;
* détection automatique des changements de composition ;
* gestion des jours fériés ;
* contrôle automatique du nombre de valeurs ;
* alertes en cas d'échec d'import ;
* centralisation de la configuration MySQL ;
* journalisation plus détaillée ;
* surveillance du fonctionnement du cron.
---
# Relation avec le site boursier
Les données produites par ce projet peuvent ensuite être utilisées par le site d'affichage des actions.
Le flux devient :
```text
Investing.com
extractions-actions
MySQL
├── indice
└── cours_actions
Site boursier
├── tableau des actions
└── bandeau défilant
```
Les routines d'extraction constituent donc la **couche d'alimentation du système boursier**.
---
# Résumé
| Composant | Rôle |
| --------------------- | ------------------------- |
| `indice` | Référentiel des actions |
| `import_cac40.php` | Extraction CAC 40 |
| `import_ibex35.php` | Extraction IBEX 35 |
| `import_dowjones.php` | Extraction Dow Jones |
| `cours_actions` | Stockage des cotations |
| `import_indices.sh` | Orchestration des imports |
| `cron` | Déclenchement périodique |
| Investing.com | Source des cotations |
| MySQL | Base de données |
---
# Auteur
**jfgiraud**
Projet personnel de collecte et d'alimentation d'une base de données boursière.
Technologies :
**PHP · MySQL · PDO · cURL · DOMXPath · Bash · cron**