Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions quantmind/preprocess/fetch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@
DEFAULT_USER_AGENT,
fetch_url,
)
from quantmind.preprocess.fetch.fxmacrodata import (
DEFAULT_FXMACRODATA_BASE_URL,
fetch_fxmacrodata_calendar,
)
from quantmind.preprocess.fetch.local import read_local_file

__all__ = [
"ArxivIdParseError",
"CrossrefMetadata",
"DEFAULT_FXMACRODATA_BASE_URL",
"DEFAULT_USER_AGENT",
"Fetched",
"RawPaper",
"fetch_arxiv",
"fetch_fxmacrodata_calendar",
"fetch_url",
"read_local_file",
"resolve_doi",
Expand Down
41 changes: 41 additions & 0 deletions quantmind/preprocess/fetch/fxmacrodata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""FXMacroData fetch helpers for macroeconomic context."""

from __future__ import annotations

from typing import Any, Optional

import httpx

DEFAULT_FXMACRODATA_BASE_URL = "https://fxmacrodata.com/api/v1"


async def fetch_fxmacrodata_calendar(
currency: str = "usd",
*,
limit: int = 50,
api_key: Optional[str] = None,
base_url: str = DEFAULT_FXMACRODATA_BASE_URL,
timeout: float = 30.0,
) -> dict[str, Any]:
"""Fetch official release-calendar rows from FXMacroData.

The function returns the parsed JSON payload so callers can preserve
FXMacroData metadata such as data quality, source names, and confirmed
announcement timestamps when building knowledge items.
"""

limit_count = max(1, min(int(limit), 100))
params: dict[str, str] = {"limit": str(limit_count)}
if api_key:
params["api_key"] = api_key

url = f"{base_url.rstrip('/')}/calendar/{currency.lower()}"
headers = {"User-Agent": "QuantMind/0.2 fxmacrodata-fetch"}
async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
response = await client.get(url, params=params, headers=headers)
response.raise_for_status()
payload: dict[str, Any] = response.json()
if isinstance(payload.get("data"), list):
payload["data"] = payload["data"][:limit_count]

return payload