GUIDE TECHNIQUE - PARTIE 3/3

Le Tooling du Trader : Grafana, Discord, Claude Code et OpenClow

La boite a outils complete du trader retail pour monitorer, alerter et orchestrer sa stack de trading systematique.

Tooling Pratique
25 min
Debutant
Open Source
Monitoring Trading Stack
3/3

Serie : Monitorer sa Stack de Trading

1 Post-Mortems 2 Architecture 3 Tooling

La Boite a Outils du Trader Moderne

Dans les deux premieres parties de cette serie, nous avons explore les post-mortems les plus marquants du trading algorithmique (Part 1) et l'architecture de monitoring qui permet d'eviter ces catastrophes (Part 2). Maintenant, il est temps de mettre les mains dans le cambouis : quels outils concrets utiliser ?

La bonne nouvelle : en 2026, un trader retail dispose d'outils qui rivalisent avec ceux des hedge funds d'il y a 5 ans. La mauvaise nouvelle : le choix est ecrasant. Grafana, Prometheus, Datadog, PagerDuty, Slack, Discord, Telegram, Claude Code, ChatGPT, n8n, Airflow... Comment s'y retrouver ?

Ce guide va vous presenter une stack concrete, testee en production, 100% open source (ou presque), et adaptee au budget d'un trader individuel. Pas de licence a 50 000 euros par an. Pas de cluster Kubernetes a 20 noeuds. Juste un VPS a 10 euros par mois et les bons outils.

Pourquoi le tooling est si important

Revenons un instant sur les lecons de la Partie 1 :

Le monitoring ne remplace pas une bonne strategie. Mais une bonne strategie sans monitoring est comme une voiture de course sans frein : elle ira tres vite... droit dans le mur.

Grafana
Dashboards temps reel pour P&L, positions, risques et metriques systeme. Le cockpit du trader.
Prometheus + Alertmanager
Collecte de metriques et regles d'alertes automatiques. Le systeme nerveux.
Discord
Centre de commande pour alertes, trades et kill-switch interactif. La tour de controle.
Claude Code + MCP
Assistant IA pour analyse de marche, debug et generation de dashboards. L'analyste infatigable.

Criteres de selection

Le choix de cette stack repose sur 4 criteres fondamentaux que tout trader retail devrait exiger :

Critere Exigence Pourquoi c'est important
Cout Gratuit ou < 20 EUR/mois Un trader retail ne peut pas payer des licences enterprise a 50 000 EUR/an
Open Source Code source disponible Pas de vendor lock-in, communaute active, personnalisable a 100%
Simplicite Deploiement en < 1h Vous etes trader, pas SRE. Le tooling doit servir, pas asservir.
Integration API + webhooks natifs Les outils doivent communiquer entre eux sans friction ni glue code

Open Source vs Commercial : le vrai debat

Beaucoup de traders debutants hesitent entre des solutions commerciales (TradingView alerts, Datadog, CloudWatch) et des outils open source. Voici la regle simple :

Commercial = rapide a mettre en place, limite en personnalisation, cout recurrent. Parfait si vous tradez manuellement et avez besoin d'alertes basiques sur les prix.

Open Source = plus de setup initial (un weekend), personnalisation infinie, cout quasi nul. Indispensable si vous faites du trading algorithmique et avez besoin de metriques custom (drawdown, latence, exposition, slippage...).

Notre recommandation : commencez par l'open source des le debut. L'investissement en temps initial vous fera economiser des milliers d'euros sur le long terme et vous donnera un controle total sur votre infrastructure.

La stack complete en un coup d'oeil

Voici comment les outils s'imbriquent dans l'architecture de monitoring de la Partie 2 :

Couche Outil Role Alternative
Collecte Prometheus Scrape les metriques de vos services InfluxDB, VictoriaMetrics
Stockage Prometheus TSDB + PostgreSQL Time-series + donnees relationnelles TimescaleDB, ClickHouse
Visualisation Grafana Dashboards interactifs temps reel Metabase, Superset, Evidence.dev
Alerting Alertmanager Routage, deduplication, inhibition des alertes Grafana Alerting, OpsGenie
Notification Discord Reception des alertes + commandes interactives Slack, Telegram, PagerDuty
Intelligence Claude Code + MCP Analyse IA, generation de contenu, debug ChatGPT, Gemini, Aider
Orchestration OpenClow Scheduling, execution, risk management Airflow, n8n, Prefect, Dagster

Architecture visuelle de la stack

Grafana : Le Tableau de Bord Universel

Grafana est le standard de facto pour la visualisation de donnees en temps reel. Cree en 2014 par Torkel Odegaard, il est utilise par Netflix, Uber, Bloomberg et des milliers d'equipes de trading dans le monde. Et il est 100% open source (licence AGPLv3).

Pour un trader, Grafana est l'equivalent de votre cockpit d'avion : c'est l'ecran unique ou vous voyez tout ce qui se passe dans votre stack, en un coup d'oeil. P&L en temps reel, positions ouvertes, drawdown, latence des ordres, sante du systeme.

Pourquoi Grafana et pas TradingView ?

Question frequente et legitime. TradingView est excellent pour l'analyse technique des graphiques de prix. Grafana est concu pour un usage completement different :

Critere TradingView Grafana
Metriques custom Non (Pine Script limite aux prix) Oui (n'importe quelle metrique imaginable)
Donnees systeme Non CPU, RAM, latence, erreurs, uptime
P&L temps reel Non (pas de connexion broker native) Oui (via Prometheus + API broker)
Alertes flexibles Limitees (prix, volume, indicateurs) Illimitees (PromQL, multi-condition, templated)
Cout 30 USD/mois (Essential) 0 EUR (self-hosted)
Self-hosted Non (SaaS uniquement) Oui (Docker, binaire, Kubernetes)
Multi-datasource Donnees TradingView uniquement 100+ data sources (Prometheus, SQL, APIs, etc.)

En resume : TradingView pour analyser les marches, Grafana pour monitorer votre stack. Les deux sont complementaires.

Installation avec Docker Compose

La facon la plus simple d'installer Grafana est via Docker. Voici le fichier docker-compose.yml minimal :

# docker-compose.grafana.yml
version: '3.8'

services:
  grafana:
    image: grafana/grafana:latest
    container_name: trading-grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=trader
      - GF_SECURITY_ADMIN_PASSWORD=changeme_strong_password
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_SERVER_ROOT_URL=http://localhost:3000
      - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-piechart-panel
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    networks:
      - trading-net

volumes:
  grafana-data:

networks:
  trading-net:
    driver: bridge

Lancez avec docker compose -f docker-compose.grafana.yml up -d puis ouvrez http://localhost:3000. Votre dashboard est pret en 30 secondes.

Les 4 dashboards essentiels du trader

Apres des mois d'iteration, nous avons identifie les 4 dashboards qui couvrent 95% des besoins d'un trader systematique :

Dashboard 1 : P&L Tracker
P&L cumule (realise + unrealise), par strategie et par instrument. Courbe d'equity. Drawdown en cours. Comparaison vs benchmark (SPY).
Dashboard 2 : Positions Monitor
Positions ouvertes en temps reel. Exposition nette (long - short). Delta portfolio. Beta-weighted exposure. Heatmap par secteur.
Dashboard 3 : Risk Metrics
VaR (95%, 99%). Max drawdown rolling 30j. Sharpe ratio. Win rate par strategie. Limites et violations.
Dashboard 4 : System Health
Latence API broker (p50, p99). CPU/RAM. Files de messages. Erreurs par endpoint. Uptime de chaque service.

Sources de donnees recommandees

Data Source Type de donnees Usage principal Performance
Prometheus Time-series metriques Metriques systeme, latences, compteurs trading Excellent pour < 1M series actives
PostgreSQL Relationnelles Trades, positions, historique P&L, audit trail Bon pour requetes complexes (JOIN, agreg.)
TimescaleDB Time-series SQL OHLCV, ticks, order book snapshots Excellent (compression 90%+ , hypertables)
InfluxDB Time-series natif Metriques haute frequence (sub-seconde) Tres bon, langage Flux puissant
JSON API REST endpoints Donnees broker temps reel, prix spot Depend de l'API externe

Exemple de dashboard JSON provisionne

Grafana permet de provisionner des dashboards automatiquement via des fichiers JSON. Voici un extrait d'un panel P&L avec gauge de drawdown :

{
  "dashboard": {
    "title": "Trading P&L Tracker",
    "uid": "trading-pnl",
    "tags": ["trading", "pnl"],
    "timezone": "America/New_York",
    "panels": [
      {
        "title": "P&L Cumule (USD)",
        "type": "timeseries",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "sum(trading_pnl_realized_total) + sum(trading_pnl_unrealized_total)",
            "legendFormat": "P&L Total"
          },
          {
            "expr": "sum(trading_pnl_realized_total)",
            "legendFormat": "Realise"
          },
          {
            "expr": "sum(trading_pnl_unrealized_total)",
            "legendFormat": "Non Realise"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "unit": "currencyUSD",
            "custom": {
              "drawStyle": "line",
              "lineWidth": 2,
              "fillOpacity": 10,
              "gradientMode": "scheme"
            }
          }
        },
        "gridPos": { "h": 8, "w": 24, "x": 0, "y": 0 }
      },
      {
        "title": "Drawdown Actuel (%)",
        "type": "gauge",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "trading_drawdown_current_percent",
            "legendFormat": "Drawdown"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "unit": "percent",
            "min": 0,
            "max": 30,
            "thresholds": {
              "steps": [
                { "color": "green", "value": 0 },
                { "color": "yellow", "value": 5 },
                { "color": "orange", "value": 10 },
                { "color": "red", "value": 20 }
              ]
            }
          }
        },
        "gridPos": { "h": 6, "w": 8, "x": 0, "y": 8 }
      },
      {
        "title": "Positions Ouvertes",
        "type": "stat",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "sum(trading_positions_count)",
            "legendFormat": "Total"
          }
        ],
        "gridPos": { "h": 6, "w": 8, "x": 8, "y": 8 }
      }
    ]
  }
}

Provisioning automatique

Pour que Grafana charge automatiquement vos dashboards et data sources au demarrage, creez cette structure :

grafana/
  provisioning/
    datasources/
      prometheus.yml      # Connexion a Prometheus
      postgres.yml        # Connexion a PostgreSQL
    dashboards/
      provider.yml        # Ou trouver les dashboards JSON
      trading-pnl.json    # Dashboard P&L
      positions.json      # Dashboard positions
      risk.json           # Dashboard risques
      system.json         # Dashboard systeme

Le fichier provider.yml :

# grafana/provisioning/dashboards/provider.yml
apiVersion: 1
providers:
  - name: 'Trading Dashboards'
    orgId: 1
    folder: 'Trading'
    type: file
    disableDeletion: false
    editable: true
    updateIntervalSeconds: 30
    options:
      path: /etc/grafana/provisioning/dashboards
      foldersFromFilesStructure: false

Et le fichier de data source pour Prometheus :

# grafana/provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    editable: true
    jsonData:
      timeInterval: '15s'
      httpMethod: POST

Conseil pratique : commencez simple

Ne creez pas 20 dashboards le premier jour. Commencez par le P&L Tracker uniquement. Ajoutez un dashboard par semaine en fonction de vos besoins reels. Un dashboard que personne ne regarde est un dashboard inutile.

La regle d'or : si vous ne pouvez pas expliquer en une phrase pourquoi un panel existe, supprimez-le.

Variables et templates Grafana

La fonctionnalite la plus puissante de Grafana pour un trader est les variables de template. Elles permettent de creer un seul dashboard adaptatif :

# Exemples de variables utiles dans Grafana

# Variable $strategy : selectionner la strategie
# Type: Query | Source: Prometheus
# Query: label_values(trading_pnl_realized_total, strategy)
# Multi-value: Yes | Include All: Yes

# Variable $timerange : periode d'analyse
# Type: Custom
# Values: 1h, 6h, 1d, 7d, 30d, 90d

# Utilisation dans les requetes PromQL :
sum(trading_pnl_realized_total{strategy=~"$strategy"})
rate(trading_orders_total{strategy=~"$strategy"}[$timerange])

Avec les variables, un seul dashboard P&L peut afficher les resultats de toutes vos strategies ou d'une seule, sur n'importe quelle periode. Un gain de temps enorme.

Prometheus + Alertmanager : Metriques et Alertes

Prometheus est le moteur qui alimente Grafana. Cree par SoundCloud en 2012, devenu projet CNCF, c'est le standard pour la collecte de metriques dans les architectures modernes.

Son modele est simple : Prometheus scrape (interroge) vos services a intervalles reguliers. Pas besoin d'envoyer des donnees a Prometheus, c'est lui qui vient les chercher. C'est le modele "pull".

Format des metriques

Votre bot expose un endpoint HTTP (/metrics) qui retourne des metriques au format texte :

# Exemple de metriques exposees par votre bot de trading

# HELP trading_positions_count Nombre de positions ouvertes
# TYPE trading_positions_count gauge
trading_positions_count{strategy="momentum"} 5
trading_positions_count{strategy="mean_reversion"} 3

# HELP trading_pnl_realized_total P&L realise cumule en USD
# TYPE trading_pnl_realized_total counter
trading_pnl_realized_total{strategy="momentum"} 12450.50
trading_pnl_realized_total{strategy="mean_reversion"} -2300.00

# HELP trading_pnl_unrealized_total P&L non realise en USD
# TYPE trading_pnl_unrealized_total gauge
trading_pnl_unrealized_total{strategy="momentum"} 890.25
trading_pnl_unrealized_total{strategy="mean_reversion"} 450.00

# HELP trading_drawdown_current_percent Drawdown actuel en %
# TYPE trading_drawdown_current_percent gauge
trading_drawdown_current_percent 3.2

# HELP trading_order_latency_seconds Latence d'execution
# TYPE trading_order_latency_seconds histogram
trading_order_latency_seconds_bucket{le="0.05"} 80
trading_order_latency_seconds_bucket{le="0.1"} 95
trading_order_latency_seconds_bucket{le="0.5"} 148
trading_order_latency_seconds_bucket{le="1.0"} 150
trading_order_latency_seconds_bucket{le="+Inf"} 152
trading_order_latency_seconds_count 152
trading_order_latency_seconds_sum 23.45

# HELP trading_api_errors_total Erreurs API broker
# TYPE trading_api_errors_total counter
trading_api_errors_total{endpoint="submit_order"} 3
trading_api_errors_total{endpoint="get_positions"} 0

# HELP trading_exposure_usd Exposition totale en USD
# TYPE trading_exposure_usd gauge
trading_exposure_usd{direction="long"} 45000
trading_exposure_usd{direction="short"} 12000

Metriques essentielles par priorite

Priorite Metrique Type Description
P0trading_pnl_realized_totalCounterP&L realise cumule par strategie
P0trading_pnl_unrealized_totalGaugeP&L non realise (mark-to-market)
P0trading_drawdown_current_percentGaugeDrawdown actuel du portefeuille
P0trading_positions_countGaugeNombre de positions ouvertes
P1trading_exposure_usdGaugeExposition brute (long/short)
P1trading_order_latency_secondsHistogramLatence d'execution (p50, p95, p99)
P1trading_api_errors_totalCounterErreurs API par endpoint
P2trading_orders_totalCounterOrdres passes (remplis vs rejetes)
P2trading_slippage_bpsHistogramSlippage en points de base
P2trading_signal_countCounterSignaux generes par strategie

Exposer les metriques en Python

# pip install prometheus_client
# metrics.py

from prometheus_client import (
    Counter, Gauge, Histogram,
    start_http_server, CollectorRegistry
)

registry = CollectorRegistry()

# Metriques P0
pnl_realized = Counter(
    'trading_pnl_realized_total', 'P&L realise cumule',
    ['strategy'], registry=registry
)
pnl_unrealized = Gauge(
    'trading_pnl_unrealized_total', 'P&L non realise',
    ['strategy'], registry=registry
)
drawdown = Gauge(
    'trading_drawdown_current_percent', 'Drawdown actuel %',
    registry=registry
)
positions_count = Gauge(
    'trading_positions_count', 'Positions ouvertes',
    ['strategy'], registry=registry
)

# Metriques P1
exposure = Gauge(
    'trading_exposure_usd', 'Exposition USD',
    ['direction'], registry=registry
)
order_latency = Histogram(
    'trading_order_latency_seconds', 'Latence ordres',
    buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0],
    registry=registry
)
api_errors = Counter(
    'trading_api_errors_total', 'Erreurs API',
    ['endpoint'], registry=registry
)

def start_metrics_server(port=8000):
    start_http_server(port, registry=registry)
    print(f"Metriques sur http://0.0.0.0:{port}/metrics")

def on_trade(strategy, pnl, latency_s):
    pnl_realized.labels(strategy=strategy).inc(max(0, pnl))
    order_latency.observe(latency_s)

def update_positions(strategy, count, unrealized):
    positions_count.labels(strategy=strategy).set(count)
    pnl_unrealized.labels(strategy=strategy).set(unrealized)

Configuration Prometheus

# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "rules/trading_alerts.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

scrape_configs:
  - job_name: 'trading-bot'
    scrape_interval: 5s
    static_configs:
      - targets: ['trading-bot:8000']

  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

Regles d'alertes

# rules/trading_alerts.yml
groups:
  - name: trading_critical
    rules:
      - alert: DrawdownCritical
        expr: trading_drawdown_current_percent > 10
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "DRAWDOWN {{ $value | printf \"%.1f\" }}%"

      - alert: DailyLossExceeded
        expr: sum(increase(trading_pnl_realized_total[1d])) < -5000
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "PERTE JOUR > 5000 USD"

      - alert: TradingBotDown
        expr: up{job="trading-bot"} == 0
        for: 30s
        labels:
          severity: critical
        annotations:
          summary: "Bot de trading DOWN"

      - alert: TooManyPositions
        expr: sum(trading_positions_count) > 20
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "{{ $value }} positions (max 20)"

  - name: trading_operations
    rules:
      - alert: HighOrderLatency
        expr: histogram_quantile(0.99, rate(trading_order_latency_seconds_bucket[5m])) > 2
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Latence p99 > 2s"

      - alert: APIErrorRate
        expr: rate(trading_api_errors_total[5m]) > 0.1
        for: 3m
        labels:
          severity: warning
        annotations:
          summary: "Erreurs API {{ $value | printf \"%.2f\" }}/s"

Configuration Alertmanager

# alertmanager.yml
global:
  resolve_timeout: 5m

route:
  receiver: 'discord-trading'
  group_by: ['alertname', 'severity']
  group_wait: 10s
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - match:
        severity: critical
      receiver: 'discord-critical'
      group_wait: 0s
      repeat_interval: 30m

receivers:
  - name: 'discord-trading'
    webhook_configs:
      - url: 'http://discord-relay:9095/webhook/trading'
        send_resolved: true
  - name: 'discord-critical'
    webhook_configs:
      - url: 'http://discord-relay:9095/webhook/critical'
        send_resolved: true

inhibit_rules:
  - source_match:
      alertname: 'TradingBotDown'
    target_match_re:
      alertname: 'Drawdown.*|DailyLoss.*|TooMany.*'

La fatigue d'alertes tue le monitoring

Le piege numero 1 est de creer trop d'alertes. Si vous recevez 50 notifications par jour, vous les ignorerez toutes, y compris les critiques. Regle : 3 alertes max par jour en conditions normales.

Discord : Le Centre de Commande

Pourquoi Discord et pas Slack ? C'est entierement gratuit (webhooks inclus, pas de limite de messages) et la communaute trading y est massive. Slack facture 7 EUR/utilisateur/mois. Discord offre tout gratuitement.

Alertes
Notifications Prometheus/Grafana dans des channels dedies avec embeds couleur
Commandes
!status, !kill, !positions depuis votre telephone
Rapports
Resume quotidien P&L envoye chaque soir a 19h automatiquement

Architecture des channels

Trading Bot Server
├── MONITORING
│   ├── #alerts-critical    → P0 : drawdown, bot down, perte max
│   ├── #alerts-warning     → P1 : latence, erreurs API
│   └── #system-health      → Heartbeat 5 min, uptime, RAM/CPU
├── TRADES
│   ├── #executions         → Chaque trade (symbol, side, qty, prix, P&L)
│   ├── #signals            → Signaux generes avant execution
│   └── #daily-report       → Resume P&L quotidien (19h)
├── COMMANDS
│   ├── #bot-control        → !status, !positions, !kill, !pause
│   └── #analysis           → Demandes Claude Code via bot
└── LOGS
    ├── #audit-log          → Toutes actions (immutable)
    └── #errors             → Stack traces et erreurs

Webhook vs Bot Discord

Webhook = tuyau unidirectionnel. Vous envoyez un message via une URL. Parfait pour les notifications automatiques (alertes Prometheus).

Bot = programme connecte en permanence qui lit les messages et reagit aux commandes. Plus complexe mais interactif (kill-switch, status).

Recommandation : webhooks pour les alertes, bot pour les commandes interactives.

Envoyer des alertes via Webhook

# discord_alerts.py
import requests
from datetime import datetime

WEBHOOK_CRITICAL = "https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN"
WEBHOOK_TRADES = "https://discord.com/api/webhooks/YOUR_ID2/YOUR_TOKEN2"

def send_embed(webhook_url, title, description, color=0xFF0000, fields=None):
    """Envoie un embed Discord formate."""
    embed = {
        "title": title,
        "description": description,
        "color": color,
        "timestamp": datetime.utcnow().isoformat(),
        "footer": {"text": "Trading Bot Monitor"},
    }
    if fields:
        embed["fields"] = fields
    resp = requests.post(webhook_url, json={"embeds": [embed]})
    return resp.status_code == 204

def alert_drawdown(current_dd, max_dd, pos_count):
    send_embed(
        WEBHOOK_CRITICAL,
        title="DRAWDOWN CRITIQUE",
        description=f"Drawdown : **{current_dd:.1f}%** (max : {max_dd}%)",
        color=0xFF0000,
        fields=[
            {"name": "Positions", "value": str(pos_count), "inline": True},
            {"name": "Action", "value": "Reduire exposition", "inline": True},
        ]
    )

def alert_trade(symbol, side, qty, price, pnl=None):
    color = 0x00FF00 if side == "BUY" else 0xFF6600
    desc = f"**{side}** {qty} x {symbol} @ ${price:.2f}"
    if pnl is not None:
        desc += f"\nP&L: **${pnl:+.2f}**"
    send_embed(WEBHOOK_TRADES, f"Trade : {symbol}", desc, color)

def daily_report(pnl_today, pnl_total, win_rate, trades, dd):
    color = 0x00FF00 if pnl_today >= 0 else 0xFF0000
    sign = "+" if pnl_today >= 0 else ""
    send_embed(
        WEBHOOK_TRADES,
        title="Resume Quotidien",
        description=f"P&L jour : **{sign}${pnl_today:.2f}**",
        color=color,
        fields=[
            {"name": "P&L Total", "value": f"${pnl_total:.2f}", "inline": True},
            {"name": "Win Rate", "value": f"{win_rate:.1f}%", "inline": True},
            {"name": "Trades", "value": str(trades), "inline": True},
            {"name": "Drawdown", "value": f"{dd:.1f}%", "inline": True},
        ]
    )

Bot interactif avec kill-switch

# discord_bot.py
import discord
from discord.ext import commands
import asyncio

bot = commands.Bot(command_prefix='!', intents=discord.Intents.default())

@bot.command()
async def status(ctx):
    """Etat actuel du bot de trading."""
    state = get_trading_state()  # Votre fonction
    emoji = "ACTIF" if state["active"] else "ARRETE"
    embed = discord.Embed(
        title=f"Status : {emoji}",
        color=0x00FF00 if state["active"] else 0xFF0000
    )
    embed.add_field(name="Positions", value=str(state["positions"]), inline=True)
    embed.add_field(name="P&L Jour", value=f"${state['pnl']:.2f}", inline=True)
    embed.add_field(name="Drawdown", value=f"{state['dd']:.1f}%", inline=True)
    await ctx.send(embed=embed)

@bot.command()
async def positions(ctx):
    """Liste les positions ouvertes."""
    pos_list = get_open_positions()
    if not pos_list:
        await ctx.send("Aucune position ouverte.")
        return
    embed = discord.Embed(title="Positions Ouvertes", color=0x3498DB)
    for p in pos_list:
        embed.add_field(
            name=f"{p['symbol']} ({p['side']})",
            value=f"Qty: {p['qty']} | Entry: ${p['entry']:.2f} | P&L: ${p['pnl']:+.2f}",
            inline=False
        )
    await ctx.send(embed=embed)

@bot.command()
async def kill(ctx):
    """KILL SWITCH - Ferme tout et arrete le bot."""
    if not ctx.author.guild_permissions.administrator:
        await ctx.send("Acces refuse. Admin requis.")
        return
    await ctx.send("**KILL SWITCH** : Tapez `CONFIRM` dans 10 secondes.")
    try:
        await bot.wait_for(
            'message',
            check=lambda m: m.author == ctx.author and m.content == "CONFIRM",
            timeout=10.0
        )
    except asyncio.TimeoutError:
        await ctx.send("Kill switch annule (timeout).")
        return
    result = execute_kill_switch()
    await ctx.send(f"KILL SWITCH ACTIVE. {result['closed']} positions fermees.")

@bot.command()
async def pause(ctx):
    set_trading_active(False)
    await ctx.send("Bot en PAUSE.")

@bot.command()
async def resume(ctx):
    set_trading_active(True)
    await ctx.send("Bot REACTIVE.")

bot.run("YOUR_DISCORD_BOT_TOKEN")

Securite du kill-switch

Le kill-switch Discord est un dernier recours. Implementez aussi : un kill-switch local (fichier KILL), un circuit-breaker automatique (3 pertes = pause 1h), et des limites hard-codees (drawdown max, perte max).

Claude Code : L'Assistant IA pour le Monitoring

Claude Code est l'agent de codage d'Anthropic, executable dans votre terminal. Via le Model Context Protocol (MCP), il accede a vos donnees de marche, bases de donnees, metriques et fichiers en temps reel.

MCP explique simplement

Imaginez que Claude est un analyste brillant enferme dans une piece sans fenetre. MCP ouvre des fenetres :

  • MCP Market Data : prix temps reel, indicateurs techniques, sentiment
  • MCP PostgreSQL : historique de trades, positions, audit trail
  • MCP Prometheus : metriques de monitoring (P&L, latence)
  • MCP Filesystem : logs, configuration, code source

Avec MCP, Claude Code interroge toutes ces sources depuis une seule interface. C'est comme donner a votre analyste un Bloomberg Terminal + acces admin + connexion DB, le tout simultanement.

Cas d'usage concrets

1. Analyse de marche automatisee (Daily Briefing)

# Commande executee chaque matin a 7h00 par le bot Discord
claude -p "articles" "analyse daily"

# Claude Code automatiquement :
# 1. GetMarketOverview via MCP → snapshot global
# 2. QueryData pour 16 instruments (SPY, QQQ, BTC-USD...)
# 3. WebSearch pour calendrier economique et actualites
# 4. Genere un briefing HTML complet (2000+ lignes)
# 5. Publie sur le site avec add_card.js
# Temps : 10-15 min (vs 2h pour un analyste humain)

2. Scanner algorithmique quotidien

# Chaque soir a 23h
claude -p "articles" "scan du jour"

# 1. RunAutoScreener → detection regime (RiskOn/RiskOff/etc.)
# 2. RunScreener x3 avec DSL custom (oversold, momentum, breakout)
# 3. RunScreener pour EU (VGK, ASML...) et APAC (EWJ, FXI...)
# 4. QueryData → validation prix spot pour chaque candidat
# 5. WebSearch → catalyseurs recents
# 6. Generation de 10 setups A+ avec entry/stop/TP/R:R

3. Analyse d'incident

$ claude

> Le bot a perdu 3200$ sur NVDA hier a 15:32.
> Analyse les logs, metriques et contexte de marche.

# Claude Code :
# 1. Lit les logs du bot autour de 15:32 (MCP Filesystem)
# 2. Verifie les metriques Prometheus (latence, erreurs)
# 3. Regarde le prix NVDA (MCP Market Data)
# 4. Croise avec les actualites (WebSearch)
# 5. Produit un post-mortem structure

4. Generation de dashboards Grafana

$ claude

> Cree un dashboard Grafana JSON pour ma strategie mean reversion.
> Panels : P&L par ETF, trades/jour, Z-score heatmap, drawdown 30j.
> Format : JSON provisionable.

Configuration MCP

// .claude/mcp.json
{
  "mcpServers": {
    "market-data": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-market-data"],
      "description": "Donnees de marche temps reel"
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-postgres"],
      "env": { "POSTGRES_URL": "postgresql://trader:pass@localhost:5432/trading" },
      "description": "Base de donnees trading"
    },
    "prometheus": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-prometheus"],
      "env": { "PROMETHEUS_URL": "http://localhost:9090" },
      "description": "Metriques Prometheus"
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-filesystem", "/home/trader/trading-bot"],
      "description": "Acces aux fichiers du bot"
    }
  }
}

Resultats concrets chez DailyTickers

Tache Frequence Outils MCP Temps economise
Briefing DailyQuotidien 7hGetMarketOverview, QueryData, WebSearch~2h/jour
ScannerLun-Ven 23hRunAutoScreener, RunScreener, QueryData~3h/jour
Analyse TickerA la demandeGetInstruments, QueryData, ScreenOptions~4h/analyse
RetrospectiveHebdo vendrediQueryData, calculs P&L~2h/semaine

Ce qu'il ne faut PAS automatiser avec l'IA

  • Execution d'ordres : l'IA suggere, le code deterministe execute
  • Risk management : regles hard-codees, pas interpretees par un LLM
  • Kill-switch : 100% deterministe (if drawdown > X then stop)
  • Sizing : formules mathematiques (Kelly, vol targeting), pas du "feeling" IA

L'IA analyse et suggere, le code deterministe execute et protege.

Flux de donnees MCP

OpenClow : L'Orchestrateur Open Source

OpenClow est un orchestrateur de trading open source concu pour les traders retail. C'est le "systeme nerveux central" qui coordonne Grafana, Prometheus, Discord et Claude Code dans un flux coherent.

Les 4 modules

Scheduler
Planifie les strategies : cron, evenements marche (open/close), triggers custom (earnings, FOMC).
Executor
Execute les ordres via APIs broker (IBKR, Alpaca, Binance) avec retry et audit trail.
Risk Manager
Valide chaque ordre contre les limites (max position, drawdown, exposition) avant execution.
Monitor
Expose metriques Prometheus, envoie alertes Discord, genere rapports quotidiens.

Configuration

# openclow.yml
version: "1.0"

broker:
  provider: alpaca
  api_key: ${ALPACA_KEY}
  api_secret: ${ALPACA_SECRET}
  paper: true

strategies:
  momentum_etf:
    enabled: true
    module: strategies.momentum_etf
    schedule: "0 9 31 * * 1-5"
    universe: ["SPY", "QQQ", "IWM", "EFA", "EEM", "GLD", "TLT"]
    params:
      lookback_days: 20
      top_n: 3

  mean_reversion:
    enabled: true
    module: strategies.mean_reversion
    schedule: "*/5 9-16 * * 1-5"
    universe: ["AAPL", "MSFT", "GOOGL", "AMZN", "NVDA"]
    params:
      zscore_entry: 2.0
      zscore_exit: 0.5

risk:
  max_portfolio_drawdown: 10
  max_daily_loss: 5000
  max_position_size: 10
  max_positions: 15
  max_sector_exposure: 30
  circuit_breaker:
    enabled: true
    trigger: 3
    cooldown_minutes: 60

monitoring:
  prometheus:
    enabled: true
    port: 8000
  discord:
    enabled: true
    webhook_alerts: ${DISCORD_WEBHOOK_ALERTS}
    webhook_trades: ${DISCORD_WEBHOOK_TRADES}
    daily_report_time: "19:00"

Comparaison avec les alternatives

Fonctionnalite OpenClow Airflow n8n Prefect
Concu pour le tradingOuiNonNonNon
Risk management integreOui (natif)NonNonNon
Connexion broker5+ brokersNonNonNon
Kill switch autoOuiPause DAGNonNon
Prometheus natifOuiPluginNonNon
Discord natifOuiNonOuiNon
Setup < 1hOuiNonOuiOui
LicenceMITApache 2.0Fair-codeApache 2.0

Progression recommandee

  1. Semaine 1 : OpenClow en mode paper + une seule strategie simple
  2. Semaine 2 : Ajout Prometheus + Grafana pour les metriques
  3. Semaine 3 : Discord pour alertes et kill-switch
  4. Semaine 4 : Claude Code pour analyse automatisee

Chaque semaine, une couche. A la fin du mois, stack complete et maitrisee.

Docker Compose : Tout Assembler

Un seul docker compose up -d et toute la stack est operationnelle.

Le docker-compose.yml complet

# docker-compose.yml - Stack complete
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: trading-prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./prometheus/rules:/etc/prometheus/rules:ro
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=90d'
      - '--web.enable-lifecycle'
    networks:
      - trading-net
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:9090/-/healthy"]
      interval: 30s
      timeout: 5s
      retries: 3

  alertmanager:
    image: prom/alertmanager:latest
    container_name: trading-alertmanager
    restart: unless-stopped
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
      - alertmanager-data:/alertmanager
    networks:
      - trading-net
    depends_on:
      - prometheus

  grafana:
    image: grafana/grafana:latest
    container_name: trading-grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-trader}
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-changeme}
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-piechart-panel
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
    networks:
      - trading-net
    depends_on:
      - prometheus
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  node-exporter:
    image: prom/node-exporter:latest
    container_name: trading-node-exporter
    restart: unless-stopped
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
    networks:
      - trading-net

  postgres:
    image: timescale/timescaledb:latest-pg16
    container_name: trading-postgres
    restart: unless-stopped
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=trading
      - POSTGRES_USER=${PG_USER:-trader}
      - POSTGRES_PASSWORD=${PG_PASSWORD:-changeme}
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    networks:
      - trading-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U trader -d trading"]
      interval: 30s
      timeout: 5s
      retries: 3

  discord-relay:
    image: benjojo/alertmanager-discord:latest
    container_name: trading-discord-relay
    restart: unless-stopped
    ports:
      - "9095:9095"
    environment:
      - DISCORD_WEBHOOK=${DISCORD_WEBHOOK_ALERTS}
    networks:
      - trading-net
    depends_on:
      - alertmanager

  trading-bot:
    build:
      context: ./bot
      dockerfile: Dockerfile
    container_name: trading-bot
    restart: unless-stopped
    ports:
      - "8000:8000"
    environment:
      - BROKER_API_KEY=${BROKER_API_KEY}
      - BROKER_API_SECRET=${BROKER_API_SECRET}
      - BROKER_PAPER=true
      - DB_URL=postgresql://trader:changeme@postgres:5432/trading
      - DISCORD_WEBHOOK_TRADES=${DISCORD_WEBHOOK_TRADES}
    volumes:
      - ./bot/config:/app/config:ro
      - bot-logs:/app/logs
    networks:
      - trading-net
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  prometheus-data:
  alertmanager-data:
  grafana-data:
  postgres-data:
  bot-logs:

networks:
  trading-net:
    driver: bridge

Services et ressources

Service Port RAM typique Depends on
Prometheus9090~500 MBAucun
Alertmanager9093~50 MBPrometheus
Grafana3000~200 MBPrometheus
Node Exporter9100~20 MBAucun
PostgreSQL5432~300 MBAucun
Discord Relay9095~30 MBAlertmanager
Trading Bot8000~200 MBPostgreSQL

Total RAM : ~1.3 GB. Un VPS Hetzner CX22 (4 GB, 10 EUR/mois) est largement suffisant.

Le fichier .env

# .env - Secrets (JAMAIS dans git ! Ajoutez .env a .gitignore)
GRAFANA_USER=trader
GRAFANA_PASSWORD=your_strong_password
PG_USER=trader
PG_PASSWORD=your_db_password
BROKER_API_KEY=your_alpaca_key
BROKER_API_SECRET=your_alpaca_secret
DISCORD_WEBHOOK_ALERTS=https://discord.com/api/webhooks/xxx/yyy
DISCORD_WEBHOOK_TRADES=https://discord.com/api/webhooks/xxx/yyy

Commandes essentielles

# Demarrer toute la stack
docker compose up -d

# Voir les logs
docker compose logs -f
docker compose logs -f trading-bot  # un seul service

# Redemarrer un service
docker compose restart grafana

# Arreter proprement
docker compose down

# Mettre a jour
docker compose pull && docker compose up -d

# Verifier la sante
docker compose ps

Dev vs Production

# docker-compose.override.yml - Surcharges dev (charge auto)
version: '3.8'
services:
  trading-bot:
    environment:
      - BROKER_PAPER=true
      - LOG_LEVEL=DEBUG
    volumes:
      - ./bot/src:/app/src  # Hot reload
  grafana:
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=true
  prometheus:
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=7d'  # 7j en dev vs 90j en prod

Vue d'ensemble des services

Securite en production

  • Changez TOUS les mots de passe par defaut
  • N'exposez PAS Prometheus (9090) et PostgreSQL (5432) sur Internet
  • Reverse proxy HTTPS (Caddy recommande) devant Grafana
  • Firewall (ufw) : seuls ports 80, 443, SSH ouverts
  • Backups automatiques (pg_dump cron quotidien)

Checklist et Prochaines Etapes

La checklist complete pour passer de la theorie a la pratique, classee par priorite.

P0 : Critique - Semaine 1 (~4h)

#TacheOutilTemps
1Installer Docker et Docker ComposeDocker15 min
2Deployer Prometheus + Grafanadocker-compose30 min
3Exposer metriques P&L et drawdown dans le botprometheus_client1h
4Creer dashboard P&L TrackerGrafana1h
5Configurer alerte DrawdownCriticalPrometheus Rules30 min
6Creer webhook Discord + connecter AlertmanagerDiscord + AM30 min
7Tester circuit complet : metrique → alerte → DiscordTous30 min

P1 : Important - Semaine 2-3 (~8h)

#TacheOutilTemps
8Ajouter metriques latence, erreurs API, expositionprometheus_client1h
9Dashboard Positions MonitorGrafana1h
10Deployer Node Exporterdocker-compose15 min
11Dashboard System HealthGrafana1h
12Bot Discord (!status, !positions)discord.py2h
13Kill-switch Discord avec confirmationdiscord.py1h
14Rapports quotidiens automatiques (19h)Python cron1h

P2 : Nice-to-have - Semaine 4+ (~15h)

#TacheOutilTemps
15Installer Claude Code + serveurs MCPClaude Code1h
16Automatiser analyse d'incidentsClaude Code2h
17Deployer OpenClow en paper tradingOpenClow2h
18Dashboard Risk Metrics (VaR, Sharpe)Grafana2h
19Backups automatiques PostgreSQLcron + pg_dump1h
20HTTPS avec Caddy reverse proxyCaddy1h
21Firewall VPS (ufw)ufw30 min
22Metriques slippage et signal qualityprometheus_client2h
23Runbooks pour chaque type d'alerteDocumentation3h

Cout total mensuel

10 EUR
VPS
Hetzner CX22 (2 vCPU, 4 GB RAM, 40 GB SSD)
0 EUR
Licences
100% open source (Grafana, Prometheus, Discord, Docker, PostgreSQL)
20 EUR
Claude Code
Optionnel. Abonnement Claude Pro pour usage IA intensif.
~30 EUR
Total
Infrastructure de niveau institutionnel pour le prix d'un abonnement Netflix.

Retour sur la serie

Partie 1 : Post-Mortems
Les catastrophes qui ont faconne les regles du monitoring.
Partie 2 : Architecture
Les 4 couches : collecte, stockage, alerting, action.
Partie 3 : Tooling (ici)
Grafana, Prometheus, Discord, Claude Code, OpenClow, Docker.

Ressources

RessourceTypeURL
Grafana DocsOfficielgrafana.com/docs
Prometheus DocsOfficielprometheus.io/docs
PromQL Cheat SheetReferencepromlabs.com/promql-cheat-sheet
Discord DeveloperAPIdiscord.com/developers/docs
Claude CodeAnthropicdocs.anthropic.com/claude-code
MCP SpecProtocolemodelcontextprotocol.io
Docker ComposeReferencedocs.docker.com/compose

Les 3 takeaways de cette serie

1. Le monitoring n'est pas optionnel. Chaque dollar investi en monitoring sauve potentiellement des milliers en pertes evitables. Les post-mortems de la Partie 1 le prouvent.

2. L'architecture avant les outils. Comprenez les 4 couches de la Partie 2 avant de choisir vos outils. Un bon design avec des outils moyens bat toujours des outils excellents sans design.

3. Commencez simple, iterez vite. Prometheus + Grafana + webhook Discord suffisent pour demarrer. Ajoutez de la complexite uniquement quand c'est necessaire.

Pret a commencer ?

Copiez le docker-compose.yml, creez votre .env, lancez docker compose up -d. Stack operationnelle en moins d'une heure. Le plus dur n'est pas la technique, c'est de faire le premier pas.

Bon trading, et surtout, bon monitoring.

Serie : Monitorer sa Stack de Trading

1 Post-Mortems 2 Architecture 3 Tooling
Monitoring Trading Stack
3/3
Introduction Grafana Prometheus Discord Claude Code OpenClow Docker Compose Checklist