Skill Tracer
Skills › Scientific Agent Skills › usfiscaldata › examples.md

examples.md

220 lines · skills/usfiscaldata/references/examples.md at 5f2bc03

Open on GitHub
1# Code Examples — U.S. Treasury Fiscal Data
2
3Python queries and transformations below were exercised against the public API on
42026-09-30. First define `fetch_all()` from [parameters.md](parameters.md), then run
5the setup. Historic dates are fixed examples, not claims about the current year.
6

Code Examples — U.S. Treasury Fiscal Data

Python queries and transformations below were exercised against the public API on 2026-09-30. First define fetch_all() from parameters.md, then run the setup. Historic dates are fixed examples, not claims about the current year.

Raw lines 1 to 6
7## Setup
8
9```python
10from datetime import date
11from decimal import Decimal
12import requests
13import pandas as pd
15BASE_URL = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"
17def fetch(endpoint, **params):
18 """Fetch one page; callers requesting a complete result use fetch_all."""
19 allowed = {"fields", "filter", "sort", "format", "page[size]", "page[number]"}
20 if set(params) - allowed:
21 raise ValueError(f"Unknown query parameters: {set(params) - allowed}")
22 resp = requests.get(BASE_URL + endpoint, params=params, timeout=30)
23 resp.raise_for_status()
24 result = resp.json()
25 if "error" in result:
26 raise ValueError(result)
27 return result
28```

Setup

from datetime import date
from decimal import Decimal
import requests
import pandas as pd

BASE_URL = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"

def fetch(endpoint, **params):
    """Fetch one page; callers requesting a complete result use fetch_all."""
    allowed = {"fields", "filter", "sort", "format", "page[size]", "page[number]"}
    if set(params) - allowed:
        raise ValueError(f"Unknown query parameters: {set(params) - allowed}")
    resp = requests.get(BASE_URL + endpoint, params=params, timeout=30)
    resp.raise_for_status()
    result = resp.json()
    if "error" in result:
        raise ValueError(result)
    return result
Raw lines 7 to 29
30## National Debt Tracker
32```python
33result = fetch("/v2/accounting/od/debt_to_penny",
34 sort="-record_date", **{"page[size]": 1})
35d = result["data"][0]
36debt = Decimal(d["tot_pub_debt_out_amt"])
37print(f"National debt as of {d['record_date']}: ${debt:,.2f}")
39# Complete fixed-period series; cents remain in raw strings if needed.
40df = fetch_all("/v2/accounting/od/debt_to_penny", {
41 "filter": "record_date:gte:2024-01-01,record_date:lte:2024-12-31",
42 "sort": "record_date", "page[size]": 100,
43})
44df["date"] = pd.to_datetime(df["record_date"])
45df["debt_trillion"] = pd.to_numeric(df["tot_pub_debt_out_amt"]) / 1e12
46print(df[["date", "debt_trillion"]].tail())
47```

National Debt Tracker

result = fetch("/v2/accounting/od/debt_to_penny",
               sort="-record_date", **{"page[size]": 1})
d = result["data"][0]
debt = Decimal(d["tot_pub_debt_out_amt"])
print(f"National debt as of {d['record_date']}: ${debt:,.2f}")

# Complete fixed-period series; cents remain in raw strings if needed.
df = fetch_all("/v2/accounting/od/debt_to_penny", {
    "filter": "record_date:gte:2024-01-01,record_date:lte:2024-12-31",
    "sort": "record_date", "page[size]": 100,
})
df["date"] = pd.to_datetime(df["record_date"])
df["debt_trillion"] = pd.to_numeric(df["tot_pub_debt_out_amt"]) / 1e12
print(df[["date", "debt_trillion"]].tail())
Raw lines 30 to 48
49## Treasury Reporting Exchange Rates
51```python
52endpoint = "/v1/accounting/od/rates_of_exchange"
53quarter = fetch(endpoint, sort="-record_date", **{"page[size]": 1})["data"][0]["record_date"]
54rates = fetch_all(endpoint, {
55 "filter": f"record_date:eq:{quarter}",
56 "sort": "country_currency_desc,effective_date,src_line_nbr",
57 "page[size]": 100,
58})
59rates["exchange_rate"] = pd.to_numeric(rates["exchange_rate"])
60# Preserve amendments as separate rows; pick the applicable reporting period first.
61rates["usd_1000_in_foreign_currency"] = 1000 * rates["exchange_rate"]
62print(rates[["country_currency_desc", "record_date", "effective_date",
63 "exchange_rate", "usd_1000_in_foreign_currency"]].head())
64```
66These are foreign-currency units per USD. Divide a foreign amount by its applicable
67rate to obtain USD. Amendments have later `effective_date` values; quarterly PDF
68reports omit amendments, so do not collapse rows without the official period rules.

Treasury Reporting Exchange Rates

endpoint = "/v1/accounting/od/rates_of_exchange"
quarter = fetch(endpoint, sort="-record_date", **{"page[size]": 1})["data"][0]["record_date"]
rates = fetch_all(endpoint, {
    "filter": f"record_date:eq:{quarter}",
    "sort": "country_currency_desc,effective_date,src_line_nbr",
    "page[size]": 100,
})
rates["exchange_rate"] = pd.to_numeric(rates["exchange_rate"])
# Preserve amendments as separate rows; pick the applicable reporting period first.
rates["usd_1000_in_foreign_currency"] = 1000 * rates["exchange_rate"]
print(rates[["country_currency_desc", "record_date", "effective_date",
             "exchange_rate", "usd_1000_in_foreign_currency"]].head())

These are foreign-currency units per USD. Divide a foreign amount by its applicable rate to obtain USD. Amendments have later effective_date values; quarterly PDF reports omit amendments, so do not collapse rows without the official period rules.

Raw lines 49 to 69
70## Treasury Securities Auction Analysis
72```python
73# Nominal fixed-rate 10-year notes. auction_date dates the event.
74result = fetch("/v1/accounting/od/auctions_query",
75 filter="security_type:eq:Note,original_security_term:eq:10-Year,inflation_index_security:eq:No,floating_rate:eq:No",
76 sort="-auction_date,cusip", **{"page[size]": 20})
77auctions = pd.DataFrame(result["data"])
78for col in ["high_yield", "bid_to_cover_ratio", "total_accepted", "indirect_bidder_accepted"]:
79 auctions[col] = pd.to_numeric(auctions[col].replace("null", None), errors="coerce")
80auctions["indirect_pct_of_total"] = (
81 100 * auctions["indirect_bidder_accepted"] / auctions["total_accepted"].where(auctions["total_accepted"] > 0)
83print(auctions[["auction_date", "cusip", "security_term", "reopening",
84 "high_yield", "indirect_pct_of_total"]].head())
85```
87`original_security_term` includes reopened securities whose remaining
88`security_term` is shorter. Name the denominator when reporting bidder shares;
89`total_accepted` is not the same as competitive awards. Missing yields can mean an
90auction has been announced but results are unavailable. Auction yields observed on
91different dates do not form a same-date yield curve; do not inner-join 2-year and
9210-year auctions on publication dates and label the difference a market spread.

Treasury Securities Auction Analysis

# Nominal fixed-rate 10-year notes. auction_date dates the event.
result = fetch("/v1/accounting/od/auctions_query",
    filter="security_type:eq:Note,original_security_term:eq:10-Year,inflation_index_security:eq:No,floating_rate:eq:No",
    sort="-auction_date,cusip", **{"page[size]": 20})
auctions = pd.DataFrame(result["data"])
for col in ["high_yield", "bid_to_cover_ratio", "total_accepted", "indirect_bidder_accepted"]:
    auctions[col] = pd.to_numeric(auctions[col].replace("null", None), errors="coerce")
auctions["indirect_pct_of_total"] = (
    100 * auctions["indirect_bidder_accepted"] / auctions["total_accepted"].where(auctions["total_accepted"] > 0)
)
print(auctions[["auction_date", "cusip", "security_term", "reopening",
                "high_yield", "indirect_pct_of_total"]].head())

original_security_term includes reopened securities whose remaining security_term is shorter. Name the denominator when reporting bidder shares; total_accepted is not the same as competitive awards. Missing yields can mean an auction has been announced but results are unavailable. Auction yields observed on different dates do not form a same-date yield curve; do not inner-join 2-year and 10-year auctions on publication dates and label the difference a market spread.

Raw lines 70 to 93
94## Daily Treasury Statement
96```python
97endpoint = "/v1/accounting/dts/operating_cash_balance"
98closing = fetch(endpoint,
99 filter="account_type:eq:Treasury General Account (TGA) Closing Balance",
100 sort="-record_date", **{"page[size]": 5})
101for row in closing["data"]:
102 print(row["record_date"], Decimal(row["open_today_bal"]), "million USD, closing TGA")
104# Named totals avoid adding category detail to summary rows.
105cash = fetch_all(endpoint, {
106 "filter": "record_date:gte:2024-01-01,record_date:lte:2024-01-31",
107 "sort": "record_date,src_line_nbr",
108})
109cash = cash[cash["account_type"].isin([
110 "Total TGA Deposits (Table II)", "Total TGA Withdrawals (Table II) (-)",
111])].copy()
112cash["million_usd"] = pd.to_numeric(cash["open_today_bal"])
113print(cash.pivot(index="record_date", columns="account_type", values="million_usd"))
114```
116Since April 18, 2022, `close_today_bal` is null. The closing-balance account row
117stores its value in `open_today_bal`. Earlier layouts need separate handling.
118DTS cash movements include financing and differ from MTS budget receipts/outlays.

Daily Treasury Statement

endpoint = "/v1/accounting/dts/operating_cash_balance"
closing = fetch(endpoint,
    filter="account_type:eq:Treasury General Account (TGA) Closing Balance",
    sort="-record_date", **{"page[size]": 5})
for row in closing["data"]:
    print(row["record_date"], Decimal(row["open_today_bal"]), "million USD, closing TGA")

# Named totals avoid adding category detail to summary rows.
cash = fetch_all(endpoint, {
    "filter": "record_date:gte:2024-01-01,record_date:lte:2024-01-31",
    "sort": "record_date,src_line_nbr",
})
cash = cash[cash["account_type"].isin([
    "Total TGA Deposits (Table II)", "Total TGA Withdrawals (Table II) (-)",
])].copy()
cash["million_usd"] = pd.to_numeric(cash["open_today_bal"])
print(cash.pivot(index="record_date", columns="account_type", values="million_usd"))

Since April 18, 2022, close_today_bal is null. The closing-balance account row stores its value in open_today_bal. Earlier layouts need separate handling. DTS cash movements include financing and differ from MTS budget receipts/outlays.

Raw lines 94 to 119
120## Monthly Budget Summary
122```python
123budget = fetch_all("/v1/accounting/mts/mts_receipts_outlays_deficit_surplus", {
124 "filter": "record_fiscal_year:eq:2024",
125 "sort": "record_date,src_line_nbr",
126})
127budget = budget[budget["amt_category"].isin(["Receipts", "Outlays", "Deficit/Surplus (-)"])].copy()
128budget["million_usd"] = pd.to_numeric(budget["mil_amt"])
129monthly = budget.pivot(index="record_date", columns="amt_category", values="million_usd")
130assert len(monthly) == 12, "Fiscal year is incomplete"
131# Published values are rounded to millions; allow rounding differences.
132residual = monthly["Outlays"] - monthly["Receipts"] - monthly["Deficit/Surplus (-)"]
133if (residual.abs() > 1).any():
134 print("[WARN] Reconcile source revisions/footnotes before using these months:")
135 print(residual[residual.abs() > 1])
136print(monthly)
137```
139The live FY2024 extract on the review date had a March 2024 reconciliation
140residual of -270 million USD, beyond rounding. This example exposes that source
141discrepancy; it does not treat the series as reconciled or overwrite the published
142values. Check the matching report/revisions before drawing budget conclusions.
144This summary has explicit million-dollar units. Tables 1 and 9 have different
145fields and dollar-scale API values; Table 1 repeats prior months and fiscal-year
146sections in each publication. Never add all Table 1 rows to obtain monthly totals.

Monthly Budget Summary

budget = fetch_all("/v1/accounting/mts/mts_receipts_outlays_deficit_surplus", {
    "filter": "record_fiscal_year:eq:2024",
    "sort": "record_date,src_line_nbr",
})
budget = budget[budget["amt_category"].isin(["Receipts", "Outlays", "Deficit/Surplus (-)"])].copy()
budget["million_usd"] = pd.to_numeric(budget["mil_amt"])
monthly = budget.pivot(index="record_date", columns="amt_category", values="million_usd")
assert len(monthly) == 12, "Fiscal year is incomplete"
# Published values are rounded to millions; allow rounding differences.
residual = monthly["Outlays"] - monthly["Receipts"] - monthly["Deficit/Surplus (-)"]
if (residual.abs() > 1).any():
    print("[WARN] Reconcile source revisions/footnotes before using these months:")
    print(residual[residual.abs() > 1])
print(monthly)

The live FY2024 extract on the review date had a March 2024 reconciliation residual of -270 million USD, beyond rounding. This example exposes that source discrepancy; it does not treat the series as reconciled or overwrite the published values. Check the matching report/revisions before drawing budget conclusions.

This summary has explicit million-dollar units. Tables 1 and 9 have different fields and dollar-scale API values; Table 1 repeats prior months and fiscal-year sections in each publication. Never add all Table 1 rows to obtain monthly totals.

Raw lines 120 to 147
148## Average Treasury and I Bond Rates
150```python
151rates = fetch_all("/v2/accounting/od/avg_interest_rates", {
152 "filter": "security_type_desc:eq:Marketable,record_date:gte:2024-01-01,record_date:lte:2024-12-31",
153 "sort": "record_date,src_line_nbr",
154})
155rates["rate_pct"] = pd.to_numeric(rates["avg_interest_rate_amt"])
156print(rates.pivot(index="record_date", columns="security_desc", values="rate_pct"))
158# One issue vintage and a fixed earning-period cutoff, not a universal I Bond rate.
159issue_month = "2024-05"
160bonds = fetch("/v1/accounting/od/i_bonds_interest_rates",
161 filter=f"issue_year_month:eq:{issue_month},earning_period_start:lte:2024-11-01",
162 sort="-earning_period_start", **{"page[size]": 1})
163print(pd.DataFrame(bonds["data"])[["issue_year_month", "earning_period_start",
164 "earning_period_end", "fixed_rate", "combined_rate"]])
165```
167Average interest rates describe the outstanding debt portfolio, not current
168market yields. I Bond fixed rates depend on issue vintage; the earning-period
169columns and issue month must be retained together.

Average Treasury and I Bond Rates

rates = fetch_all("/v2/accounting/od/avg_interest_rates", {
    "filter": "security_type_desc:eq:Marketable,record_date:gte:2024-01-01,record_date:lte:2024-12-31",
    "sort": "record_date,src_line_nbr",
})
rates["rate_pct"] = pd.to_numeric(rates["avg_interest_rate_amt"])
print(rates.pivot(index="record_date", columns="security_desc", values="rate_pct"))

# One issue vintage and a fixed earning-period cutoff, not a universal I Bond rate.
issue_month = "2024-05"
bonds = fetch("/v1/accounting/od/i_bonds_interest_rates",
    filter=f"issue_year_month:eq:{issue_month},earning_period_start:lte:2024-11-01",
    sort="-earning_period_start", **{"page[size]": 1})
print(pd.DataFrame(bonds["data"])[["issue_year_month", "earning_period_start",
                                  "earning_period_end", "fixed_rate", "combined_rate"]])

Average interest rates describe the outstanding debt portfolio, not current market yields. I Bond fixed rates depend on issue vintage; the earning-period columns and issue month must be retained together.

Raw lines 148 to 170
171## Completed Fiscal-Year Interest Expense
173```python
174fy = 2024
175expenses = fetch_all("/v2/accounting/od/interest_expense", {
176 "filter": f"record_fiscal_year:eq:{fy}",
177 "sort": "record_date,src_line_nbr",
178})
179assert expenses["record_date"].nunique() == 12, "Fiscal year is incomplete"
180assert expenses["record_date"].max() == f"{fy}-09-30"
181assert not expenses.duplicated(["record_date", "src_line_nbr"]).any()
182monthly_total = sum(Decimal(x) for x in expenses["month_expense_amt"])
183september = expenses[expenses["record_date"] == f"{fy}-09-30"]
184fytd_total = sum(Decimal(x) for x in september["fytd_expense_amt"])
185assert abs(monthly_total - fytd_total) <= Decimal("0.01"), "Reconcile revisions/components"
186print(f"FY{fy} public-debt interest expense: ${fytd_total:,.2f}")
187```
189This uses the expense dataset's components and accounting basis, not budget net
190interest. Sum monthly flows once, or take September FYTD once; never sum FYTD
191values across months. Preserve category/group/type fields to inspect components.

Completed Fiscal-Year Interest Expense

fy = 2024
expenses = fetch_all("/v2/accounting/od/interest_expense", {
    "filter": f"record_fiscal_year:eq:{fy}",
    "sort": "record_date,src_line_nbr",
})
assert expenses["record_date"].nunique() == 12, "Fiscal year is incomplete"
assert expenses["record_date"].max() == f"{fy}-09-30"
assert not expenses.duplicated(["record_date", "src_line_nbr"]).any()
monthly_total = sum(Decimal(x) for x in expenses["month_expense_amt"])
september = expenses[expenses["record_date"] == f"{fy}-09-30"]
fytd_total = sum(Decimal(x) for x in september["fytd_expense_amt"])
assert abs(monthly_total - fytd_total) <= Decimal("0.01"), "Reconcile revisions/components"
print(f"FY{fy} public-debt interest expense: ${fytd_total:,.2f}")

This uses the expense dataset's components and accounting basis, not budget net interest. Sum monthly flows once, or take September FYTD once; never sum FYTD values across months. Preserve category/group/type fields to inspect components.

Raw lines 171 to 192
193## R example (illustrative; R runtime not exercised)
195```r
196library(httr)
197library(jsonlite)
198base <- "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"
199response <- GET(paste0(base, "/v1/accounting/mts/mts_table_9"),
200 query = list(filter = "line_code_nbr:eq:120",
201 sort = "-record_date", `page[size]` = 1),
202 timeout(30))
203stop_for_status(response)
204result <- fromJSON(rawToChar(response$content))
205stopifnot(nrow(result$data) == 1)
206print(result$data[c("record_date", "classification_desc", "current_month_rcpt_outly_amt")])
207```

R example (illustrative; R runtime not exercised)

library(httr)
library(jsonlite)
base <- "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"
response <- GET(paste0(base, "/v1/accounting/mts/mts_table_9"),
                query = list(filter = "line_code_nbr:eq:120",
                             sort = "-record_date", `page[size]` = 1),
                timeout(30))
stop_for_status(response)
result <- fromJSON(rawToChar(response$content))
stopifnot(nrow(result$data) == 1)
print(result$data[c("record_date", "classification_desc", "current_month_rcpt_outly_amt")])
Raw lines 193 to 208
209## Discovering fields and datasets
211```python
212result = fetch("/v2/accounting/od/debt_to_penny", **{"page[size]": 1})
213for field, label in result["meta"]["labels"].items():
214 print(field, result["meta"]["dataTypes"][field], label)
215```
217Use the [dataset catalog](https://fiscaldata.treasury.gov/datasets/) and each
218API Quick Guide/data dictionary for current paths, table coverage, units and
219limitations. The [API guide](https://fiscaldata.treasury.gov/api-documentation/)
220documents common filters, pagination and response metadata.

Discovering fields and datasets

result = fetch("/v2/accounting/od/debt_to_penny", **{"page[size]": 1})
for field, label in result["meta"]["labels"].items():
    print(field, result["meta"]["dataTypes"][field], label)

Use the dataset catalog and each API Quick Guide/data dictionary for current paths, table coverage, units and limitations. The API guide documents common filters, pagination and response metadata.

Raw lines 209 to 220