La boite a outils complete du trader retail pour monitorer, alerter et orchestrer sa stack de trading systematique.
Serie : Monitorer sa Stack de Trading
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.
Revenons un instant sur les lecons de la Partie 1 :
!kill aurait pu couper les pertes.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.
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 |
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.
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 |
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.
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.
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.
Apres des mois d'iteration, nous avons identifie les 4 dashboards qui couvrent 95% des besoins d'un trader systematique :
| 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 |
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 }
}
]
}
}
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
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.
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 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".
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
| Priorite | Metrique | Type | Description |
|---|---|---|---|
| P0 | trading_pnl_realized_total | Counter | P&L realise cumule par strategie |
| P0 | trading_pnl_unrealized_total | Gauge | P&L non realise (mark-to-market) |
| P0 | trading_drawdown_current_percent | Gauge | Drawdown actuel du portefeuille |
| P0 | trading_positions_count | Gauge | Nombre de positions ouvertes |
| P1 | trading_exposure_usd | Gauge | Exposition brute (long/short) |
| P1 | trading_order_latency_seconds | Histogram | Latence d'execution (p50, p95, p99) |
| P1 | trading_api_errors_total | Counter | Erreurs API par endpoint |
| P2 | trading_orders_total | Counter | Ordres passes (remplis vs rejetes) |
| P2 | trading_slippage_bps | Histogram | Slippage en points de base |
| P2 | trading_signal_count | Counter | Signaux generes par strategie |
# 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)
# 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']
# 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"
# 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.*'
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.
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.
!status, !kill, !positions depuis votre telephoneTrading 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 = 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.
# 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},
]
)
# 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")
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 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.
Imaginez que Claude est un analyste brillant enferme dans une piece sans fenetre. MCP ouvre des fenetres :
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.
# 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)
# 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
$ 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
$ 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.
// .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"
}
}
}
| Tache | Frequence | Outils MCP | Temps economise |
|---|---|---|---|
| Briefing Daily | Quotidien 7h | GetMarketOverview, QueryData, WebSearch | ~2h/jour |
| Scanner | Lun-Ven 23h | RunAutoScreener, RunScreener, QueryData | ~3h/jour |
| Analyse Ticker | A la demande | GetInstruments, QueryData, ScreenOptions | ~4h/analyse |
| Retrospective | Hebdo vendredi | QueryData, calculs P&L | ~2h/semaine |
L'IA analyse et suggere, le code deterministe execute et protege.
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.
# 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"
| Fonctionnalite | OpenClow | Airflow | n8n | Prefect |
|---|---|---|---|---|
| Concu pour le trading | Oui | Non | Non | Non |
| Risk management integre | Oui (natif) | Non | Non | Non |
| Connexion broker | 5+ brokers | Non | Non | Non |
| Kill switch auto | Oui | Pause DAG | Non | Non |
| Prometheus natif | Oui | Plugin | Non | Non |
| Discord natif | Oui | Non | Oui | Non |
| Setup < 1h | Oui | Non | Oui | Oui |
| Licence | MIT | Apache 2.0 | Fair-code | Apache 2.0 |
Chaque semaine, une couche. A la fin du mois, stack complete et maitrisee.
Un seul docker compose up -d et toute la stack est operationnelle.
# 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
| Service | Port | RAM typique | Depends on |
|---|---|---|---|
| Prometheus | 9090 | ~500 MB | Aucun |
| Alertmanager | 9093 | ~50 MB | Prometheus |
| Grafana | 3000 | ~200 MB | Prometheus |
| Node Exporter | 9100 | ~20 MB | Aucun |
| PostgreSQL | 5432 | ~300 MB | Aucun |
| Discord Relay | 9095 | ~30 MB | Alertmanager |
| Trading Bot | 8000 | ~200 MB | PostgreSQL |
Total RAM : ~1.3 GB. Un VPS Hetzner CX22 (4 GB, 10 EUR/mois) est largement suffisant.
# .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
# 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
# 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
La checklist complete pour passer de la theorie a la pratique, classee par priorite.
| # | Tache | Outil | Temps |
|---|---|---|---|
| 1 | Installer Docker et Docker Compose | Docker | 15 min |
| 2 | Deployer Prometheus + Grafana | docker-compose | 30 min |
| 3 | Exposer metriques P&L et drawdown dans le bot | prometheus_client | 1h |
| 4 | Creer dashboard P&L Tracker | Grafana | 1h |
| 5 | Configurer alerte DrawdownCritical | Prometheus Rules | 30 min |
| 6 | Creer webhook Discord + connecter Alertmanager | Discord + AM | 30 min |
| 7 | Tester circuit complet : metrique → alerte → Discord | Tous | 30 min |
| # | Tache | Outil | Temps |
|---|---|---|---|
| 8 | Ajouter metriques latence, erreurs API, exposition | prometheus_client | 1h |
| 9 | Dashboard Positions Monitor | Grafana | 1h |
| 10 | Deployer Node Exporter | docker-compose | 15 min |
| 11 | Dashboard System Health | Grafana | 1h |
| 12 | Bot Discord (!status, !positions) | discord.py | 2h |
| 13 | Kill-switch Discord avec confirmation | discord.py | 1h |
| 14 | Rapports quotidiens automatiques (19h) | Python cron | 1h |
| # | Tache | Outil | Temps |
|---|---|---|---|
| 15 | Installer Claude Code + serveurs MCP | Claude Code | 1h |
| 16 | Automatiser analyse d'incidents | Claude Code | 2h |
| 17 | Deployer OpenClow en paper trading | OpenClow | 2h |
| 18 | Dashboard Risk Metrics (VaR, Sharpe) | Grafana | 2h |
| 19 | Backups automatiques PostgreSQL | cron + pg_dump | 1h |
| 20 | HTTPS avec Caddy reverse proxy | Caddy | 1h |
| 21 | Firewall VPS (ufw) | ufw | 30 min |
| 22 | Metriques slippage et signal quality | prometheus_client | 2h |
| 23 | Runbooks pour chaque type d'alerte | Documentation | 3h |
| Ressource | Type | URL |
|---|---|---|
| Grafana Docs | Officiel | grafana.com/docs |
| Prometheus Docs | Officiel | prometheus.io/docs |
| PromQL Cheat Sheet | Reference | promlabs.com/promql-cheat-sheet |
| Discord Developer | API | discord.com/developers/docs |
| Claude Code | Anthropic | docs.anthropic.com/claude-code |
| MCP Spec | Protocole | modelcontextprotocol.io |
| Docker Compose | Reference | docs.docker.com/compose |
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.
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