Jaspers Hub

jaspers / treasury

pluginOfficialReviewed★ 0↓ 3

US Treasury Fiscal Data: Pulls average Treasury interest rates, the daily debt to the penny, auction results, and federal spending by agency from the US Treasury's Fiscal Data API. No key needed.

3.6 KB
1import { defineSource } from '@jaspers-ai/sdk'
2import { z } from 'zod'
3
4
5// The US Treasury's Fiscal Data API. No key, no account, no limit published: the government's own
6// numbers for what it owes and what it pays to borrow.
7
8const HOST = 'api.fiscaldata.treasury.gov'
9const BASE = `https://${HOST}/services/api/fiscal_service`
10
11/** Every dataset here answers the same way, so one reader serves them all. */
12async function table(
13 ctx: { fetch: typeof fetch },
14 path: string,
15 { limit, filter, sort = '-record_date' }: { limit: number; filter?: string; sort?: string },
16): Promise<Record<string, unknown>[]> {
17 const query = new URLSearchParams({ sort, 'page[size]': String(Math.min(limit, 10000)) })
18 if (filter) query.set('filter', filter)
19 const response = await ctx.fetch(`${BASE}${path}?${query.toString()}`)
20 if (!response.ok) throw new Error(`Fiscal Data answered ${response.status}.`)
21 const body = (await response.json()) as { data?: Record<string, unknown>[]; error?: string }
22 if (!body.data) throw new Error(body.error ?? 'Fiscal Data answered with no rows.')
23 // Everything arrives as strings; anything that reads as a number becomes one, so it can be charted.
24 return body.data.map((row) => {
25 const out: Record<string, unknown> = {}
26 for (const [key, value] of Object.entries(row)) {
27 const numeric = typeof value === 'string' && value !== '' && Number.isFinite(Number(value)) && !key.endsWith('_date')
28 out[key] = numeric ? Number(value) : value
29 }
30 return out
31 })
32}
33
34const from = z.string().optional().describe('Earliest record date, YYYY-MM-DD.')
35const limit = z.number().int().min(1).max(10000).default(120)
36
37export const rates = defineSource({
38 description:
39 'The average interest rate the US Treasury pays, by security, month by month. What the government actually pays to borrow, as opposed to what the market quotes.',
40 hosts: [HOST],
41 input: z.object({ security: z.string().optional().describe('One security, like Treasury Bills, Treasury Notes, or Treasury Bonds.'), from, limit }),
42 async run({ security, from: start, limit: take }, ctx) {
43 const parts = [start ? `record_date:gte:${start}` : '', security ? `security_desc:eq:${security}` : ''].filter(Boolean)
44 return { rows: await table(ctx, '/v2/accounting/od/avg_interest_rates', { limit: take, filter: parts.join(',') || undefined }) }
45 },
46})
47
48export const debt = defineSource({
49 description: 'The total US public debt, to the penny, by day: what is held by the public, what is held inside government, and the total.',
50 hosts: [HOST],
51 input: z.object({ from, limit }),
52 async run({ from: start, limit: take }, ctx) {
53 return { rows: await table(ctx, '/v2/accounting/od/debt_to_penny', { limit: take, filter: start ? `record_date:gte:${start}` : undefined }) }
54 },
55})
56
57export const auctions = defineSource({
58 description: 'Treasury securities as they were auctioned: the term, the issue and maturity dates, the rate, and the amount. Where new supply comes from.',
59 hosts: [HOST],
60 input: z.object({ from, limit }),
61 async run({ from: start, limit: take }, ctx) {
62 return { rows: await table(ctx, '/v1/accounting/od/auctions_query', { limit: take, filter: start ? `auction_date:gte:${start}` : undefined, sort: '-auction_date' }) }
63 },
64})
65
66export const spending = defineSource({
67 description: "Federal spending by agency for a fiscal year, from the Monthly Treasury Statement: where the money went.",
68 hosts: [HOST],
69 input: z.object({ from, limit: z.number().int().min(1).max(10000).default(200) }),
70 async run({ from: start, limit: take }, ctx) {
71 return { rows: await table(ctx, '/v1/accounting/mts/mts_table_5', { limit: take, filter: start ? `record_date:gte:${start}` : undefined }) }
72 },
73})