DSPy is useful for FX research workflows when you want to program and measure an AI pipeline instead of hand-tuning one long prompt. FXMacroData supplies the current market evidence: confirmed release calendars, announcement history, EUR/USD context, COT positioning, commodities, and FX session data.
https://mcp.fxmacrodata.com, then optimize only after your metric rewards evidence, source paths, and data-gap disclosure.
The key boundary is simple. DSPy should organize the language-model program: signatures, modules, tools, evaluation, and optimizers. FXMacroData should answer the market-data questions: what printed, when it printed, what the prior value was, which rows are scheduled next, and which dashboard a human can inspect. That matters for US CPI, Non-Farm Payrolls, a Federal Reserve policy rate decision, or a USD/JPY release-risk note.
Fit
Use this for
Measured macro briefings, evidence-first ReAct agents, model comparison, prompt optimization, and repeatable research workflows.
Do not start with
Autonomous trading, write-capable execution tools, stale vector-only facts, or optimizers that reward confident prose without checked data.
Best first build
A USD release briefing program that calls FXMacroData, returns evidence and gaps, and is scored by a simple desk-review metric.
Why DSPy Fits FX Macro Agents
DSPy is built around reusable primitives. Signatures declare typed inputs and outputs. Modules decide how a signature runs. ReAct adds a tool-using loop. Optimizers compile a program against examples and a metric. That maps well to finance because a macro workflow is not just a prompt; it is a sequence of data retrieval, interpretation, scoring, and review.
For FX, the useful question is not "can the model write a convincing note?" The useful question is "can the program consistently fetch current macro evidence, cite the source paths, disclose missing data, and produce the kind of briefing a human analyst can review?" DSPy gives you a way to measure that behavior.
DSPy macro-agent workflow
1. Declare
A DSPy signature defines the question, evidence, answer, sources, and gaps.
2. Fetch
FXMacroData tools retrieve dated rows, endpoint paths, and missing-data signals.
3. Score
A metric rewards grounded, sourced, reviewable answers rather than fluent guesses.
4. Improve
DSPy optimizers tune the program against the metric and training examples.
Takeaway: DSPy controls the program and optimization loop; FXMacroData controls the current macro evidence.
REST, ReAct, MCP, or Optimizers: Which Path to Use
Start with the smallest integration that proves the workflow. A direct REST wrapper is often enough for a deterministic report. ReAct is useful when the model should choose which narrow data function to call. MCP is useful when DSPy should consume a standard hosted tool surface. Optimizers come last, once you can score quality.
| Path | Use it when | What DSPy gets | First useful output |
|---|---|---|---|
| REST wrapper | Your service owns credentials, retries, validation, and logs. | A normal Python function returning FXMacroData JSON. | Evidence packet. |
| Signature module | The data is already fetched and the model only needs to shape the briefing. | Typed inputs and outputs through dspy.Signature. |
Structured briefing. |
| ReAct tools | The program should choose which read-only macro function to call. | Python functions or dspy.Tool instances. |
Tool-grounded answer. |
| MCP | The agent should discover tools from a hosted server. | FXMacroData tools from https://mcp.fxmacrodata.com. |
Reusable tool surface. |
| Optimizer | You have examples and a metric that reflects analyst quality. | Compiled prompts and program settings. | Improved reliability. |
Prerequisites
You need Python, DSPy, a configured model provider, an FXMacroData API key, and one narrow finance workflow to measure. For MCP use, install DSPy with its MCP extras.
pip install -U dspy requests
pip install -U "dspy[mcp]"
For direct REST checks, use production FXMacroData endpoints and query-parameter authentication:
curl "https://api.fxmacrodata.com/v1/calendar/usd?api_key=YOUR_API_KEY"
curl "https://api.fxmacrodata.com/v1/announcements/usd/inflation?api_key=YOUR_API_KEY"
curl "https://api.fxmacrodata.com/v1/forex/eur/usd?api_key=YOUR_API_KEY"
curl "https://api.fxmacrodata.com/v1/commodities/latest?api_key=YOUR_API_KEY"
Keep the API key server-side. The model should receive evidence and source paths, not credentials.
Step 1: Define the DSPy Signature
What to do: declare the final briefing shape before adding tools. This keeps the program focused on evidence, not general market prose.
import dspy
class FxMacroBrief(dspy.Signature):
"""Brief an FX macro event using supplied evidence only."""
question: str = dspy.InputField()
evidence: dict = dspy.InputField()
answer: str = dspy.OutputField()
sources: list[str] = dspy.OutputField()
data_gaps: list[str] = dspy.OutputField()
review_required: bool = dspy.OutputField()
The signature is deliberately small. A first version should prove that the program can separate evidence from interpretation and name what it used. Add portfolio, pair, scenario, or risk fields later when the workflow needs them.
Briefing contract
Evidence
Returned rows, currencies, indicators, timestamps, and endpoint paths.
Interpretation
The analyst view generated from fetched data, not model memory.
Gaps
Missing rows, stale data, unavailable values, and anything requiring review.
Step 2: Add FXMacroData REST Tools
What to do: keep authentication and HTTP behavior in normal application code. DSPy tools can call that code, but prompts should not contain credentials, retry policy, or data-cleaning rules.
import os
import requests
API_ROOT = "https://api.fxmacrodata.com/v1"
def fxmd_get(path: str, params: dict | None = None) -> dict:
query = {"api_key": os.environ["FXMD_API_KEY"], **(params or {})}
response = requests.get(f"{API_ROOT}/{path}", params=query, timeout=10)
response.raise_for_status()
return {
"endpoint": f"/v1/{path}",
"payload": response.json(),
}
Start with one or two data functions. A broad "get anything" tool makes evaluation harder because the model can call irrelevant endpoints and still write a plausible answer.
def fxmacrodata_calendar(currency: str) -> dict:
"""Fetch confirmed macro calendar rows for a 3-letter currency."""
code = currency.lower().strip()
return fxmd_get(f"calendar/{code}")
def fxmacrodata_announcement(currency: str, indicator: str) -> dict:
"""Fetch historical announcement rows for one indicator."""
code = currency.lower().strip()
slug = indicator.lower().strip()
return fxmd_get(f"announcements/{code}/{slug}")
| Function | Purpose | Example endpoint |
|---|---|---|
fxmacrodata_calendar |
Find scheduled releases for a currency. | /v1/calendar/usd |
fxmacrodata_announcement |
Fetch historical release rows. | /v1/announcements/usd/inflation |
fxmacrodata_pair_context |
Add spot context to a release note. | /v1/forex/eur/usd |
fxmacrodata_positioning |
Add COT positioning to a currency view. | /v1/cot/usd |
Step 3: Use ReAct When the Program Needs Tools
What to do: use dspy.ReAct when the program needs to decide whether to call a tool. DSPy documentation describes tools as normal Python functions with type-hinted parameters and docstrings, and ReAct as a reasoning-and-acting loop that can decide when to call tools and when to finish.
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))
class FxMacroAgent(dspy.Signature):
"""Answer only after checking FXMacroData when facts are current."""
question: str = dspy.InputField()
answer: str = dspy.OutputField()
sources: list[str] = dspy.OutputField()
data_gaps: list[str] = dspy.OutputField()
agent = dspy.ReAct(
FxMacroAgent,
tools=[fxmacrodata_calendar, fxmacrodata_announcement],
max_iters=4,
)
result = agent(question="What USD release risk matters next?")
print(result.answer)
Keep max_iters conservative at first. A finance agent should not wander across tools until it finds a narrative. It should retrieve the smallest evidence set that answers the question.
Step 4: Use MCP for a Standard Tool Surface
What to do: use MCP when the tool surface should be reusable across DSPy and other agent hosts. FXMacroData's canonical MCP endpoint is https://mcp.fxmacrodata.com. In hosts that use the VS Code-style shape, the configuration is:
{
"servers": {
"FXMacroData": {
"type": "http",
"url": "https://mcp.fxmacrodata.com"
}
}
}
DSPy can consume MCP tools through the Python MCP client session and convert discovered MCP tools into dspy.Tool instances. The DSPy MCP tutorial demonstrates that pattern with dspy.Tool.from_mcp_tool(session, tool). The transport you use should match your MCP client and host; the FXMacroData production server is remote HTTP.
# Sketch: convert discovered MCP tools into DSPy tools.
dspy_tools = []
for tool in tools.tools:
dspy_tools.append(dspy.Tool.from_mcp_tool(session, tool))
react = dspy.ReAct(FxMacroAgent, tools=dspy_tools)
result = await react.acall(
question="Summarize the next USD macro events."
)
For teams that prefer an explicit local wrapper, keep the MCP tool contract small and finance-specific. A JSON shape like this is enough to describe the calendar tool to a compatible host:
{
"name": "fxmacrodata_calendar",
"description": "Fetch confirmed macro calendar rows for a currency.",
"input_schema": {
"type": "object",
"properties": {
"currency": {
"type": "string",
"description": "Three-letter currency code, such as USD"
}
},
"required": ["currency"]
}
}
Step 5: Optimize Against Finance Criteria
What to do: do not optimize for style first. Optimize for evidence. DSPy optimizers need examples and a metric. For FX macro, a basic metric can reward source paths, explicit gaps, and a concise answer grounded in the fetched rows.
def macro_brief_metric(example, pred, trace=None) -> float:
sources = " ".join(getattr(pred, "sources", []) or [])
answer = getattr(pred, "answer", "") or ""
gaps = getattr(pred, "data_gaps", []) or []
has_source_path = "/v1/" in sources
has_answer = len(answer) >= 80
names_gaps = isinstance(gaps, list)
avoids_trade_order = "buy " not in answer.lower()
return float(has_source_path and has_answer and names_gaps and avoids_trade_order)
Once the metric is meaningful, compile the program against a small set of real examples. Keep a validation set separate so you can tell whether optimization improved the workflow or merely fit your examples.
optimizer = dspy.GEPA(
metric=macro_brief_metric,
auto="light",
num_threads=2,
)
optimized_agent = optimizer.compile(
agent,
trainset=train_examples,
valset=validation_examples,
)
optimized_agent.save("fxmacrodata_dspy_agent.json")
What the metric should reward
Grounding
The answer includes endpoint paths and values from retrieved FXMacroData rows.
Restraint
The program refuses to turn a macro note into an execution instruction.
Disclosure
The output names missing data, stale rows, empty results, and review needs.
Step 6: Add Finance Guardrails
Keep the first DSPy and FXMacroData integration read-only. The program should retrieve, summarize, compare, and flag. It should not place trades, alter risk limits, or hide missing data behind confident language.
- Require evidence before prose. Current macro claims should come after a REST or MCP tool call.
- Keep tools narrow. Prefer separate calendar, announcement, FX, COT, commodity, and session functions.
- Score gaps. Reward outputs that name missing or stale data instead of smoothing over it.
- Cap ReAct loops. Avoid uncontrolled tool-chaining for simple release briefings.
- Separate research from execution. The first production workflow should be human-reviewed and read-only.
Common Questions
Can DSPy use FXMacroData?
Yes. DSPy can use FXMacroData through direct REST wrappers, normal Python tools passed to dspy.ReAct, or MCP tools converted into dspy.Tool instances.
Should DSPy replace a macro data feed?
No. DSPy should organize and optimize the model program. FXMacroData should remain the source for release calendars, announcement rows, FX history, COT, commodities, sessions, timestamps, and data gaps.
Should I use REST or MCP with DSPy?
Use REST when your application owns credentials, retries, cache policy, validation, and logs. Use MCP when you want a shared standard tool surface that can also work across other agent hosts.
When should I use DSPy optimizers?
Use optimizers after you have a meaningful metric and examples. For finance, the metric should reward evidence, source paths, gap disclosure, and conservative wording before it rewards style.