Guides / Analyser un marché

Analyser un marché local

Combinez stats, tendances et activité pour un tableau de bord marché complet.

Une analyse de marché efficace combine trois dimensions : l'état actuel (statistiques agrégées), l'évolution temporelle (tendances), et la dynamique (activité, saisonnalité). Normi propose un endpoint dédié à chaque dimension.

1. Statistiques actuelles

Commencez par une vue d'ensemble : volume de transactions, prix médian, prix au m².

import requests

API_KEY = "normi_votre_token"
BASE_URL = "https://mcp.normi.fr/v1"
HEADERS = {"X-API-Key": API_KEY}

# 1. Statistiques agrégées — état actuel du marché
stats = requests.get(
    f"{BASE_URL}/stats/market",
    params={"code_postal": "33000", "type_local": "Appartement"},
    headers=HEADERS,
).json()

print(f"=== Marché Appartements — Bordeaux Centre (33000) ===")
print(f"Transactions (3 ans)  : {stats['count']:,}")
print(f"Prix médian           : {stats['price']['median']:,} €")
print(f"Prix médian au m²     : {stats['price_per_m2']['median']:,} €/m²")
print(f"Surface médiane       : {stats['surface']['median']} m²")

2. Tendances temporelles

/v1/stats/trends retourne l'évolution par période avec les variations year-over-year (YoY). Résultats mis en cache 24h.

# 2. Évolution trimestrielle sur 5 ans
trends = requests.get(
    f"{BASE_URL}/stats/trends",
    params={
        "code_postal": "33000",
        "type_local": "Appartement",
        "granularity": "quarter",
    },
    headers=HEADERS,
).json()

print(f"\n=== Tendances trimestrielles ===")
print(f"Tendance globale : {trends['summary']['overall_trend']}")
print(f"Variation totale : {trends['summary']['total_change_pct']:+.1f}%")

# Afficher les 4 derniers trimestres
for t in trends["trends"][-4:]:
    yoy = t["yoy_change"]["price_median_pct"]
    print(f"  {t['period']} : {t['price']['median']:,} € ({yoy:+.1f}% YoY)")
Cache 24h sur /v1/stats/trends
Les requêtes identiques dans la journée ne consomment qu'un seul débit réseau, mais les crédits sont toujours déduits. Stockez les résultats côté client si vous faites plusieurs requêtes identiques.

3. Saisonnalité et activité

Utilisez la granularité mensuelle pour identifier les pics d'activité saisonniers.

# 3. Activité et saisonnalité (24 derniers mois)
activity = requests.get(
    f"{BASE_URL}/stats/trends",
    params={
        "code_postal": "33000",
        "granularity": "month",
        "date_debut": "2024-01-01",
    },
    headers=HEADERS,
).json()

# Identifier les mois les plus actifs
monthly = sorted(
    activity["trends"],
    key=lambda t: t["transaction_count"],
    reverse=True,
)

print("\n=== Top 3 mois les plus actifs ===")
for m in monthly[:3]:
    print(f"  {m['period']} : {m['transaction_count']} transactions, {m['price']['median']:,} € médiane")

4. Comparer plusieurs zones

Comparez plusieurs codes postaux ou communes pour identifier les zones premium et abordables.

# 4. Comparaison de quartiers — Bordeaux vs Mériadeck vs Chartrons
compare = requests.get(
    f"{BASE_URL}/stats/market",
    params={"commune": "BORDEAUX", "type_local": "Appartement"},
    headers=HEADERS,
).json()

# Requêtes par code postal pour granularité quartier
QUARTIERS = {
    "Centre (33000)": "33000",
    "Caudéran (33200)": "33200",
    "Bacalan (33300)": "33300",
}

print("\n=== Comparaison par quartier ===")
print(f"{'Quartier':<25} {'Médiane/m²':>12} {'Transactions':>14}")
print("-" * 55)

for name, cp in QUARTIERS.items():
    r = requests.get(
        f"{BASE_URL}/stats/market",
        params={"code_postal": cp, "type_local": "Appartement"},
        headers=HEADERS,
    ).json()
    print(f"{name:<25} {r['price_per_m2']['median']:>10,} €/m² {r['count']:>12,}")
Coût de comparaison multi-zones
Chaque appel à /v1/stats/market coûte 5 crédits. Comparer 4 zones = 20 crédits. Pensez à mettre en cache les résultats si vous construisez un tableau de bord.

Visualisation avec Chart.js

Les données de tendances sont directement compatibles avec Chart.js pour des graphiques d'évolution des prix.

// Préparer les données pour Chart.js
const trends = await fetchTrends("33000", "Appartement", "quarter");

const chartData = {
  labels: trends.trends.map((t) => t.period),
  datasets: [
    {
      label: "Prix médian au m² (€)",
      data: trends.trends.map((t) => t.price_per_m2.median),
      borderColor: "rgb(37, 99, 235)",
      backgroundColor: "rgba(37, 99, 235, 0.1)",
      tension: 0.3,
      fill: true,
    },
  ],
};

const config = {
  type: "line",
  data: chartData,
  options: {
    responsive: true,
    plugins: {
      legend: { position: "top" },
      title: { display: true, text: "Évolution du prix au m² — Bordeaux 33000" },
    },
    scales: {
      y: {
        ticks: {
          callback: (value) => `${value.toLocaleString("fr-FR")} €`,
        },
      },
    },
  },
};

// new Chart(document.getElementById("myChart"), config);

Avec Claude (MCP)

Claude peut réaliser toute l'analyse en une seule instruction :

"Fais-moi une analyse complète du marché immobilier des appartements à Bordeaux : 1. Les statistiques actuelles (prix médian, prix/m², volume) 2. L'évolution des prix sur 3 ans avec la variation YoY 3. Les mois les plus actifs en termes de transactions 4. Une comparaison entre les codes postaux 33000, 33200 et 33300"