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

How-To

How-To Guides

How to Build an FX Macro Model with FXMacroData

Build a repeatable FX macro scorecard from FXMacroData releases, calendars, coverage metadata, and source-labelled forecasts.

Share article X LinkedIn Email
FXMacroData robot assembling official macro data tiles into an FX scorecard

Quick answer

A useful FX macro model does not need to predict every release. It needs a repeatable way to turn official releases, forecast expectations, and release timing into comparable country scores. FXMacroData gives those inputs a shared structure: confirmed release calendars, released observations, source-labelled forecasts, and coverage metadata.

Most FX macro frameworks start with the same economic building blocks: growth, inflation, labour, policy, external balance, money, and sentiment. The hard part is turning those blocks into a model that updates consistently, respects release timing, and can be reviewed after each data cycle.

This guide shows how to build an EUR/USD-style country scorecard with FXMacroData as the data layer. The same structure works for any supported pair: score the base currency, score the quote currency, then trade the spread only when the macro evidence and price action agree.

Use case

Analysts, traders, and developers building a repeatable FX macro signal from official releases, forecasts, and coverage metadata.

Coverage basis

Inputs are selected from FXMacroData coverage metadata, so each factor has clear timing, units, and source labels.

Main output

A country-level macro score and a pair-level spread score for dashboards, research notes, alerts, and backtests.

Define a Comparable Data Universe

Start by deciding which economic concepts can be measured consistently for the currencies in the pair. The FXMacroData catalogue is useful here because it exposes coverage, units, frequency, and availability before the model assigns weights.

Some macro concepts have several reasonable proxies. A hard activity measure, a confidence survey, an output series, and a construction release can all describe the cycle, but they do not carry the same meaning. Treat coverage gaps as a signal to reduce confidence, not as a reason to force a weak proxy into a high-weight bucket.

Coverage quality: a smaller model with clear release timing, units, and source labels is easier to audit than a wide model built from mismatched factors. Score strong buckets normally, scale down partial buckets, and keep sparse currencies transparent in the output.

Map Supported Indicators to Macro Buckets

Start with the economic logic, then use the FXMacroData catalogue to decide which indicators can actually enter the model for each currency.

Macro bucket Supported FXMacroData inputs Scoring idea
Growth GDP, retail sales, building permits, construction-related releases where covered Positive when growth momentum improves versus the currency's own recent history.
Inflation CPI, core inflation, PCE or local inflation variants where covered Positive for the currency when inflation pressure raises policy-rate support, unless growth risk dominates.
Labour Unemployment rate, Non-Farm Payrolls, wages and participation where available Positive when employment momentum is firm and unemployment is falling. Keep level and trend separate when unemployment gaps are not directly modelled.
Policy Policy rate, central-bank releases, policy-sensitive inflation and labour data Positive when realised data and central-bank communication point to tighter relative policy.
External balance Trade balance, current account where covered Positive when external balances improve or terms-of-trade pressure eases.
Money and liquidity M2, risk-free rates, bond yields, liquidity-sensitive market datasets where covered Use as a regime filter rather than a single-release trigger.
Sentiment and activity surveys Business confidence, consumer confidence, supported official survey proxies Positive when confidence improves and confirms hard-data momentum.

Build the Scorecard Workflow

The core workflow has four layers: coverage, observations, forecasts, and pair scoring. The release calendar tells you when data becomes known, announcements carry released values, and predictions carry source-labelled expectations where FXMacroData has them.

1. Coverage

Use the data catalogue to decide which buckets are scoreable.

2. Actuals

Pull released values from announcements.

3. Expectations

Use source-labelled predictions only when available.

4. FX spread

Subtract quote-country score from base-country score.

Prerequisites

  • An FXMacroData API key.
  • A target pair, such as EUR/USD, GBP/USD, or AUD/JPY.
  • A defined research horizon, such as intraday event monitoring, weekly macro review, or medium-term regime scoring.
  • A decision on bucket weights before you inspect the next release.

Step 1: Check what the currency can score

A universal indicator list will usually break across currencies. Start with the catalogue, then keep rows that are available, timely, and usable for signal work.

curl "https://api.fxmacrodata.com/v1/data_catalogue/usd?include_coverage=true&api_key=YOUR_API_KEY"

A model can then require available=true, recent coverage, and a compatible unit/frequency before an indicator is allowed into the scorecard.

import requests

API_KEY = "YOUR_API_KEY"
root = "https://api.fxmacrodata.com/v1"

def catalogue(currency):
    url = f"{root}/data_catalogue/{currency.lower()}"
    params = {"include_coverage": "true", "api_key": API_KEY}
    return requests.get(url, params=params, timeout=20).json()

usd_catalogue = catalogue("usd")

Step 2: Pull observations with release timing

For each selected indicator, use the announcements route. Keep date for the observation period and announcement_datetime for the moment the value became known.

curl "https://api.fxmacrodata.com/v1/announcements/usd/inflation?seasonality=sa&frequency=qoq&annualization=saar&start_date=2026-01-01&end_date=2026-12-31&limit=100&api_key=YOUR_API_KEY"

That distinction matters. A Q2 inflation observation can have a quarter-end date of 30 June while the release arrives in July. A backtest or live scorecard should not treat the value as known before the release timestamp.

Step 3: Convert each indicator into a signed factor

Raw values are not comparable. A 0.3% monthly inflation print, a 150k payrolls print, and a 5.25% policy rate need to become standardised factor scores.

Transform Use when Example
Rolling z-score You want the latest value relative to its own history. (latest - rolling_mean) / rolling_std
Direction score Higher is not always better. Falling unemployment is positive, so multiply the unemployment z-score by -1.
Surprise score A matching FXMacroData forecast exists for the same period and unit. actual - forecast, scaled by historical surprise volatility.
def signed_zscore(values, higher_is_positive=True, window=24):
    latest = values[-1]
    hist = values[-window:]
    mean = sum(hist) / len(hist)
    variance = sum((x - mean) ** 2 for x in hist) / max(len(hist) - 1, 1)
    z = (latest - mean) / (variance ** 0.5 or 1)
    return z if higher_is_positive else -z

Add Forecast Surprises Without Lookahead

Forecasts should be treated by source label. A market_consensus row is a market consensus row. A survey row is a survey row. A model should not rename one as the other simply because both can be used as expectations.

The FXMacroData Predictions API keeps those expectations separate from released observations and links them to the same announcement_id. That makes the join explicit.

curl "https://api.fxmacrodata.com/v1/predictions/usd/inflation?seasonality=sa&frequency=qoq&annualization=saar&prediction_type=survey&start_date=2026-01-01&end_date=2026-12-31&limit=100&api_key=YOUR_API_KEY"

When a prediction row and an announcement row share an announcement identifier, the scorecard can join the expectation and the realised value without guessing the release period:

{
  "announcement_id": "usd_inflation_example",
  "date": "2026-06-30",
  "announcement_datetime": 1784032200,
  "predictions": [
    {
      "predicted_value": 2.4,
      "prediction_type": "survey",
      "prediction_source": "survey_source"
    }
  ]
}

The matching announcement row carries the realised value:

{
  "announcement_id": "usd_inflation_example",
  "date": "2026-06-30",
  "val": 2.55,
  "announcement_datetime": 1784032200,
  "source": "official_source"
}

In this simplified example, the surprise is 2.55 - 2.40 = +0.15 percentage points. Because the forecast and actual use the same frequency, seasonality, annualisation, observation date, and release identifier, the surprise is suitable for a clean scorecard.

Turn Country Scores Into an FX Pair Score

A pair model should compare countries rather than score one currency in isolation. Build a country score for each side, then subtract the quote side from the base side.

Example country score

country_score = 0.25 * growth + 0.25 * inflation + 0.20 * labour + 0.20 * policy + 0.10 * external_balance

pair_score = base_country_score - quote_country_score

weights = {
    "growth": 0.25,
    "inflation": 0.25,
    "labour": 0.20,
    "policy": 0.20,
    "external": 0.10,
}

def country_score(bucket_scores):
    return sum(weights[k] * bucket_scores.get(k, 0.0) for k in weights)

eur_usd_score = country_score(eur_buckets) - country_score(usd_buckets)

Use thresholds to keep the output practical. For example, a score near zero can mean "no macro edge"; a high positive score can mean the base currency has stronger macro support; a high negative score can mean the quote currency has stronger support. The score should guide idea selection, not replace execution rules.

Plot the Model Outputs

Interactive charts make a macro scorecard easier to audit. A good model view should show which buckets are driving the country score, whether surprises are coming from clean expectation joins, and when the pair spread is strong enough to matter.

Bucket score comparison

Compare the base and quote currency by macro bucket before combining them into a pair score.

Country score by macro bucket Growth Inflation Labour Policy External Base currency Quote

Takeaway: the pair signal is easier to trust when the strongest buckets are visible, not hidden inside one blended number.

Actual, expectation, and surprise

Plot expectations beside released values so the model separates trend strength from release-day surprise.

Released value vs expectation JanFebMarAprMayJun ActualExpectation

Takeaway: a surprise score is only useful when the forecast and actual use the same observation period, units, and release identifier.

Pair macro spread

Track the base-minus-quote spread through time and mark the zones where the score is strong enough to become a research lead.

Base-minus-quote macro spread W1W2W3W4W5W6W7W8

Takeaway: the chart should make stale, neutral, and high-conviction regimes obvious before a trade idea reaches execution.

Review the Model After Each Release Cycle

Macro scorecards improve through review. After each major release week, record which bucket moved, whether the release was a trend confirmation or a surprise, and whether the currency pair followed through over the next few sessions.

Review item Question
Coverage Were the scored inputs covered by FXMacroData with compatible units and timing?
Timing Was the score updated only after announcement_datetime?
Surprise Did the forecast and actual use the same frequency, seasonality, and unit?
Decision value Did large score changes improve the quality of alerts, research notes, backtests, or trade filters?

Common Questions

How should expectation sources be used?

Treat each prediction source label as its own expectation stream. A market_consensus row, survey forecast, model nowcast, central-bank projection, and blended forecast can all be useful, but they should be scored and reviewed separately unless the model has a deliberate blend method.

How should the model handle indicators that are not covered?

Use the catalogue to separate strong, partial, and unavailable buckets. If a related indicator measures the same economic concept, it can be used with a lower confidence weight. If coverage is too thin, mark that bucket as unavailable for the currency rather than overstating the signal.

What should I do when a currency has sparse coverage?

Use fewer buckets, lower confidence weights, and clearer labels. Sparse coverage is still useful when the output tells the reader which parts of the country score are strong, partial, or unavailable.

Does the scorecard generate trades automatically?

No. The scorecard ranks macro support across currencies. Execution still needs liquidity, volatility, price confirmation, and risk controls. The model is most useful as a repeatable research layer that can feed alerts, dashboards, backtests, and trade filters.

The final model is deliberately conservative: it favours comparable inputs, transparent coverage, and release-aware scoring over a long list of loosely related variables. That is what makes the output repeatable enough to use in a trading process.

Blogroll

AI Answer-Ready

Key Facts

Page
How To Build FX Macro Model With FXmacrodata
Section
Articles
Canonical URL
https://fxmacrodata.com/articles/how-to-build-fx-macro-model-with-fxmacrodata
Source
FXMacroData editorial and official publisher references
Last Updated
2026-07-15 10:45 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

How should expectation sources be used? Treat each prediction source label as its own expectation stream. A market_consensus row, survey forecast, model nowcast, central-bank projection, and blended forecast can all be useful, but they should be scored and reviewed separately unless the model has a deliberate blend method.

How should the model handle indicators that are not covered? Use the catalogue to separate strong, partial, and unavailable buckets. If a related indicator measures the same economic concept, it can be used with a lower confidence weight. If coverage is too thin, mark that bucket as unavailable for the currency rather than overstating the signal.

What should I do when a currency has sparse coverage? Use fewer buckets, lower confidence weights, and clearer labels. Sparse coverage is still useful when the output tells the reader which parts of the country score are strong, partial, or unavailable.

Does the scorecard generate trades automatically? No. The scorecard ranks macro support across currencies. Execution still needs liquidity, volatility, price confirmation, and risk controls.

Prompt Packs

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