Skip to content
Open
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
69 changes: 37 additions & 32 deletions eodhd/APIs/TreasuryAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,102 +11,107 @@ class TreasuryAPI(BaseAPI):
GET /api/ust/yield-rates
GET /api/ust/long-term-rates
GET /api/ust/real-yield-rates

These endpoints do not support pagination or date-range filtering
(page[limit], page[offset], from, to are ignored by the API). The only
supported filter is filter[year], which selects a single calendar year;
when omitted the API returns the current year's dataset.
"""

def _get_treasury_data(self, api_token: str, rate_type: str, from_date: str = None, to_date: str = None):
"""Internal helper for treasury endpoints."""
def _get_treasury_data(self, api_token: str, rate_type: str, year: int = None):
"""Internal helper for treasury endpoints.

When ``year`` is provided it is sent as filter[year]=<year>; otherwise
no filter is emitted and the API defaults to the current year.
"""
endpoint = "ust"
uri = rate_type
querystring = ""

if from_date is not None:
querystring += f"&from={from_date}"
if to_date is not None:
querystring += f"&to={to_date}"
query_string = self._filter("year", year)

return self._rest_get_method(
api_key=api_token,
endpoint=endpoint,
uri=uri,
querystring=querystring,
querystring=query_string,
)

def get_treasury_bill_rates(self, api_token: str, from_date: str = None, to_date: str = None):
def get_treasury_bill_rates(self, api_token: str, year: int = None):
"""
Get US Treasury bill rates.

Parameters
----------
api_token : str
Your EODHD API token.
from_date : str, optional
Start date in YYYY-MM-DD format.
to_date : str, optional
End date in YYYY-MM-DD format.
year : int, optional
Calendar year to select (sent as filter[year]). Defaults to the
current year when omitted. This is the only supported filter — the
endpoint has no pagination and no date-range parameters.

Returns
-------
list[dict]
Treasury bill rate data.
"""
return self._get_treasury_data(api_token, "bill-rates", from_date, to_date)
return self._get_treasury_data(api_token, "bill-rates", year=year)

def get_treasury_yield_rates(self, api_token: str, from_date: str = None, to_date: str = None):
def get_treasury_yield_rates(self, api_token: str, year: int = None):
"""
Get US Treasury yield curve rates.

Parameters
----------
api_token : str
Your EODHD API token.
from_date : str, optional
Start date in YYYY-MM-DD format.
to_date : str, optional
End date in YYYY-MM-DD format.
year : int, optional
Calendar year to select (sent as filter[year]). Defaults to the
current year when omitted. This is the only supported filter — the
endpoint has no pagination and no date-range parameters.

Returns
-------
list[dict]
Treasury yield rate data.
"""
return self._get_treasury_data(api_token, "yield-rates", from_date, to_date)
return self._get_treasury_data(api_token, "yield-rates", year=year)

def get_treasury_long_term_rates(self, api_token: str, from_date: str = None, to_date: str = None):
def get_treasury_long_term_rates(self, api_token: str, year: int = None):
"""
Get US Treasury long-term rates.

Parameters
----------
api_token : str
Your EODHD API token.
from_date : str, optional
Start date in YYYY-MM-DD format.
to_date : str, optional
End date in YYYY-MM-DD format.
year : int, optional
Calendar year to select (sent as filter[year]). Defaults to the
current year when omitted. This is the only supported filter — the
endpoint has no pagination and no date-range parameters.

Returns
-------
list[dict]
Treasury long-term rate data.
"""
return self._get_treasury_data(api_token, "long-term-rates", from_date, to_date)
return self._get_treasury_data(api_token, "long-term-rates", year=year)

def get_treasury_real_yield_rates(self, api_token: str, from_date: str = None, to_date: str = None):
def get_treasury_real_yield_rates(self, api_token: str, year: int = None):
"""
Get US Treasury real yield curve rates.

Parameters
----------
api_token : str
Your EODHD API token.
from_date : str, optional
Start date in YYYY-MM-DD format.
to_date : str, optional
End date in YYYY-MM-DD format.
year : int, optional
Calendar year to select (sent as filter[year]). Defaults to the
current year when omitted. This is the only supported filter — the
endpoint has no pagination and no date-range parameters.

Returns
-------
list[dict]
Treasury real yield rate data.
"""
return self._get_treasury_data(api_token, "real-yield-rates", from_date, to_date)
return self._get_treasury_data(api_token, "real-yield-rates", year=year)
40 changes: 32 additions & 8 deletions eodhd/apiclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -1558,37 +1558,61 @@ def get_bulk_fundamentals_v1_1(self, exchange, symbols=None, offset=None, limit=
api_token=self._api_key, exchange=exchange, symbols=symbols, offset=offset, limit=limit,
)

def get_treasury_bill_rates(self, from_date=None, to_date=None):
def get_treasury_bill_rates(self, year: int = None):
"""
US Treasury Bill Rates
Endpoint: GET /api/ust/bill-rates

Args:
year [OPTIONAL] - calendar year to select (sent as filter[year]).
Defaults to the current year when omitted. This is the only
supported filter: the endpoint has no pagination and no
date-range parameters.
"""
api_call = TreasuryAPI(session=self._session, timeout=self._timeout)
return api_call.get_treasury_bill_rates(api_token=self._api_key, from_date=from_date, to_date=to_date)
return api_call.get_treasury_bill_rates(api_token=self._api_key, year=year)

def get_treasury_yield_rates(self, from_date=None, to_date=None):
def get_treasury_yield_rates(self, year: int = None):
"""
US Treasury Yield Curve Rates
Endpoint: GET /api/ust/yield-rates

Args:
year [OPTIONAL] - calendar year to select (sent as filter[year]).
Defaults to the current year when omitted. This is the only
supported filter: the endpoint has no pagination and no
date-range parameters.
"""
api_call = TreasuryAPI(session=self._session, timeout=self._timeout)
return api_call.get_treasury_yield_rates(api_token=self._api_key, from_date=from_date, to_date=to_date)
return api_call.get_treasury_yield_rates(api_token=self._api_key, year=year)

def get_treasury_long_term_rates(self, from_date=None, to_date=None):
def get_treasury_long_term_rates(self, year: int = None):
"""
US Treasury Long-Term Rates
Endpoint: GET /api/ust/long-term-rates

Args:
year [OPTIONAL] - calendar year to select (sent as filter[year]).
Defaults to the current year when omitted. This is the only
supported filter: the endpoint has no pagination and no
date-range parameters.
"""
api_call = TreasuryAPI(session=self._session, timeout=self._timeout)
return api_call.get_treasury_long_term_rates(api_token=self._api_key, from_date=from_date, to_date=to_date)
return api_call.get_treasury_long_term_rates(api_token=self._api_key, year=year)

def get_treasury_real_yield_rates(self, from_date=None, to_date=None):
def get_treasury_real_yield_rates(self, year: int = None):
"""
US Treasury Real Yield Curve Rates
Endpoint: GET /api/ust/real-yield-rates

Args:
year [OPTIONAL] - calendar year to select (sent as filter[year]).
Defaults to the current year when omitted. This is the only
supported filter: the endpoint has no pagination and no
date-range parameters.
"""
api_call = TreasuryAPI(session=self._session, timeout=self._timeout)
return api_call.get_treasury_real_yield_rates(api_token=self._api_key, from_date=from_date, to_date=to_date)
return api_call.get_treasury_real_yield_rates(api_token=self._api_key, year=year)

# ── Phase 2: Marketplace ──────────────────────────────────────

Expand Down
38 changes: 34 additions & 4 deletions tests/test_treasury.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,41 @@ def test_real_yield_rates(mock_session):
assert "/ust/real-yield-rates" in call_url


def test_date_params(mock_session):
def test_no_pagination_or_date_params(mock_session):
"""UST endpoints ignore pagination/date-range params, so the SDK must not emit them."""
_mock_response(mock_session)
api = _make_api(mock_session)
api.get_treasury_bill_rates(api_token="test1234567890123456", from_date="2024-01-01", to_date="2024-06-01")
api.get_treasury_bill_rates(api_token="test1234567890123456")

call_url = mock_session.get.call_args[0][0]
assert "&from=2024-01-01" in call_url
assert "&to=2024-06-01" in call_url
assert "from=" not in call_url
assert "to=" not in call_url
assert "page[" not in call_url


def test_no_year_filter_when_omitted(mock_session):
"""When year is omitted, no filter[year] must be emitted (API defaults to current year)."""
_mock_response(mock_session)
api = _make_api(mock_session)
api.get_treasury_bill_rates(api_token="test1234567890123456")

call_url = mock_session.get.call_args[0][0]
assert "filter[year]" not in call_url
assert "filter[" not in call_url


def test_year_filter_emitted(mock_session):
"""When year is passed, filter[year]=<year> is emitted on every UST endpoint."""
_mock_response(mock_session)
api = _make_api(mock_session)

for method, path in (
(api.get_treasury_bill_rates, "/ust/bill-rates"),
(api.get_treasury_yield_rates, "/ust/yield-rates"),
(api.get_treasury_long_term_rates, "/ust/long-term-rates"),
(api.get_treasury_real_yield_rates, "/ust/real-yield-rates"),
):
method(api_token="test1234567890123456", year=2024)
call_url = mock_session.get.call_args[0][0]
assert path in call_url
assert "filter[year]=2024" in call_url