Build a Two-Agent FX Stack: Research Agent + Execution Gatekeeper banner image

Implementation

How-To Guides

Build a Two-Agent FX Stack: Research Agent + Execution Gatekeeper

Design a safer AI FX workflow by splitting analysis from execution approval: one agent researches macro setups, a second gatekeeper enforces risk rules and blocks unsafe trades before they reach your broker.

Également disponible en English

Construire une pile de deux agents: agent de recherche + gardien d'exécution

Auteur: Équipe FXMacroData
Publié: 21 mai 2026

Les robots FX à un seul agent échouent pour une raison simple: le même modèle qui génère des idées est également autorisé à les approuver. Les effectifs non agricoles des États-Unis, une erreur de raisonnement peut se transformer en risque de position.

Ce guide montre une architecture plus sûre: responsabilités divisées entre deux agents. Le premier agent effectue des études de marché et propose des configurations. Le deuxième agent est un gardien de porte strict qui ne peut approuver, redimensionner ou rejeter des propositions basées sur des règles de risque dur.

À la fin, vous aurez un flux de travail pratique pour deux agents. Le taux de change Je suis désolé . Le taux de change qui prend en charge à la fois l'intégration directe des API REST et l'integration des outils basés sur MCP.

Objectif: Passer de "idées de commerce d'IA" à "candidats à des échanges d'AI validés par le risque" en imposant une couche d'approbation obligatoire avant toute action de courtage.

Pré-requis

  • Python 3.10 ou plus.
  • Une clé d'API FXMacroData de Gestion des APIJe suis désolé .
  • Un point final de LLM pour les agents de recherche et de garde-porte.
  • Familiarité de base avec les API JSON et HTTP.

Installer des dépendances:

pip install requests python-dotenv pydantic

Créez un .env fichier:

FXMD_API_KEY=your_fxmacrodata_key
RESEARCH_MODEL=claude-or-hermes
GATEKEEPER_MODEL=claude-or-hermes
MAX_RISK_PCT=0.50

Étape 1: définir des rôles stricts pour les deux agents

Ce qu' il faut faire: Fermez les responsabilités avant d'écrire du code.

  • Agent de recherche: lit le contexte macro + marché et propose des candidatures.
  • L'agent gardien de porte: valide uniquement les contraintes. Il ne peut pas inventer de nouveaux métiers, seulement approuver/rejeter/réduire la taille.

Pourquoi cela compte: Cette séparation empêche un modèle unique de contourner les contrôles des risques lorsque la confiance est élevée mais que les preuves sont faibles.


Étape 2: extraire le contexte structuré avec des appels REST directs

Ce qu' il faut faire: Les données de recherche sont fournies par FXMacroData afin que l'agent de recherche obtienne des données propres au lieu de titres non structurés.

curl "https://fxmacrodata.com/api/v1/calendar/usd?api_key=YOUR_API_KEY"
curl "https://fxmacrodata.com/api/v1/announcements/eur/inflation?api_key=YOUR_API_KEY"
curl "https://fxmacrodata.com/api/v1/announcements/gbp/unemployment?api_key=YOUR_API_KEY"
curl "https://fxmacrodata.com/api/v1/forex?base=EUR&quote=USD&api_key=YOUR_API_KEY"

Pourquoi cela compte: Les champs structurés et cohérents donnent aux deux agents la même source de vérité et rendent la validation déterministe.

Le collecteur Python minimum:

import os
import requests
from datetime import datetime, timezone

API = "https://fxmacrodata.com/api/v1"
KEY = os.environ["FXMD_API_KEY"]


def fxmd_get(path, **params):
    r = requests.get(
        f"{API}{path}",
        params={"api_key": KEY, **params},
        timeout=25,
    )
    r.raise_for_status()
    return r.json()


def build_market_context():
    return {
        "asof_utc": datetime.now(timezone.utc).isoformat(),
        "calendar_usd": fxmd_get("/calendar/usd").get("data", [])[:8],
        "calendar_eur": fxmd_get("/calendar/eur").get("data", [])[:8],
        "eur_inflation": fxmd_get("/announcements/eur/inflation").get("data", [])[-1:],
        "gbp_unemployment": fxmd_get("/announcements/gbp/unemployment").get("data", [])[-1:],
        "eurusd": fxmd_get("/forex", base="EUR", quote="USD").get("data", [])[-48:],
        "gbpusd": fxmd_get("/forex", base="GBP", quote="USD").get("data", [])[-48:],
    }

Étape 3: Générer des candidats au métier avec l'agent de recherche

Ce qu' il faut faire: Demandez à l'agent de recherche uniquement pour les candidats de métiers structurés.

{
  "pair": "EUR/USD",
  "bias": "long|short|flat",
  "thesis": "string",
  "confidence": 0.0,
  "entry_zone": "string",
  "invalidation": "string",
  "event_risks": ["string"]
}

Pourquoi cela compte: Un schéma fixe permet au gardien de passerelle d'appliquer des règles sur des champs prévisibles au lieu d'essayer d'analyser du texte libre.

Un conseil: inclure le contexte de la banque centrale à partir de Réserve fédérale Je suis désolé . La BCE La communication dans l'invite de recherche, mais garder la sortie finale compacte.

Étape 4: appliquer les règles de risque dur dans l'agent gardien

Ce qu' il faut faire: faire passer chaque candidat à travers un deuxième modèle ou un validateur de règles avec des limites strictes.

Exemple de politique:

  • Le risque maximal par transaction est de 0,50% du capital.
  • Aucune nouvelle transaction dans les 15 minutes suivant la sortie de la calendrier de sortieJe suis désolé .
  • Niveau d'invalidation obligatoire
  • Rejeter si la confiance est inférieure à 0,60.

Porte pydactique et sortie de décision:

from pydantic import BaseModel, Field


class Candidate(BaseModel):
    pair: str
    bias: str
    thesis: str
    confidence: float = Field(ge=0.0, le=1.0)
    entry_zone: str
    invalidation: str
    event_risks: list[str]


class GateDecision(BaseModel):
    status: str  # approve, resize, reject
    approved_size_pct: float
    reason: str


def gate(candidate: Candidate, max_risk_pct: float = 0.50) -> GateDecision:
    if candidate.confidence < 0.60:
        return GateDecision(status="reject", approved_size_pct=0.0, reason="Low confidence")
    if not candidate.invalidation.strip():
        return GateDecision(status="reject", approved_size_pct=0.0, reason="Missing invalidation")
    proposed = 0.50 if candidate.confidence >= 0.75 else 0.30
    size = min(proposed, max_risk_pct)
    return GateDecision(status="approve", approved_size_pct=size, reason="Within policy")

Pourquoi cela compte: Même si l'agent de recherche a une mauvaise lecture, le gardien peut toujours bloquer les configurations trop grandes ou faibles.


Étape 5: Ajouter le chemin d'intégration MCP (flux de travail des agents natifs de l'outil)

Ce qu' il faut faire: exposer FXMacroData via MCP afin que les frameworks d'agents puissent appeler des outils nativement au lieu de créer une colle REST personnalisée pour chaque bot.

Démarrez un serveur MCP basé sur Python via uvxLe texte est le suivant:

uvx fxmacrodata-mcp --transport http --server-url https://fxmacrodata.com/mcp

Exemple de configuration du client:

{
  "mcpServers": {
    "fxmacrodata": {
      "command": "uvx",
      "args": [
        "fxmacrodata-mcp",
        "--transport",
        "http",
        "--server-url",
        "https://fxmacrodata.com/mcp"
      ]
    }
  }
}

Exemple de schéma d'appel d'outils MCP pour votre agent de recherche:

{
  "name": "get_fx_calendar_and_spot",
  "description": "Get upcoming macro events and current spot context for selected pairs",
  "input_schema": {
    "type": "object",
    "properties": {
      "currencies": {
        "type": "array",
        "items": { "type": "string" }
      },
      "pairs": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "base": { "type": "string" },
            "quote": { "type": "string" }
          },
          "required": ["base", "quote"]
        }
      }
    },
    "required": ["currencies", "pairs"]
  }
}

Exemple d'invocation d'agent (chemin MCP):

Research Agent:
"Using the fxmacrodata MCP tools, pull today's USD/EUR/GBP calendar and spot for EUR/USD and GBP/USD.
Return up to 3 candidate setups in strict JSON schema."

Gatekeeper Agent:
"Validate each candidate against risk policy v1. Reject anything violating confidence,
size, invalidation, or event-window constraints. Return approve/resize/reject with reason."

Pourquoi cela compte: MCP réduit la dérive d'intégration à mesure que votre pile grandit, en particulier lorsque vous exécutez plusieurs agents ou fournisseurs de modèles d'échange.


Étape 6: Envoyer les sorties à l'examen humain, puis à l"API du courtier

Ce qu' il faut faire: Envoyez les transactions approuvées aux systèmes d'exécution après confirmation humaine dans les premières versions.

Pourquoi cela compte: Cela crée une boucle auditable et vous protège lors de changements de mode ou de modèle.

[FX Two-Agent Candidate]
Pair: EUR/USD
Research Bias: Long
Gatekeeper: Approve
Approved Size: 0.30%
Reason: Confidence 0.71, invalidation present, no high-impact event in 15m window.

Ce que vous avez construit

Vous avez maintenant une architecture FX à deux agents qui sépare la génération d'idées de l'approbation des risques, prend en charge l'intégration directe REST et prend également en charge la mise en œuvre d'outils basés sur MCP via uvxIl s'agit d'une base plus solide que les robots à agent unique, car les candidats au commerce doivent survivre à une porte de politique indépendante avant l'exécution.

Suivant: ajouter une couche de commutateur qui force automatiquement . reject Vous pouvez également ajouter des contraintes de session à partir de Sessions de change et le contexte de positionnement de Le COTJe suis désolé .

Blogroll