Ce projet personnel a été réalisé pour démontrer mes compétences en ingénierie des données et en conception de systèmes d'information. Il s'agit de la modélisation et de l'exploitation relationnelle d'une plateforme de gestion de portefeuilles boursiers (type eToro / Boursorama).
Ce projet allie mon intérêt pour les marchés financiers et le Back-End / Data Engineering, s'inscrivant parfaitement dans mon projet d'intégrer un Master MIAGE.
- SGBD : PostgreSQL
- Modélisation : DBML / dbdiagram.io
- Concepts SQL : DDL/DML, Contraintes (CHECK, FK), CTE (Common Table Expressions), Window Functions, Agrégations conditionnelles.
Justification des choix de cardinalités :
- Un
Utilisateurpeut avoir plusieursPortefeuilles(1:N), permettant de séparer PEA et Compte-Titres. - Une
Transactionest liée à un seulPortefeuilleet un seulActif(N:1). - L'
Historique_Prixutilise une clé primaire composite(actif_id, date_cotation)pour garantir une seule valeur de clôture par jour et par action.
L'objectif de cette base n'est pas seulement de stocker, mais d'analyser. Voici quelques requêtes clés tirées de mon fichier analytics_queries.sql.
Cette requête calcule la position nette de chaque utilisateur (Achats - Ventes) et la croise avec le dernier cours de clôture connu pour donner la valeur totale de son portefeuille.
WITH PositionsActuelles AS (
SELECT p.utilisateur_id, t.actif_id,
SUM(CASE WHEN t.type_ordre = 'ACHAT' THEN t.quantite ELSE -t.quantite END) AS qte
FROM Transactions t JOIN Portefeuilles p ON t.portefeuille_id = p.id
GROUP BY p.utilisateur_id, t.actif_id
),
DerniersPrix AS (
SELECT actif_id, prix_cloture FROM Historique_Prix hp1
WHERE date_cotation = (SELECT MAX(date_cotation) FROM Historique_Prix hp2 WHERE hp1.actif_id = hp2.actif_id)
)
SELECT u.nom, SUM(pa.qte * dp.prix_cloture) AS valorisation_totale
FROM PositionsActuelles pa
JOIN DerniersPrix dp ON pa.actif_id = dp.actif_id
JOIN Utilisateurs u ON pa.utilisateur_id = u.id
GROUP BY u.nom;Utilisation de OVER PARTITION BY pour le traitement de séries temporelles (Time Series), très utilisé en finance de marché.
SELECT
a.ticker_symbol, hp.date_cotation, hp.prix_cloture,
ROUND(AVG(hp.prix_cloture) OVER (
PARTITION BY hp.actif_id
ORDER BY hp.date_cotation
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
), 2) AS moyenne_mobile_7j
FROM Historique_Prix hp
JOIN Actifs a ON hp.actif_id = a.id
WHERE a.ticker_symbol = 'AAPL';- Cloner le repository.
- Exécuter le script
schema_and_data.sqlsur une instance PostgreSQL. - Lancer les requêtes du fichier
analytics_queries.sqlpour observer les résultats.

