Live release feed
Sub-second macro releases for FX backtests
Point-in-time history
USD 25/month
Start Free Trial

Reference

Macro Education

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.

Share article X LinkedIn Email
AI macro research workflow illustration for Build a Two-Agent FX Stack: Research Agent + Execution Gatekeeper

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

Author: FXMacroData Team
Published: May 21, 2026

Single-agent FX bots fail for a simple reason: the same model that generates ideas is also allowed to approve them. When volatility spikes around events like US Non-Farm Payrolls, one reasoning error can jump straight into position risk.

This guide shows a safer architecture: split responsibilities between two agents. The first agent does market research and proposes setups. The second agent is a strict gatekeeper that can only approve, resize, or reject proposals based on hard risk rules.

By the end, you will have a practical two-agent workflow for EUR/USD and GBP/USD that supports both direct REST API integration and MCP-based tool integration.

Goal: Move from "AI trade ideas" to "risk-validated AI trade candidates" by enforcing a mandatory approval layer before any broker action.

Prerequisites

  • Python 3.10+.
  • An FXMacroData API key from API Management.
  • An LLM endpoint for the research and gatekeeper agents.
  • Basic familiarity with JSON and HTTP APIs.

Install dependencies:

pip install requests python-dotenv pydantic

Create a .env file:

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

Step 1: Define strict roles for both agents

What to do: lock responsibilities before writing code.

  • Research agent: reads macro + market context and proposes candidate setups.
  • Gatekeeper agent: validates constraints only. It cannot invent new trades, only approve/reject/resize.

Why it matters: this separation prevents a single model from bypassing risk controls when confidence is high but evidence is weak.


Step 2: Pull structured context with direct REST calls

What to do: fetch releases and spot data from FXMacroData so the research agent gets clean inputs instead of unstructured headlines.

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

Why it matters: consistent, structured fields give both agents the same source of truth and make validation deterministic.

Minimal Python collector:

import os
import requests
from datetime import datetime, timezone

API = "https://api.fxmacrodata.com/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:],
    }

Step 3: Generate trade candidates with the research agent

What to do: ask the research agent for structured trade candidates only. Do not let it send execution-ready instructions.

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

Why it matters: a fixed schema lets the gatekeeper enforce rules on predictable fields instead of trying to parse free-form text.

Tip: include central-bank context from Federal Reserve and ECB communication in the research prompt, but keep the final output compact.

Step 4: Enforce hard risk rules in the gatekeeper agent

What to do: run every candidate through a second model or rule-first validator with strict limits.

Example policy:

  • Maximum risk per trade: 0.50% of equity.
  • No new trades inside 15 minutes of high-impact releases from the release calendar.
  • Mandatory invalidation level.
  • Reject if confidence < 0.60.

Pydantic gate and decision output:

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")

Why it matters: even if the research agent has a bad read, the gatekeeper can still block oversized or weak setups.


Step 5: Add MCP integration path (tool-native agent workflow)

What to do: expose FXMacroData through MCP so agent frameworks can call tools natively instead of building custom REST glue for each bot.

Start a Python-based MCP server via uvx:

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

Client config example:

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

Example MCP tool-call schema for your research agent:

{
  "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"]
  }
}

Agent invocation example (MCP path):

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."

Why it matters: MCP reduces integration drift as your stack grows, especially when you run multiple agents or swap model providers.


Step 6: Route outputs to human review, then broker API

What to do: send the gatekeeper decision to Slack/Telegram first. Only send approved trades to execution systems after human confirmation in early versions.

Why it matters: this creates an auditable loop and protects you during prompt or model changes.

[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.

What you built

You now have a two-agent FX architecture that separates idea generation from risk approval, supports direct REST integration, and also supports MCP-based tool orchestration through uvx. This is a stronger foundation than single-agent bots because trade candidates must survive an independent policy gate before execution.

Next step: add a kill-switch layer that automatically forces reject after unusual latency, missing data fields, or repeated schema failures during high-volatility sessions. You can also add session-aware constraints from FX sessions and positioning context from COT.

Blogroll

AI Answer-Ready

Key Facts

Page
Build A Two Agent FX Stack Research And Execution Gatekeeper
Section
Articles
Canonical URL
https://fxmacrodata.com/articles/build-a-two-agent-fx-stack-research-and-execution-gatekeeper
Source
FXMacroData editorial and official publisher references
Last Updated
2026-07-09 07:07 UTC

Provenance And Trust

Cite the canonical URL and source field above. Where available, this page maps to official publisher releases and timestamped updates.

Quick Q&A

What is the main point of 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.

How can traders use this with FXMacroData? Use the article context alongside FXMacroData dashboards, indicator docs, release calendars, and API endpoints to structure macro research and event-risk workflows.

Can an AI assistant use this topic? Yes. FXMacroData exposes ChatGPT, MCP, OpenAPI, llms.txt, and API documentation surfaces so AI assistants can retrieve the relevant macro data and cite canonical pages.

Prompt Packs

Use these in ChatGPT, Claude, Gemini, Mistral, Perplexity, or Grok for consistent source-aware outputs.