Jaspers Hub

biseroff / massive

pluginReviewed★ 0↓ 4

Massive Market Data (Polygon.io): Market data plugin wrapping the Polygon.io/Massive REST API: bars, snapshots, options, news, financials, indicators, and four chart/watchlist views.

7 KB
1import { defineSource } from '@jaspers-ai/sdk'
2import { z } from 'zod'
3import { HOSTS, baseField, flatten, get, list, upper } from './client'
4
5// Reference data: tickers, one ticker's details, dividends, splits, exchanges, conditions, market hours.
6
7const limit = (d: number) => z.number().int().min(1).max(10000).default(d).describe('Most rows to answer.')
8const page = (max: number) => Math.min(max, 1000)
9const opt = (s?: string) => (s ? upper(s) : undefined)
10
11const tickers = defineSource({
12 description: 'Search or list tickers: ticker, name, market, type, primary exchange, active, currency, CIK, FIGI.',
13 hosts: HOSTS,
14 input: z.object({
15 search: z.string().optional().describe('Words in the ticker or company name, like apple.'),
16 ticker: z.string().optional().describe('One exact ticker.'),
17 market: z.enum(['stocks', 'crypto', 'fx', 'otc', 'indices']).optional().describe('The market.'),
18 type: z.string().optional().describe('A ticker type like CS (common stock), ETF, ADRC, INDEX.'),
19 active: z.boolean().default(true).describe('Only tickers trading now.'),
20 limit: limit(100),
21 base: baseField,
22 }),
23 async run(args, ctx) {
24 const res = await list(
25 ctx,
26 args.base,
27 '/v3/reference/tickers',
28 { search: args.search, ticker: opt(args.ticker), market: args.market, type: args.type, active: args.active, limit: page(args.limit) },
29 args.limit,
30 )
31 const rows = res.rows.map((r) => ({
32 ticker: r.ticker,
33 name: r.name ?? null,
34 market: r.market ?? null,
35 locale: r.locale ?? null,
36 type: r.type ?? null,
37 primary_exchange: r.primary_exchange ?? null,
38 active: r.active ?? null,
39 currency: r.currency_name ?? null,
40 cik: r.cik ?? null,
41 composite_figi: r.composite_figi ?? null,
42 last_updated: r.last_updated_utc ?? null,
43 }))
44 return { rows, more: res.more }
45 },
46})
47
48const tickerDetails = defineSource({
49 description: 'One ticker overview: name, description, market cap, employees, list date, SIC, shares outstanding, address, homepage, logo.',
50 hosts: HOSTS,
51 input: z.object({
52 ticker: z.string().min(1).describe('The ticker, like AAPL.'),
53 date: z.string().optional().describe('As of this date, YYYY-MM-DD. Leave out for now.'),
54 base: baseField,
55 }),
56 async run(args, ctx) {
57 const body = await get(ctx, args.base, `/v3/reference/tickers/${upper(args.ticker)}`, { date: args.date })
58 return body?.results ? [flatten(body.results)] : []
59 },
60})
61
62const dividends = defineSource({
63 description: 'Cash dividends, newest ex-date first: ticker, cash amount, currency, declaration, ex-dividend, record, pay dates, frequency, type.',
64 hosts: HOSTS,
65 input: z.object({
66 ticker: z.string().optional().describe('A ticker, like AAPL. Leave out for all.'),
67 from: z.string().optional().describe('Earliest ex-dividend date, YYYY-MM-DD.'),
68 to: z.string().optional().describe('Latest ex-dividend date, YYYY-MM-DD.'),
69 limit: limit(100),
70 base: baseField,
71 }),
72 async run(args, ctx) {
73 const res = await list(
74 ctx,
75 args.base,
76 '/v3/reference/dividends',
77 {
78 ticker: opt(args.ticker),
79 'ex_dividend_date.gte': args.from,
80 'ex_dividend_date.lte': args.to,
81 sort: 'ex_dividend_date',
82 order: 'desc',
83 limit: page(args.limit),
84 },
85 args.limit,
86 )
87 const rows = res.rows.map((r) => ({
88 ticker: r.ticker,
89 ex_dividend_date: r.ex_dividend_date ?? null,
90 cash_amount: r.cash_amount ?? null,
91 currency: r.currency ?? null,
92 declaration_date: r.declaration_date ?? null,
93 record_date: r.record_date ?? null,
94 pay_date: r.pay_date ?? null,
95 frequency: r.frequency ?? null,
96 dividend_type: r.dividend_type ?? null,
97 }))
98 return { rows, more: res.more }
99 },
100})
101
102const splits = defineSource({
103 description: 'Stock splits, newest first: ticker, execution date, split from, split to, ratio.',
104 hosts: HOSTS,
105 input: z.object({
106 ticker: z.string().optional().describe('A ticker, like AAPL. Leave out for all.'),
107 from: z.string().optional().describe('Earliest execution date, YYYY-MM-DD.'),
108 to: z.string().optional().describe('Latest execution date, YYYY-MM-DD.'),
109 limit: limit(100),
110 base: baseField,
111 }),
112 async run(args, ctx) {
113 const res = await list(
114 ctx,
115 args.base,
116 '/v3/reference/splits',
117 {
118 ticker: opt(args.ticker),
119 'execution_date.gte': args.from,
120 'execution_date.lte': args.to,
121 sort: 'execution_date',
122 order: 'desc',
123 limit: page(args.limit),
124 },
125 args.limit,
126 )
127 const rows = res.rows.map((r) => ({
128 ticker: r.ticker,
129 execution_date: r.execution_date ?? null,
130 split_from: r.split_from ?? null,
131 split_to: r.split_to ?? null,
132 ratio: r.split_from ? r.split_to / r.split_from : null,
133 }))
134 return { rows, more: res.more }
135 },
136})
137
138const exchanges = defineSource({
139 description: 'Exchanges Massive knows: id, name, acronym, MIC, type, asset class, locale, participant id.',
140 hosts: HOSTS,
141 input: z.object({
142 asset_class: z.enum(['stocks', 'options', 'crypto', 'fx']).optional().describe('Only this asset class.'),
143 base: baseField,
144 }),
145 async run(args, ctx) {
146 const body = await get(ctx, args.base, '/v3/reference/exchanges', { asset_class: args.asset_class })
147 return ((body?.results ?? []) as any[]).map((r) => flatten(r))
148 },
149})
150
151const conditions = defineSource({
152 description: 'Trade and quote condition codes: id, name, type, asset class, data types, SIP mapping, description.',
153 hosts: HOSTS,
154 input: z.object({
155 asset_class: z.enum(['stocks', 'options', 'crypto', 'fx']).optional().describe('Only this asset class.'),
156 data_type: z.enum(['trade', 'bbo', 'nbbo']).optional().describe('Only conditions for this data type.'),
157 limit: limit(1000),
158 base: baseField,
159 }),
160 async run(args, ctx) {
161 const res = await list(
162 ctx,
163 args.base,
164 '/v3/reference/conditions',
165 { asset_class: args.asset_class, data_type: args.data_type, limit: page(args.limit) },
166 args.limit,
167 )
168 return { rows: res.rows.map((r) => flatten(r)), more: res.more }
169 },
170})
171
172const marketStatus = defineSource({
173 description: 'Whether US markets are open now: market, early hours, after hours, each exchange, currencies, index groups, server time. One row.',
174 hosts: HOSTS,
175 input: z.object({ base: baseField }),
176 async run(args, ctx) {
177 return [flatten(await get(ctx, args.base, '/v1/marketstatus/now'))]
178 },
179})
180
181const marketHolidays = defineSource({
182 description: 'Upcoming market holidays and early closes: date, exchange, name, status, open and close times.',
183 hosts: HOSTS,
184 input: z.object({ base: baseField }),
185 async run(args, ctx) {
186 const body = await get(ctx, args.base, '/v1/marketstatus/upcoming')
187 const items = Array.isArray(body) ? body : (body?.results ?? [])
188 return (items as any[]).map((r) => flatten(r))
189 },
190})
191
192export const referenceSources = {
193 tickers,
194 'ticker-details': tickerDetails,
195 dividends,
196 splits,
197 exchanges,
198 conditions,
199 'market-status': marketStatus,
200 'market-holidays': marketHolidays,
201}