prefect-fxmacrodata 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ # Operation coverage
2
+
3
+ This release exposes all 79 operations in the public-client 0.1.1 inventory:
4
+ 29 REST operations (28 GET, 1 POST) and 50 hosted MCP tools. Each is a named Prefect task
5
+ imported from `prefect_fxmacrodata.tasks`; exact input schemas are available through
6
+ `operation_schemas()`. This inventory is the service snapshot verified on 2026-09-11.
7
+
8
+ | Task | Transport and path | Complete history |
9
+ | --- | --- | --- |
10
+ | `health` | `GET /v1/health` | Not offset-paginated |
11
+ | `ping` | `GET /v1/ping` | Not offset-paginated |
12
+ | `forex` | `GET /v1/forex/{base}/{quote}` | `complete_history` |
13
+ | `intraday_reference_rates` | `GET /v1/fx/intraday-reference-rates/{base}/{quote}` | Not offset-paginated |
14
+ | `fx_sources` | `GET /v1/fx/sources` | Not offset-paginated |
15
+ | `fx_source_universe` | `GET /v1/fx/source-universe` | Not offset-paginated |
16
+ | `data_catalogue` | `GET /v1/data_catalogue/{currency}` | Not offset-paginated |
17
+ | `release_calendar` | `GET /v1/calendar/{currency}` | Not offset-paginated |
18
+ | `market_sessions` | `GET /v1/market_sessions` | Not offset-paginated |
19
+ | `rate_differentials` | `GET /v1/rate_differentials/{base}/{quote}` | `complete_history` |
20
+ | `curves` | `GET /v1/curves/{currency}` | Not offset-paginated |
21
+ | `financial_prices` | `GET /v1/financial_prices/{currency}` | `complete_history` |
22
+ | `press_releases` | `GET /v1/press-releases/{currency}` | `complete_history` |
23
+ | `risk_sentiment` | `GET /v1/risk_sentiment` | `complete_history` |
24
+ | `factors` | `GET /v1/factors/{currency}/{factor}` | `complete_history` |
25
+ | `event_predictions` | `GET /v1/predictions/{currency}/{indicator}` | `complete_history` |
26
+ | `latest_announcements` | `GET /v1/announcements/{currency}/latest` | Not offset-paginated |
27
+ | `indicator_history` | `GET /v1/announcements/{currency}/{indicator}` | `complete_history` |
28
+ | `cot` | `GET /v1/cot/{currency}` | `complete_history` |
29
+ | `latest_commodities` | `GET /v1/commodities/latest` | Not offset-paginated |
30
+ | `commodities` | `GET /v1/commodities/{indicator}` | `complete_history` |
31
+ | `announcement_changes` | `GET /v1/announcements/changes` | Not offset-paginated |
32
+ | `stream_events` | `GET /v1/stream/events` | Not offset-paginated |
33
+ | `reference_rates` | `GET /v1/fx/reference-rates/{base}/{quote}` | `complete_history` |
34
+ | `session_rates` | `GET /v1/fx/session-rates/{base}/{quote}` | `complete_history` |
35
+ | `prediction_coverage` | `GET /v1/predictions/coverage` | Not offset-paginated |
36
+ | `currency_prediction_coverage` | `GET /v1/predictions/coverage/{currency}` | Not offset-paginated |
37
+ | `currency_predictions` | `GET /v1/predictions/{currency}` | Not offset-paginated |
38
+ | `research_panel` | `POST /v1/research/panel` | Not offset-paginated |
39
+ | `mcp_ping` | `MCP /mcp` | Not offset-paginated |
40
+ | `mcp_mcp_capabilities` | `MCP /mcp` | Not offset-paginated |
41
+ | `mcp_mcp_auth_guide` | `MCP /mcp` | Not offset-paginated |
42
+ | `mcp_subscribe_for_mcp_access` | `MCP /mcp` | Not offset-paginated |
43
+ | `mcp_data_catalogue` | `MCP /mcp` | Not offset-paginated |
44
+ | `mcp_risk_sentiment` | `MCP /mcp` | Not offset-paginated |
45
+ | `mcp_macro_news` | `MCP /mcp` | Not offset-paginated |
46
+ | `mcp_release_calendar` | `MCP /mcp` | Not offset-paginated |
47
+ | `mcp_release_calendar_visual_artifact` | `MCP /mcp` | Not offset-paginated |
48
+ | `mcp_event_predictions` | `MCP /mcp` | Not offset-paginated |
49
+ | `mcp_latest_announcements` | `MCP /mcp` | Not offset-paginated |
50
+ | `mcp_announcement_changes` | `MCP /mcp` | Not offset-paginated |
51
+ | `mcp_press_releases` | `MCP /mcp` | Not offset-paginated |
52
+ | `mcp_macro_factor` | `MCP /mcp` | Not offset-paginated |
53
+ | `mcp_fx_reference_sources` | `MCP /mcp` | Not offset-paginated |
54
+ | `mcp_fx_reference_universe` | `MCP /mcp` | Not offset-paginated |
55
+ | `mcp_fx_intraday_reference_rates` | `MCP /mcp` | Not offset-paginated |
56
+ | `mcp_rate_curve` | `MCP /mcp` | Not offset-paginated |
57
+ | `mcp_rate_differentials` | `MCP /mcp` | Not offset-paginated |
58
+ | `mcp_latest_commodities` | `MCP /mcp` | Not offset-paginated |
59
+ | `mcp_forex` | `MCP /mcp` | Not offset-paginated |
60
+ | `mcp_seasonality` | `MCP /mcp` | Not offset-paginated |
61
+ | `mcp_indicator_query` | `MCP /mcp` | Not offset-paginated |
62
+ | `mcp_plot_visual_artifact` | `MCP /mcp` | Not offset-paginated |
63
+ | `mcp_indicator_visual_artifact` | `MCP /mcp` | Not offset-paginated |
64
+ | `mcp_forex_visual_artifact` | `MCP /mcp` | Not offset-paginated |
65
+ | `mcp_commodities_visual_artifact` | `MCP /mcp` | Not offset-paginated |
66
+ | `mcp_cot_visual_artifact` | `MCP /mcp` | Not offset-paginated |
67
+ | `mcp_policy_rate_differential_visual_artifact` | `MCP /mcp` | Not offset-paginated |
68
+ | `mcp_macro_briefing_task` | `MCP /mcp` | Not offset-paginated |
69
+ | `mcp_indicator_intel_task` | `MCP /mcp` | Not offset-paginated |
70
+ | `mcp_pair_intel_task` | `MCP /mcp` | Not offset-paginated |
71
+ | `mcp_macro_heatmap_task` | `MCP /mcp` | Not offset-paginated |
72
+ | `mcp_policy_scenario_modeler_task` | `MCP /mcp` | Not offset-paginated |
73
+ | `mcp_macro_war_room_task` | `MCP /mcp` | Not offset-paginated |
74
+ | `mcp_event_impact_replay_task` | `MCP /mcp` | Not offset-paginated |
75
+ | `mcp_quant_scenario_lab_task` | `MCP /mcp` | Not offset-paginated |
76
+ | `mcp_known_at_time_task` | `MCP /mcp` | Not offset-paginated |
77
+ | `mcp_macro_regime_classifier_task` | `MCP /mcp` | Not offset-paginated |
78
+ | `mcp_release_risk_score_task` | `MCP /mcp` | Not offset-paginated |
79
+ | `mcp_portfolio_risk_engine_task` | `MCP /mcp` | Not offset-paginated |
80
+ | `mcp_fx_trade_setup_task` | `MCP /mcp` | Not offset-paginated |
81
+ | `mcp_fx_backtest_task` | `MCP /mcp` | Not offset-paginated |
82
+ | `mcp_macro_research_pack_task` | `MCP /mcp` | Not offset-paginated |
83
+ | `mcp_prediction_coverage` | `MCP /mcp` | Not offset-paginated |
84
+ | `mcp_market_sessions` | `MCP /mcp` | Not offset-paginated |
85
+ | `mcp_cot_data` | `MCP /mcp` | Not offset-paginated |
86
+ | `mcp_commodities` | `MCP /mcp` | Not offset-paginated |
87
+ | `mcp_financial_prices` | `MCP /mcp` | Not offset-paginated |
88
+ | `mcp_official_dataset_family` | `MCP /mcp` | Not offset-paginated |
89
+
90
+ All tasks return `FXMacroDataResult` with the original payload, provenance and an additive
91
+ record view. No endpoint payload is replaced with a target-specific schema. MCP artefact
92
+ content is retained in the result for downstream tasks; this collection does not execute
93
+ embedded HTML or scripts. Streaming remains a finite capture with completion metadata.
94
+
95
+ [FXMacroData reference](https://fxmacrodata.com/documentation/reference?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=docs)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Tidball
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,16 @@
1
+ include CAPABILITIES.md
2
+ include LICENSE
3
+ include MANIFEST.in
4
+ include PUBLIC_FILES.json
5
+ include README.md
6
+ include pyproject.toml
7
+ include prefect_fxmacrodata/__init__.py
8
+ include prefect_fxmacrodata/credentials.py
9
+ include prefect_fxmacrodata/flows.py
10
+ include prefect_fxmacrodata/models.py
11
+ include prefect_fxmacrodata/tasks.py
12
+ include prefect_fxmacrodata/tasks.pyi
13
+ include prefect_fxmacrodata/py.typed
14
+ include tests/conftest.py
15
+ include tests/test_tasks.py
16
+ include tests/test_runtime.py
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.4
2
+ Name: prefect-fxmacrodata
3
+ Version: 0.1.0
4
+ Summary: FXMacroData subscription data in Prefect tasks and research flows
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://fxmacrodata.com/?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=readme
7
+ Project-URL: Subscribe, https://fxmacrodata.com/subscribe?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=subscribe
8
+ Project-URL: Documentation, https://fxmacrodata.com/documentation/reference?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=docs
9
+ Requires-Python: <3.15,>=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: prefect<4,>=3.9.1
13
+ Requires-Dist: fxmacrodata-public-client==0.1.1
14
+ Dynamic: license-file
15
+
16
+ # FXMacroData for Prefect
17
+
18
+ Bring your FXMacroData subscription into scheduled Prefect research workflows:
19
+ cross-currency indicators, complete available histories, FX reference rates,
20
+ commodities, positioning and release analysis. Store your API key in a Prefect
21
+ Credentials Block and pass its name to native tasks.
22
+
23
+ **[Subscribe to FXMacroData](https://fxmacrodata.com/subscribe?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=subscribe)**
24
+ for subscriber coverage and deeper available history. Public USD catalogue,
25
+ recent indicator history and calendar access let you evaluate the workflow
26
+ before subscribing without an API key. Availability varies by dataset.
27
+
28
+ ## Install and connect
29
+
30
+ Use Python 3.10–3.14 and Prefect 3.9.1 or later within version 3. From the release artifacts directory,
31
+ install the adapter wheel into the environment that runs your flows. Its pinned
32
+ FXMacroData public client is available on PyPI and resolves automatically:
33
+
34
+ ```bash
35
+ python -m pip install ./prefect_fxmacrodata-0.1.0-py3-none-any.whl
36
+ prefect block register -m prefect_fxmacrodata
37
+ ```
38
+
39
+ The adapter uses the supplied release artifact; its public-client dependency
40
+ comes from PyPI. Configure your Prefect server or Cloud workspace through Prefect's
41
+ normal setup. In **Blocks**, create an **FXMacroData Credentials** block, enter
42
+ your subscription API key and save it as `fxmacrodata-research`. The key uses
43
+ Prefect's secret-field storage. The timeout controls each HTTP request, in seconds.
44
+
45
+ To create the same block interactively without putting a key in source code:
46
+
47
+ ```python
48
+ from getpass import getpass
49
+ from pydantic import SecretStr
50
+ from prefect_fxmacrodata import FXMacroDataCredentials
51
+
52
+ FXMacroDataCredentials(
53
+ api_key=SecretStr(getpass("FXMacroData API key: ")),
54
+ ).save("fxmacrodata-research")
55
+ ```
56
+
57
+ Create the block during setup, outside a flow. Flows and tasks take only its name;
58
+ do not put keys in flow parameters, operation arguments or logs. Omitting
59
+ `credentials_block` explicitly uses public evaluation access, even if an API-key
60
+ environment variable is set.
61
+
62
+ ## Build a research flow
63
+
64
+ `macro_snapshot` is a Prefect subflow that collects every available history page
65
+ for the selected series and retrieves its release calendar. Pass the typed
66
+ snapshot to your own downstream task:
67
+
68
+ ```python
69
+ import asyncio
70
+ from prefect import flow, task
71
+ from prefect_fxmacrodata import MacroSnapshot, macro_snapshot
72
+
73
+
74
+ @task(persist_result=False)
75
+ def count_observations(snapshot: MacroSnapshot) -> int:
76
+ return len(snapshot.history.records())
77
+
78
+
79
+ @flow(persist_result=False)
80
+ async def research_run():
81
+ snapshot = await macro_snapshot(
82
+ "EUR",
83
+ "policy_rate",
84
+ credentials_block="fxmacrodata-research",
85
+ start_date="2020-01-01",
86
+ end_date="2026-01-01",
87
+ )
88
+ return count_observations(snapshot)
89
+
90
+
91
+ if __name__ == "__main__":
92
+ asyncio.run(research_run())
93
+ ```
94
+
95
+ To evaluate with USD, omit the credentials and historical date range:
96
+
97
+ ```python
98
+ snapshot = await macro_snapshot("USD", "policy_rate")
99
+ ```
100
+
101
+ Subscriber history can extend beyond the public evaluation window where the
102
+ series supports it.
103
+ Deploy or schedule this flow with your normal Prefect work pool and deployment process.
104
+ The date filters select indicator history. The calendar uses the API's current
105
+ release-calendar window for the currency; it is not filtered to the historical
106
+ range or one indicator. Use the `release_calendar` task directly for different
107
+ calendar filters.
108
+
109
+ ## Use individual operations
110
+
111
+ Every packaged operation is a named Prefect task, with normal task states,
112
+ dependencies, `with_options`, retries and scheduling through its enclosing flow.
113
+ Both REST and hosted MCP operations are available:
114
+
115
+ ```python
116
+ from prefect_fxmacrodata import operation_schemas
117
+ from prefect_fxmacrodata.tasks import indicator_history, mcp_macro_briefing_task
118
+
119
+
120
+ async def inspect_series():
121
+ page = await indicator_history(
122
+ {"currency": "GBP", "indicator": "inflation", "limit": 100},
123
+ credentials_block="fxmacrodata-research",
124
+ )
125
+ briefing = await mcp_macro_briefing_task(
126
+ {"currency": "GBP"},
127
+ credentials_block="fxmacrodata-research",
128
+ )
129
+ return page, briefing
130
+
131
+
132
+ schemas = {operation.name: operation.input_schema for operation in operation_schemas()}
133
+ ```
134
+
135
+ See [CAPABILITIES.md](CAPABILITIES.md) for the exact operation inventory. The
136
+ original input schemas are available through `operation_schemas()` or the native
137
+ `discover_operations` task. `OPERATION_TASKS[name]` supports configuration-driven
138
+ flows without losing operation-specific task names.
139
+
140
+ Results are `FXMacroDataResult` models. `payload` retains the entire service
141
+ response, including original units, provenance, unavailable values and MCP
142
+ content; `source_url` records the source endpoint. `records()` adds a convenient
143
+ row view without replacing the payload. No publication timestamps or missing
144
+ observations are inferred.
145
+
146
+ ## History and failure behavior
147
+
148
+ Individual operation tasks return a single response using the API's pagination
149
+ rules. Use `complete_history("indicator_history", arguments, credentials_block)`
150
+ for a complete available dataset within the requested filters. It starts at
151
+ offset zero, verifies contiguous pages and dataset versions when supplied, and
152
+ fails if completion cannot be established. Its payload retains every page's
153
+ metadata and returns rows in chronological order. `max_pages` is an explicit
154
+ safety budget; an error never passes an incomplete history off as complete.
155
+ Applications that need resumable storage can persist individual page responses
156
+ and control `offset` and `dataset_version` through the named operation tasks.
157
+
158
+ Event streaming is a bounded capture using `max_events` and `max_seconds`.
159
+ The response retains the original completion flag and reason. Cancellation
160
+ finishes the current bounded HTTP request, closes the client, and stops before
161
+ the next history page. MCP sessions are closed after each task.
162
+
163
+ Tasks disable result persistence and caching by default. Opt in only when the
164
+ destination and access controls suit your data licence. Task errors omit raw
165
+ responses, authenticated URLs and credentials. Transient retries are opt-in with
166
+ Prefect's `with_options(retries=..., retry_delay_seconds=...)`.
167
+
168
+ [FXMacroData API reference](https://fxmacrodata.com/documentation/reference?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=docs)
169
+ describes access requirements and supported arguments for each dataset.
@@ -0,0 +1,20 @@
1
+ {
2
+ "files": [
3
+ "CAPABILITIES.md",
4
+ "LICENSE",
5
+ "MANIFEST.in",
6
+ "PUBLIC_FILES.json",
7
+ "README.md",
8
+ "pyproject.toml",
9
+ "prefect_fxmacrodata/__init__.py",
10
+ "prefect_fxmacrodata/credentials.py",
11
+ "prefect_fxmacrodata/flows.py",
12
+ "prefect_fxmacrodata/models.py",
13
+ "prefect_fxmacrodata/tasks.py",
14
+ "prefect_fxmacrodata/tasks.pyi",
15
+ "prefect_fxmacrodata/py.typed",
16
+ "tests/conftest.py",
17
+ "tests/test_tasks.py",
18
+ "tests/test_runtime.py"
19
+ ]
20
+ }
@@ -0,0 +1,154 @@
1
+ # FXMacroData for Prefect
2
+
3
+ Bring your FXMacroData subscription into scheduled Prefect research workflows:
4
+ cross-currency indicators, complete available histories, FX reference rates,
5
+ commodities, positioning and release analysis. Store your API key in a Prefect
6
+ Credentials Block and pass its name to native tasks.
7
+
8
+ **[Subscribe to FXMacroData](https://fxmacrodata.com/subscribe?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=subscribe)**
9
+ for subscriber coverage and deeper available history. Public USD catalogue,
10
+ recent indicator history and calendar access let you evaluate the workflow
11
+ before subscribing without an API key. Availability varies by dataset.
12
+
13
+ ## Install and connect
14
+
15
+ Use Python 3.10–3.14 and Prefect 3.9.1 or later within version 3. From the release artifacts directory,
16
+ install the adapter wheel into the environment that runs your flows. Its pinned
17
+ FXMacroData public client is available on PyPI and resolves automatically:
18
+
19
+ ```bash
20
+ python -m pip install ./prefect_fxmacrodata-0.1.0-py3-none-any.whl
21
+ prefect block register -m prefect_fxmacrodata
22
+ ```
23
+
24
+ The adapter uses the supplied release artifact; its public-client dependency
25
+ comes from PyPI. Configure your Prefect server or Cloud workspace through Prefect's
26
+ normal setup. In **Blocks**, create an **FXMacroData Credentials** block, enter
27
+ your subscription API key and save it as `fxmacrodata-research`. The key uses
28
+ Prefect's secret-field storage. The timeout controls each HTTP request, in seconds.
29
+
30
+ To create the same block interactively without putting a key in source code:
31
+
32
+ ```python
33
+ from getpass import getpass
34
+ from pydantic import SecretStr
35
+ from prefect_fxmacrodata import FXMacroDataCredentials
36
+
37
+ FXMacroDataCredentials(
38
+ api_key=SecretStr(getpass("FXMacroData API key: ")),
39
+ ).save("fxmacrodata-research")
40
+ ```
41
+
42
+ Create the block during setup, outside a flow. Flows and tasks take only its name;
43
+ do not put keys in flow parameters, operation arguments or logs. Omitting
44
+ `credentials_block` explicitly uses public evaluation access, even if an API-key
45
+ environment variable is set.
46
+
47
+ ## Build a research flow
48
+
49
+ `macro_snapshot` is a Prefect subflow that collects every available history page
50
+ for the selected series and retrieves its release calendar. Pass the typed
51
+ snapshot to your own downstream task:
52
+
53
+ ```python
54
+ import asyncio
55
+ from prefect import flow, task
56
+ from prefect_fxmacrodata import MacroSnapshot, macro_snapshot
57
+
58
+
59
+ @task(persist_result=False)
60
+ def count_observations(snapshot: MacroSnapshot) -> int:
61
+ return len(snapshot.history.records())
62
+
63
+
64
+ @flow(persist_result=False)
65
+ async def research_run():
66
+ snapshot = await macro_snapshot(
67
+ "EUR",
68
+ "policy_rate",
69
+ credentials_block="fxmacrodata-research",
70
+ start_date="2020-01-01",
71
+ end_date="2026-01-01",
72
+ )
73
+ return count_observations(snapshot)
74
+
75
+
76
+ if __name__ == "__main__":
77
+ asyncio.run(research_run())
78
+ ```
79
+
80
+ To evaluate with USD, omit the credentials and historical date range:
81
+
82
+ ```python
83
+ snapshot = await macro_snapshot("USD", "policy_rate")
84
+ ```
85
+
86
+ Subscriber history can extend beyond the public evaluation window where the
87
+ series supports it.
88
+ Deploy or schedule this flow with your normal Prefect work pool and deployment process.
89
+ The date filters select indicator history. The calendar uses the API's current
90
+ release-calendar window for the currency; it is not filtered to the historical
91
+ range or one indicator. Use the `release_calendar` task directly for different
92
+ calendar filters.
93
+
94
+ ## Use individual operations
95
+
96
+ Every packaged operation is a named Prefect task, with normal task states,
97
+ dependencies, `with_options`, retries and scheduling through its enclosing flow.
98
+ Both REST and hosted MCP operations are available:
99
+
100
+ ```python
101
+ from prefect_fxmacrodata import operation_schemas
102
+ from prefect_fxmacrodata.tasks import indicator_history, mcp_macro_briefing_task
103
+
104
+
105
+ async def inspect_series():
106
+ page = await indicator_history(
107
+ {"currency": "GBP", "indicator": "inflation", "limit": 100},
108
+ credentials_block="fxmacrodata-research",
109
+ )
110
+ briefing = await mcp_macro_briefing_task(
111
+ {"currency": "GBP"},
112
+ credentials_block="fxmacrodata-research",
113
+ )
114
+ return page, briefing
115
+
116
+
117
+ schemas = {operation.name: operation.input_schema for operation in operation_schemas()}
118
+ ```
119
+
120
+ See [CAPABILITIES.md](CAPABILITIES.md) for the exact operation inventory. The
121
+ original input schemas are available through `operation_schemas()` or the native
122
+ `discover_operations` task. `OPERATION_TASKS[name]` supports configuration-driven
123
+ flows without losing operation-specific task names.
124
+
125
+ Results are `FXMacroDataResult` models. `payload` retains the entire service
126
+ response, including original units, provenance, unavailable values and MCP
127
+ content; `source_url` records the source endpoint. `records()` adds a convenient
128
+ row view without replacing the payload. No publication timestamps or missing
129
+ observations are inferred.
130
+
131
+ ## History and failure behavior
132
+
133
+ Individual operation tasks return a single response using the API's pagination
134
+ rules. Use `complete_history("indicator_history", arguments, credentials_block)`
135
+ for a complete available dataset within the requested filters. It starts at
136
+ offset zero, verifies contiguous pages and dataset versions when supplied, and
137
+ fails if completion cannot be established. Its payload retains every page's
138
+ metadata and returns rows in chronological order. `max_pages` is an explicit
139
+ safety budget; an error never passes an incomplete history off as complete.
140
+ Applications that need resumable storage can persist individual page responses
141
+ and control `offset` and `dataset_version` through the named operation tasks.
142
+
143
+ Event streaming is a bounded capture using `max_events` and `max_seconds`.
144
+ The response retains the original completion flag and reason. Cancellation
145
+ finishes the current bounded HTTP request, closes the client, and stops before
146
+ the next history page. MCP sessions are closed after each task.
147
+
148
+ Tasks disable result persistence and caching by default. Opt in only when the
149
+ destination and access controls suit your data licence. Task errors omit raw
150
+ responses, authenticated URLs and credentials. Transient retries are opt-in with
151
+ Prefect's `with_options(retries=..., retry_delay_seconds=...)`.
152
+
153
+ [FXMacroData API reference](https://fxmacrodata.com/documentation/reference?utm_source=github&utm_medium=referral&utm_campaign=prefect&utm_content=docs)
154
+ describes access requirements and supported arguments for each dataset.
@@ -0,0 +1,19 @@
1
+ """FXMacroData credentials, tasks and research flows for Prefect."""
2
+
3
+ from .credentials import FXMacroDataCredentials
4
+ from .flows import macro_snapshot
5
+ from .models import FXMacroDataResult, MacroSnapshot, OperationSchema
6
+ from .tasks import OPERATION_TASKS, complete_history, discover_operations, operation_schemas
7
+
8
+ __version__ = "0.1.0"
9
+ __all__ = [
10
+ "FXMacroDataCredentials",
11
+ "FXMacroDataResult",
12
+ "MacroSnapshot",
13
+ "OperationSchema",
14
+ "OPERATION_TASKS",
15
+ "complete_history",
16
+ "discover_operations",
17
+ "macro_snapshot",
18
+ "operation_schemas",
19
+ ]
@@ -0,0 +1,30 @@
1
+ """Reusable FXMacroData connection configuration for Prefect."""
2
+
3
+ from fxmacrodata_public import FXMacroDataClient
4
+ from prefect.blocks.core import Block
5
+ from pydantic import Field, SecretStr
6
+
7
+
8
+ class FXMacroDataCredentials(Block):
9
+ """Store a subscriber's API key using Prefect's encrypted secret field.
10
+
11
+ Tasks take the saved Block name and load this configuration inside the run.
12
+ An empty key explicitly selects public evaluation access.
13
+ """
14
+
15
+ _block_type_name = "FXMacroData Credentials"
16
+ _documentation_url = (
17
+ "https://fxmacrodata.com/documentation/reference?utm_source=github"
18
+ "&utm_medium=referral&utm_campaign=prefect&utm_content=docs"
19
+ )
20
+
21
+ api_key: SecretStr = Field(
22
+ default_factory=lambda: SecretStr(""),
23
+ description="Your FXMacroData subscription API key; leave empty for USD evaluation.",
24
+ repr=False,
25
+ )
26
+ timeout: float = Field(default=30, ge=1, le=120, allow_inf_nan=False)
27
+
28
+ def get_client(self) -> FXMacroDataClient:
29
+ """Create a bounded client; use it as a context manager."""
30
+ return FXMacroDataClient(api_key=self.api_key.get_secret_value(), timeout=self.timeout)
@@ -0,0 +1,42 @@
1
+ """Research workflows composed from ordinary Prefect tasks."""
2
+
3
+ import asyncio
4
+
5
+ from prefect import flow
6
+
7
+ from .models import MacroSnapshot
8
+ from .tasks import OPERATION_TASKS, complete_history
9
+
10
+
11
+ @flow(name="fxmacrodata-macro-snapshot", persist_result=False, log_prints=False)
12
+ async def macro_snapshot(
13
+ currency: str,
14
+ indicator: str,
15
+ credentials_block: str | None = None,
16
+ start_date: str | None = None,
17
+ end_date: str | None = None,
18
+ max_pages: int = 10000,
19
+ ) -> MacroSnapshot:
20
+ """Fetch complete available indicator history and the release calendar.
21
+
22
+ The caller chooses the currency and history range; calendar dates use the
23
+ API's current release-calendar window independently of the history range.
24
+ Original source fields,
25
+ values, publication timestamps and unavailable states are retained.
26
+ """
27
+ arguments = {"currency": currency, "indicator": indicator}
28
+ if start_date is not None:
29
+ arguments["start_date"] = start_date
30
+ if end_date is not None:
31
+ arguments["end_date"] = end_date
32
+ history, calendar = await asyncio.gather(
33
+ complete_history("indicator_history", arguments, credentials_block, max_pages),
34
+ OPERATION_TASKS["release_calendar"]({"currency": currency}, credentials_block),
35
+ )
36
+ return MacroSnapshot(
37
+ currency=currency,
38
+ indicator=indicator,
39
+ history=history,
40
+ calendar=calendar,
41
+ source_urls=list(dict.fromkeys([history.source_url, calendar.source_url])),
42
+ )
@@ -0,0 +1,51 @@
1
+ """Typed envelopes that retain FXMacroData's original responses."""
2
+
3
+ from copy import deepcopy
4
+ from typing import Any
5
+
6
+ from fxmacrodata_public import Result
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+
10
+ class FXMacroDataResult(BaseModel):
11
+ """Original payload and provenance plus an additive row-oriented view."""
12
+
13
+ model_config = ConfigDict(frozen=True)
14
+
15
+ operation: str
16
+ payload: Any = Field(repr=False)
17
+ source_url: str
18
+
19
+ @classmethod
20
+ def from_result(cls, result: Result) -> "FXMacroDataResult":
21
+ """Copy a client result without changing values or metadata."""
22
+ return cls(
23
+ operation=result.operation,
24
+ payload=deepcopy(result.payload),
25
+ source_url=result.source_url,
26
+ )
27
+
28
+ def records(self) -> list[dict[str, Any]]:
29
+ """Return the public client's additive record view."""
30
+ return Result(self.operation, self.payload, self.source_url).records()
31
+
32
+
33
+ class OperationSchema(BaseModel):
34
+ """Discover a native task and its unchanged API argument schema."""
35
+
36
+ name: str
37
+ description: str
38
+ method: str
39
+ path: str
40
+ input_schema: dict[str, Any]
41
+ supports_complete_history: bool
42
+
43
+
44
+ class MacroSnapshot(BaseModel):
45
+ """History and scheduled releases for a research flow's next task."""
46
+
47
+ currency: str
48
+ indicator: str
49
+ history: FXMacroDataResult
50
+ calendar: FXMacroDataResult
51
+ source_urls: list[str] = Field(default_factory=list)
File without changes