Série Construire un MCP Server Finance — Partie 6 sur 6

Intégrations Avancées : Multi-Source, Backtest, Portfolio

La dernière étape : agrégation multi-source avec fallback automatique, backtesting de stratégies, gestion de portefeuille, forecasting ML, et l'architecture complète d'un MCP server finance de production.

Multi-source Backtest engine Portfolio manager ML forecasting
Construire un MCP Server Finance6/6
Multi-sourceBacktestPortfolioForecasting MLArchitecture finaleConclusion

Agrégation multi-source avec fallback

Un serveur de production ne peut pas dépendre d'un seul provider. Yahoo Finance peut être rate-limité, Binance peut être down, et SEC EDGAR peut être lent un jour de filing massif. La solution : une chaîne de providers avec fallback automatique.

# providers/aggregator.py — Fallback chain
class AggregatedProvider:
    def __init__(self, providers: list[MarketDataProvider]):
        self.providers = providers  # Ordonnés par priorité

    async def get_quote(self, ticker: str) -> dict:
        errors = []
        for provider in self.providers:
            try:
                result = await provider.get_quote(ticker)
                result["source"] = provider.name
                return result
            except Exception as e:
                errors.append(f"{provider.name}: {e}")
                logger.warning(f"Provider {provider.name} failed for {ticker}: {e}")
                continue

        # Tous les providers ont échoué
        raise AllProvidersFailedError(ticker, errors)

# Initialisation
aggregator = AggregatedProvider([
    YahooProvider(),        # Priorité 1 : gratuit, large couverture
    PolygonProvider(),      # Priorité 2 : payant, plus fiable
    AlphaVantageProvider(), # Priorité 3 : fallback
])

Smart routing par asset class

Mieux que le fallback linéaire : router vers le bon provider selon l'asset class :

Asset classProvider primaireFallbackDétection
Actions USYahoo FinancePolygonTicker 1-5 lettres majuscules
ETFsYahoo FinanceIEXListe ETF connue (SPY, QQQ...)
CryptoBinanceCoinGeckoSuffixe -USD ou paire connue
ForexYahoo (EURUSD=X)OANDAPattern XXX/YYY ou =X
IndicesYahoo (^GSPC)—Préfixe ^
CommoditiesYahoo (GC=F)FREDSuffixe =F
# Smart routing
def get_provider_chain(ticker: str) -> list[MarketDataProvider]:
    if ticker.endswith("-USD") or ticker in KNOWN_CRYPTO:
        return [binance_provider, coingecko_provider]
    if ticker.startswith("^"):
        return [yahoo_provider]
    if ticker.endswith("=X"):
        return [yahoo_provider, oanda_provider]
    # Default: actions US
    return [yahoo_provider, polygon_provider, alphavantage_provider]

Binance directement, pas via Yahoo

Pour la crypto, utilisez l'API Binance directement. Yahoo Finance ajoute un délai de 15-60 minutes sur les prix crypto, ce qui est inacceptable pour un marché 24/7. L'API publique Binance est gratuite, rapide (~50ms), et ne nécessite pas de clé API pour les données de marché.

Section 2

Outil de backtesting

Un outil de backtest via MCP permet au LLM de valider une hypothèse de trading en la testant sur données historiques. L'outil prend une stratégie en entrée et retourne des métriques de performance :

BACKTEST_TOOL = Tool(
    name="RunBacktest",
    description="""Backtest a trading strategy on historical data.
Takes entry/exit conditions and returns performance metrics.

Metrics returned: total_return_pct, max_drawdown_pct, sharpe_ratio,
win_rate_pct, profit_factor, avg_trade_pct, total_trades, best/worst_trade.

Example strategy:
  entry: 'rsi_14 < 30 AND ema_20_slope > 0'
  exit: 'rsi_14 > 70 OR trailing_stop_pct(-3)'
  period: '2y'
  universe: ['AAPL', 'MSFT', 'GOOGL']""",
    inputSchema={
        "type": "object",
        "properties": {
            "entry_condition": {"type": "string"},
            "exit_condition": {"type": "string"},
            "period": {"type": "string", "enum": ["6m","1y","2y","5y"]},
            "universe": {"type": "array", "items": {"type": "string"}},
            "position_size_pct": {"type": "number", "default": 10}
        },
        "required": ["entry_condition", "exit_condition", "period"]
    }
)

Le résultat donne au LLM tout ce qu'il faut pour évaluer la stratégie :

# Résultat du backtest
{
    "period": "2024-01-01 to 2025-12-31",
    "total_return_pct": 34.2,
    "annualized_return_pct": 16.1,
    "max_drawdown_pct": -8.7,
    "sharpe_ratio": 1.42,
    "sortino_ratio": 1.89,
    "win_rate_pct": 62.5,
    "profit_factor": 2.1,
    "total_trades": 48,
    "avg_trade_pct": 2.8,
    "avg_hold_days": 12,
    "best_trade": {"ticker": "NVDA", "return_pct": 18.4},
    "worst_trade": {"ticker": "INTC", "return_pct": -6.2},
    "benchmark_return_pct": 28.1,  # SPY sur la même période
    "alpha_pct": 6.1
}

Backtesting honnête

Le backtest doit toujours inclure le benchmark (SPY) sur la même période. Un rendement de +34% semble excellent, mais si SPY a fait +28%, l'alpha réel n'est que de 6 points. Sans benchmark, le LLM (et l'utilisateur) peuvent surestimer la stratégie. Voir notre article Backtesting Honnête pour les pièges classiques.

Section 3

Gestion de portefeuille

Un MCP finance avancé peut exposer des outils de gestion de portefeuille : optimisation de sizing, calcul de VaR, et suivi des positions :

OptimizeSizing

Taille optimale de chaque position selon corrélation, volatilité, et contraintes de risque.

CalculateVaR

Value at Risk : perte maximale à 95% de confiance sur 1j/5j/1m. Monte Carlo ou historique.

GetCorrelationMatrix

Corrélation entre N tickers pour détecter les clusters de risque dans le portefeuille.

StressTest

Simuler l'impact de scénarios (VIX à 40, -10% S&P, taux +100bps) sur le portefeuille.

# Outil OptimizeSizing
OPTIMIZE_SIZING_TOOL = Tool(
    name="OptimizeSizing",
    description="""Optimize position sizes for a portfolio of tickers.
Uses correlation matrix, ATR-based volatility, and regime to suggest
optimal allocation percentages that maximize diversification while
respecting risk constraints.

Constraints: max_per_position (default 15%), max_correlation (default 0.7),
max_sector_exposure (default 30%).""",
    inputSchema={
        "type": "object",
        "properties": {
            "tickers": {"type": "array", "items": {"type": "string"}},
            "portfolio_size": {"type": "number"},
            "constraints": {
                "type": "object",
                "properties": {
                    "max_per_position_pct": {"type": "number", "default": 15},
                    "max_correlation": {"type": "number", "default": 0.7},
                    "max_sector_exposure_pct": {"type": "number", "default": 30}
                }
            }
        },
        "required": ["tickers", "portfolio_size"]
    }
)
Section 4

Intégration forecasting ML

Un MCP server peut intégrer des modèles de machine learning comme TimesFM (Google) pour le forecasting de séries temporelles. Le LLM n'exécute pas le ML — il appelle un outil qui exécute le modèle et retourne les prédictions :

FORECAST_TOOL = Tool(
    name="ForecastPrice",
    description="""Forecast future price using TimesFM 2.0 (time-series foundation model).
Returns probabilistic forecast with confidence intervals.

IMPORTANT: Direction accuracy is ~44% (worse than random) for individual stocks.
Use confidence intervals as 'probabilistic support/resistance zones', not as
directional signals. ATR/volatility forecasts are more reliable (~70% accuracy).

Output includes: point forecast, q10/q50/q90, predicted_direction, historical_accuracy.""",
    inputSchema={
        "type": "object",
        "properties": {
            "ticker": {"type": "string"},
            "horizon": {"type": "integer", "description": "Days ahead (1-30)", "default": 5},
            "metric": {"type": "string", "enum": ["close", "atr", "volume"], "default": "close"}
        },
        "required": ["ticker"]
    }
)

Honnêteté dans la description

La description de l'outil dit explicitement que la direction est à 44%. C'est volontaire. Si le LLM croit que le forecast est fiable, il va recommander des trades basés sur les prédictions. En étant honnête dans la description, le LLM utilisera les forecasts comme zones probabilistes, pas comme des signaux directionnels. C'est la différence entre un outil utile et un outil dangereux.

MCP comme passerelle vers le ML

Le serveur MCP n'exécute pas le modèle ML directement — il appelle un service de forecast via HTTP (dans notre cas, un serveur TimesFM sur un GPU séparé). MCP sert de passerelle : le LLM appelle l'outil, le serveur MCP appelle le service ML, et retourne le résultat formaté. Le LLM n'a pas besoin de savoir qu'il y a un modèle Google derrière — il voit juste un outil ForecastPrice.

Section 5

Architecture finale complète

En assemblant tout ce qu'on a construit dans les 6 parties, voici l'architecture d'un MCP server finance de production :

CoucheComposantsPartie
TransportCaddy (TLS) → FastAPI (SSE + POST)2, 5
SécuritéBearer auth → Rate limiter (client + upstream)4
CacheTTL cache en mémoire (15s → 24h par type)4
MCP CoreServer + tool registry + dispatch + error handling2
OutilsQueryData, RunScreener, GetMarketOverview, RunBacktest, OptimizeSizing, ForecastPrice3, 6
ProvidersYahoo, Binance, SEC, FRED — avec fallback chain3, 6
ServicesTimesFM (forecast), portfolio engine6
InfraDocker, Nomad, healthcheck, JSON logs5

Ce que le serveur peut faire maintenant

Avec l'architecture complète, un LLM connecté au serveur peut :

Quiz : Combien d'outils MCP minimum pour un serveur finance utile ?
Trois : GetQuote (prix), QueryData (analyse détaillée), et GetMarketOverview (contexte). Avec ces trois outils, le LLM peut répondre à 80% des questions finance courantes. Les outils avancés (screener, backtest, portfolio) ajoutent de la profondeur mais ne sont pas nécessaires pour commencer.
Conclusion

Ce qu'on a construit

En 6 parties, on a construit un serveur MCP finance complet — du concept à la production. Récapitulatif :

1

Concept

MCP, architecture Host-Client-Server, les 3 primitives, pourquoi pour la finance.

2

Squelette

FastAPI + mcp-python-sdk, premier outil en 200 lignes, transport SSE.

3

Outils

QueryData, RunScreener, GetMarketOverview. Providers interchangeables, calculs techniques.

4

Sécurité

Bearer tokens, rate limiting token bucket, cache TTL par type de donnée.

5

Déploiement

Docker multi-stage, Nomad, Caddy TLS, logs JSON, checklist production.

6

Avancé

Multi-source fallback, backtest, portfolio, forecasting ML.

Le résultat
Un LLM qui voit les marchés en temps réel, analyse sur commande, et ne ment jamais

Pour aller plus loin

Les principes à retenir

  • Déclaratif, pas impératif — décrivez vos outils, le LLM décide quand les utiliser
  • Transparence absolue — source, timestamp, cache status dans chaque réponse
  • Fail loud, never lie — erreur = dire l'erreur, jamais inventer de données
  • Cache intelligent — TTL adapté par type, pas un TTL unique pour tout
  • Honnêteté dans les descriptions — si le forecast est à 44%, le dire (pas le cacher)
  • Provider agnostic — abstraire les sources, fallback automatique
Relire depuis le début