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 { definePlugin, defineView } from '@jaspers-ai/sdk' |
| 2 | import { z } from 'zod' |
| 3 | import { barSources } from './stocks-bars' |
| 4 | import { snapSources } from './stocks-snap' |
| 5 | import { tickSources } from './ticks' |
| 6 | import { referenceSources } from './reference' |
| 7 | import { news } from './news' |
| 8 | import { financials } from './financials' |
| 9 | import { optionSources } from './options' |
| 10 | import { globalSources } from './global' |
| 11 | import { indicator } from './indicators' |
| 12 | import { selfCheck } from './selfcheck' |
| 13 | import { NewsView } from './NewsView' |
| 14 | import { PriceView } from './PriceView' |
| 15 | import { WatchlistView } from './WatchlistView' |
| 16 | import { ChainView } from './ChainView' |
| 17 | |
| 18 | const sources = { |
| 19 | ...barSources, |
| 20 | ...snapSources, |
| 21 | ...tickSources, |
| 22 | ...referenceSources, |
| 23 | news, |
| 24 | financials, |
| 25 | ...optionSources, |
| 26 | ...globalSources, |
| 27 | indicator, |
| 28 | 'self-check': selfCheck, |
| 29 | } |
| 30 | |
| 31 | export default definePlugin({ |
| 32 | id: 'massive', |
| 33 | secrets: { apikey: { label: 'Massive (Polygon.io) API key' } }, |
| 34 | sources, |
| 35 | views: { |
| 36 | watchlist: defineView(WatchlistView, { |
| 37 | title: 'Massive watchlist', |
| 38 | state: z.object({ |
| 39 | tickers: z.array(z.string()).max(100).default(['AAPL', 'MSFT', 'NVDA']).describe('Stock tickers to show.'), |
| 40 | }), |
| 41 | output: z.object({ tickers: z.array(z.string()), count: z.number(), error: z.string().nullable() }), |
| 42 | instructions: 'A snapshot table of stocks: last, change, change %, volume. Set state.tickers to the tickers; the user refreshes it with its button.', |
| 43 | renders: [snapSources.snapshot], |
| 44 | summarize: (state, output) => `Watchlist: ${output.count} of ${state.tickers?.length ?? 0} tickers`, |
| 45 | }), |
| 46 | chart: defineView(PriceView, { |
| 47 | title: 'Massive price chart', |
| 48 | state: z.object({ |
| 49 | ticker: z.string().default('AAPL').describe('Any ticker: AAPL, O:..., I:SPX, C:EURUSD, X:BTCUSD.'), |
| 50 | multiplier: z.number().int().min(1).default(1).describe('Timespans per bar.'), |
| 51 | timespan: z.enum(['minute', 'hour', 'day', 'week', 'month', 'quarter', 'year']).default('day').describe('Bar size.'), |
| 52 | from: z.string().optional().describe('Start date YYYY-MM-DD. Defaults to six months ago.'), |
| 53 | to: z.string().optional().describe('End date YYYY-MM-DD. Defaults to today.'), |
| 54 | style: z.enum(['candles', 'line']).default('candles').describe('Candlesticks or a close line.'), |
| 55 | }), |
| 56 | output: z.object({ ticker: z.string(), bars: z.number(), first: z.string().nullable(), last: z.string().nullable(), close: z.number().nullable(), error: z.string().nullable() }), |
| 57 | instructions: 'A candlestick or line chart with volume bars from Massive aggregates. Set state.ticker, and optionally multiplier, timespan, from, to, style.', |
| 58 | renders: [barSources.aggregates], |
| 59 | summarize: (state, output) => `${state.ticker ?? 'AAPL'} chart: ${output.bars} bars, last close ${output.close ?? '–'}`, |
| 60 | }), |
| 61 | chain: defineView(ChainView, { |
| 62 | title: 'Massive option chain', |
| 63 | state: z.object({ |
| 64 | underlying: z.string().default('SPY').describe('The underlying ticker.'), |
| 65 | expiration: z.string().optional().describe('Expiration YYYY-MM-DD. Defaults to the nearest one.'), |
| 66 | strike_min: z.number().optional().describe('Lowest strike shown.'), |
| 67 | strike_max: z.number().optional().describe('Highest strike shown.'), |
| 68 | }), |
| 69 | output: z.object({ underlying: z.string(), expiration: z.string().nullable(), strikes: z.number(), underlyingPrice: z.number().nullable(), error: z.string().nullable() }), |
| 70 | instructions: 'Calls and puts side by side by strike for one underlying and expiration. Set state.underlying, state.expiration, and a strike range.', |
| 71 | renders: [optionSources['option-chain']], |
| 72 | summarize: (state, output) => `${state.underlying ?? 'SPY'} chain ${output.expiration ?? ''}: ${output.strikes} strikes`, |
| 73 | }), |
| 74 | news: defineView(NewsView, { |
| 75 | title: 'Massive news', |
| 76 | state: z.object({ |
| 77 | tickers: z.array(z.string()).max(20).default(['AAPL']).describe('Tickers whose news to list.'), |
| 78 | limit: z.number().int().min(1).max(200).default(50).describe('How many articles.'), |
| 79 | }), |
| 80 | output: z.object({ tickers: z.array(z.string()), count: z.number(), latest: z.string().nullable(), error: z.string().nullable() }), |
| 81 | instructions: 'Ticker news from Massive, newest first, with publisher, time, link, summary, and sentiment. Set state.tickers and state.limit.', |
| 82 | renders: [news], |
| 83 | summarize: (state, output) => `News for ${(state.tickers ?? []).join(', ')}: ${output.count} articles`, |
| 84 | }), |
| 85 | }, |
| 86 | }) |