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.
| 1 | import { defineSource } from '@jaspers-ai/sdk' |
| 2 | import { z } from 'zod' |
| 3 | import { HOSTS, baseField, flatten, get, list, upper } from './client' |
| 4 | |
| 5 | // Reference data: tickers, one ticker's details, dividends, splits, exchanges, conditions, market hours. |
| 6 | |
| 7 | const limit = (d: number) => z.number().int().min(1).max(10000).default(d).describe('Most rows to answer.') |
| 8 | const page = (max: number) => Math.min(max, 1000) |
| 9 | const opt = (s?: string) => (s ? upper(s) : undefined) |
| 10 | |
| 11 | const 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 | |
| 48 | const 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 | |
| 62 | const 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 | |
| 102 | const 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 | |
| 138 | const 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 | |
| 151 | const 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 | |
| 172 | const 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 | |
| 181 | const 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 | |
| 192 | export 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 | } |