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, iso, list, upper, type Params } from './client' |
| 4 | |
| 5 | // Tick data: trades and quotes for a stock or option ticker, newest first. |
| 6 | |
| 7 | const input = z.object({ |
| 8 | ticker: z.string().min(1).describe('A stock ticker like AAPL, or an option like O:SPY251219C00600000.'), |
| 9 | date: z.string().optional().describe('One day, YYYY-MM-DD. Leave out to use the timestamp bounds or the latest data.'), |
| 10 | from: z.string().optional().describe('Earliest timestamp, ISO date-time or nanoseconds (timestamp.gte).'), |
| 11 | to: z.string().optional().describe('Latest timestamp, ISO date-time or nanoseconds (timestamp.lte).'), |
| 12 | order: z.enum(['asc', 'desc']).default('desc').describe('desc for newest first.'), |
| 13 | limit: z.number().int().min(1).max(50000).default(1000).describe('Most rows to answer.'), |
| 14 | base: baseField, |
| 15 | }) |
| 16 | |
| 17 | type Args = z.infer<typeof input> |
| 18 | |
| 19 | function params(args: Args): Params { |
| 20 | return { |
| 21 | timestamp: args.date, |
| 22 | 'timestamp.gte': args.from, |
| 23 | 'timestamp.lte': args.to, |
| 24 | order: args.order, |
| 25 | sort: 'timestamp', |
| 26 | limit: Math.min(args.limit, 50000), |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | const joined = (v: unknown) => (Array.isArray(v) ? v.join(', ') : null) |
| 31 | |
| 32 | const trades = defineSource({ |
| 33 | description: 'Trades for a ticker: time, price, size, exchange, conditions, tape, sequence number. Newest first.', |
| 34 | hosts: HOSTS, |
| 35 | input, |
| 36 | async run(args, ctx) { |
| 37 | const t = upper(args.ticker) |
| 38 | const res = await list(ctx, args.base, `/v3/trades/${t}`, params(args), args.limit) |
| 39 | const rows = res.rows.map((r) => ({ |
| 40 | ticker: t, |
| 41 | time: iso(r.sip_timestamp ?? r.participant_timestamp), |
| 42 | price: r.price ?? null, |
| 43 | size: r.size ?? null, |
| 44 | exchange: r.exchange ?? null, |
| 45 | conditions: joined(r.conditions), |
| 46 | tape: r.tape ?? null, |
| 47 | sequence_number: r.sequence_number ?? null, |
| 48 | id: r.id ?? null, |
| 49 | })) |
| 50 | return { rows, more: res.more, pages: res.pages } |
| 51 | }, |
| 52 | }) |
| 53 | |
| 54 | const quotes = defineSource({ |
| 55 | description: 'NBBO quotes for a ticker: time, bid, bid size, ask, ask size, exchanges, conditions. Newest first.', |
| 56 | hosts: HOSTS, |
| 57 | input, |
| 58 | async run(args, ctx) { |
| 59 | const t = upper(args.ticker) |
| 60 | const res = await list(ctx, args.base, `/v3/quotes/${t}`, params(args), args.limit) |
| 61 | const rows = res.rows.map((r) => ({ |
| 62 | ticker: t, |
| 63 | time: iso(r.sip_timestamp ?? r.participant_timestamp), |
| 64 | bid: r.bid_price ?? null, |
| 65 | bid_size: r.bid_size ?? null, |
| 66 | bid_exchange: r.bid_exchange ?? null, |
| 67 | ask: r.ask_price ?? null, |
| 68 | ask_size: r.ask_size ?? null, |
| 69 | ask_exchange: r.ask_exchange ?? null, |
| 70 | conditions: joined(r.conditions), |
| 71 | tape: r.tape ?? null, |
| 72 | sequence_number: r.sequence_number ?? null, |
| 73 | })) |
| 74 | return { rows, more: res.more, pages: res.pages } |
| 75 | }, |
| 76 | }) |
| 77 | |
| 78 | export const tickSources = { trades, quotes } |