Introduction
La prévision de trésorerie est un outil essentiel pour toute entreprise, permettant d'anticiper les soldes futurs à partir des flux entrants (encaissements) et sortants (décaissements). En 2026, avec la volatilité économique, automatiser ces calculs via Python devient indispensable pour gagner du temps et minimiser les erreurs humaines.
Ce tutoriel intermédiaire vous guide pas à pas pour créer une application web complète avec Streamlit, Pandas et Matplotlib. Vous partirez de données historiques (CSV simple) pour projeter 12 mois en avant, en utilisant une méthode hybride : moyenne mobile pour la stabilité et régression linéaire pour la tendance. Imaginez comme un GPS financier : il analyse votre parcours passé pour tracer la route future.
Résultat : une interface interactive où vous uploadez vos données, ajustez les paramètres, et visualisez soldes, alertes de découvert et graphiques. Parfait pour CFOs tech-savvy ou devs en finance. Temps estimé : 30 minutes pour un prototype fonctionnel.
Prérequis
- Python 3.10+ installé
- Connaissances de base en Pandas et DataFrames
- pip pour les dépendances
- Fichier CSV exemple avec colonnes :
date(YYYY-MM-DD),entrees(float),sorties(float),solde_initial(optionnel) - Éditeur comme VS Code
Installation des dépendances
pip install streamlit pandas numpy matplotlib plotly scikit-learnCes paquets forment la base : Streamlit pour l'interface web, Pandas/Numpy pour les calculs, Matplotlib/Plotly pour les visualisations interactives, et scikit-learn pour la régression linéaire. Exécutez en terminal pour un environnement virtuel recommandé (via venv).
Préparation des données d'exemple
Créez un fichier CSV de test pour simuler des flux réels. Colonnes obligatoires : date, entrees, sorties. Le solde se calcule cumulativement : solde_mensuel = solde_precedent + entrees - sorties. Utilisez des dates mensuelles pour simplifier les agrégations.
Génération du fichier CSV d'exemple
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# Paramètres
start_date = datetime(2025, 1, 1)
dates = pd.date_range(start=start_date, periods=24, freq='MS')
# Flux aléatoires réalistes (entrees > sorties en moyenne)
np.random.seed(42)
entrees = np.random.normal(50000, 10000, 24).clip(20000)
sorties = np.random.normal(40000, 8000, 24).clip(15000)
# Solde initial
df = pd.DataFrame({
'date': dates,
'entrees': entrees,
'sorties': sorties
})
df['solde'] = df['entrees'].cumsum() - df['sorties'].cumsum() + 100000 # Solde initial 100k€
df.to_csv('tresorerie_historique.csv', index=False)
print('Fichier créé : tresorerie_historique.csv')
print(df.head())Ce script génère 24 mois de données fictives mais réalistes (moyenne entrees 50k€, sorties 40k€, solde initial 100k€). La seed assure la reproductibilité. Exécutez-le pour obtenir tresorerie_historique.csv, prêt pour les tests. Piège : toujours clipper les valeurs négatives pour éviter les flux absurdes.
Chargement et nettoyage des données
Dans l'app Streamlit, chargez le CSV, convertissez date en datetime, agrégez mensuellement si besoin, et calculez les soldes cumulés. Gérez les NaN et validez les colonnes pour robustesse.
Fonctions de chargement et nettoyage
import pandas as pd
import streamlit as st
@st.cache_data
def load_data(uploaded_file):
df = pd.read_csv(uploaded_file)
df['date'] = pd.to_datetime(df['date'])
df = df.sort_values('date').reset_index(drop=True)
# Vérifications
required_cols = ['date', 'entrees', 'sorties']
if not all(col in df.columns for col in required_cols):
st.error('Colonnes manquantes : date, entrees, sorties')
st.stop()
# Nettoyage
df = df.dropna(subset=required_cols)
df['entrees'] = pd.to_numeric(df['entrees'], errors='coerce').fillna(0)
df['sorties'] = pd.to_numeric(df['sorties'], errors='coerce').fillna(0)
# Calcul solde cumulé
solde_initial = st.number_input('Solde initial (€)', value=100000.0)
df['solde'] = solde_initial + df['entrees'].cumsum() - df['sorties'].cumsum()
return df
# Utilisation : df = load_data(st.file_uploader('Upload CSV'))Cette fonction charge, valide et nettoie les données via Streamlit. Le @st.cache_data optimise les rechargements. Solde cumulé dynamique avec input utilisateur. Piège : ignorer les erreurs de conversion peut corrompre les calculs ; utilisez toujours errors='coerce'. Copiez dans votre app principale.
Algorithme de prévision
Moyenne mobile (période 3 mois) pour lisser les fluctuations + régression linéaire sur les tendances entrees/sorties. Projetez 12 mois : pour chaque mois futur, appliquez les prédictions aux soldes cumulés. Alertes si solde < 10k€.
Fonctions de prévision
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from datetime import timedelta
def forecast_tresorerie(df, periods=12):
df_forecast = df.copy()
# Moyenne mobile pour lissage
df['entrees_smooth'] = df['entrees'].rolling(window=3, min_periods=1).mean()
df['sorties_smooth'] = df['sorties'].rolling(window=3, min_periods=1).mean()
# Régression linéaire sur tendances
X = np.arange(len(df)).reshape(-1, 1)
reg_entrees = LinearRegression().fit(X, df['entrees_smooth'])
reg_sorties = LinearRegression().fit(X, df['sorties_smooth'])
# Projection
last_date = df['date'].max()
future_dates = pd.date_range(start=last_date + timedelta(days=1), periods=periods, freq='MS')
future_X = np.arange(len(df), len(df) + periods).reshape(-1, 1)
future_entrees = reg_entrees.predict(future_X)
future_sorties = reg_sorties.predict(future_X)
future_df = pd.DataFrame({
'date': future_dates,
'entrees_pred': future_entrees,
'sorties_pred': future_sorties
})
# Solde projeté
last_solde = df['solde'].iloc[-1]
future_df['solde_pred'] = np.cumsum(future_entrees - future_sorties) + last_solde
df_forecast = pd.concat([df_forecast, future_df], ignore_index=True)
df_forecast['type'] = ['historique'] * len(df) + ['prevision'] * periods
return df_forecast
# Utilisation : df_full = forecast_tresorerie(df)Hybride robuste : rolling mean lisse le bruit, LinearRegression capture la croissance. freq='MS' pour mensuel. Soldes cumulés préservent la réalité comptable. Piège : sans min_periods=1, les débuts manquent ; testez avec <3 mois de data.
Visualisation interactive
Affichez graphiques : évolution soldes (ligne), histo flux (barres), avec zoom Plotly. Ajoutez métriques : solde min projeté, % croissance moyenne.
Visualisations et métriques
import streamlit as st
import plotly.express as px
import plotly.graph_objects as go
def plot_forecast(df_full):
fig = go.Figure()
# Soldes
fig.add_trace(go.Scatter(x=df_full['date'], y=df_full['solde'],
mode='lines+markers', name='Solde historique',
line=dict(color='blue')))
fig.add_trace(go.Scatter(x=df_full[df_full['type']=='prevision']['date'],
y=df_full[df_full['type']=='prevision']['solde_pred'],
mode='lines+markers', name='Solde prévisionnel',
line=dict(color='orange', dash='dash')))
fig.update_layout(title='Évolution de la trésorerie', xaxis_title='Date', yaxis_title='Solde (€)')
st.plotly_chart(fig, use_container_width=True)
# Métriques
solde_min = df_full[df_full['type']=='prevision']['solde_pred'].min()
if solde_min < 10000:
st.error(f'🚨 Alerte : Solde minimum projeté = {solde_min:,.0f}€')
else:
st.success(f'Solde minimum projeté = {solde_min:,.0f}€')
croissance = (df_full['entrees'].tail(12).mean() / df_full['entrees'].head(12).mean() - 1) * 100
st.metric('Croissance moyenne entrees (%)', f'{croissance:.1f}%')
# Utilisation : plot_forecast(df_full)Plotly pour interactivité (zoom, hover). Traces séparées historique/prévision. Alertes conditionnelles boostent l'utilité. Piège : sans use_container_width=True, le chart déborde ; toujours filtrer par type pour clarté.
Application Streamlit complète
import streamlit as st
from data_loader import load_data
from forecaster import forecast_tresorerie
from visualizer import plot_forecast
st.set_page_config(page_title='Prévision Trésorerie', layout='wide')
st.title('🚀 Prévision de Trésorerie Automatisée')
uploaded_file = st.file_uploader('Choisissez votre fichier CSV', type='csv')
if uploaded_file is not None:
df = load_data(uploaded_file)
st.subheader('Données chargées')
st.dataframe(df.tail())
periods = st.slider('Mois à prévoir', 3, 24, 12)
df_full = forecast_tresorerie(df, periods)
col1, col2 = st.columns(2)
with col1:
plot_forecast(df_full)
with col2:
st.subheader('Tableau prévisionnel')
st.dataframe(df_full[df_full['type']=='prevision'])
st.download_button('Télécharger CSV complet', df_full.to_csv(index=False),
'tresorerie_forecast.csv')
if __name__ == '__main__':
st.info('Exécutez : streamlit run app.py')App intégrant tout : upload, params, viz, export. Layout wide optimise l'espace. Modularité via imports. Lancez avec streamlit run app.py. Piège : sans st.cache_data, rechargements lents ; testez avec gros CSV.
Bonnes pratiques
- Validez toujours les données : colonnes, types, NaN pour éviter crashes en prod.
- Utilisez des environnements virtuels :
venv+requirements.txtpour déploiement. - Modularisez le code : fonctions séparées pour tests unitaires (pytest).
- Sécurisez les inputs : limitez tailles fichiers, sanitizez valeurs.
- Déployez sur cloud : Streamlit Cloud gratuit pour sharing avec équipe finance.
Erreurs courantes à éviter
- Oublier le cumulé des soldes : prévision non-réaliste si on reset à zéro chaque mois.
- Pas de lissage : moyenne mobile absente amplifie le bruit aléatoire.
- Dates mal formatées :
pd.to_datetimeéchoue sans gestion errors → crash app. - Prévisions trop optimistes : ajoutez scénarios pessimistes (facteur 1.2 sur sorties).
Pour aller plus loin
Intégrez ML avancé (Prophet pour saisonnalité) ou API compta (QuickBooks). Découvrez nos formations Python Data Science et Streamlit Pro. Ressources : Doc Pandas, Streamlit Gallery.