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, get, iso, type Params } from './client' |
| 4 | |
| 5 | // Technical indicators Massive computes: SMA, EMA, RSI, MACD, newest first. |
| 6 | |
| 7 | export const indicator = defineSource({ |
| 8 | description: |
| 9 | 'A technical indicator for any ticker, newest first: time (ISO) and value; MACD adds signal and histogram. SMA, EMA, RSI, or MACD over day/hour/minute bars.', |
| 10 | hosts: HOSTS, |
| 11 | input: z.object({ |
| 12 | ticker: z.string().min(1).describe('A ticker of any asset class, like AAPL or X:BTCUSD.'), |
| 13 | indicator: z.enum(['sma', 'ema', 'rsi', 'macd']).default('sma').describe('sma, ema, rsi, or macd.'), |
| 14 | timespan: z.enum(['minute', 'hour', 'day', 'week', 'month', 'quarter', 'year']).default('day').describe('The bar size.'), |
| 15 | window: z.number().int().min(1).default(14).describe('The window for sma, ema, rsi, like 50 for a 50-day SMA.'), |
| 16 | short_window: z.number().int().min(1).default(12).describe('MACD short EMA window.'), |
| 17 | long_window: z.number().int().min(1).default(26).describe('MACD long EMA window.'), |
| 18 | signal_window: z.number().int().min(1).default(9).describe('MACD signal window.'), |
| 19 | series_type: z.enum(['open', 'high', 'low', 'close']).default('close').describe('Which price to compute on.'), |
| 20 | from: z.string().optional().describe('Earliest date, YYYY-MM-DD.'), |
| 21 | to: z.string().optional().describe('Latest date, YYYY-MM-DD.'), |
| 22 | adjusted: z.boolean().default(true).describe('Adjust for splits.'), |
| 23 | limit: z.number().int().min(1).max(5000).default(250).describe('Most values to answer.'), |
| 24 | base: baseField, |
| 25 | }), |
| 26 | async run(args, ctx) { |
| 27 | const t = args.ticker.trim().toUpperCase() |
| 28 | const windows: Params = |
| 29 | args.indicator === 'macd' |
| 30 | ? { short_window: args.short_window, long_window: args.long_window, signal_window: args.signal_window } |
| 31 | : { window: args.window } |
| 32 | const body = await get(ctx, args.base, `/v1/indicators/${args.indicator}/${t}`, { |
| 33 | timespan: args.timespan, |
| 34 | series_type: args.series_type, |
| 35 | adjusted: args.adjusted, |
| 36 | 'timestamp.gte': args.from, |
| 37 | 'timestamp.lte': args.to, |
| 38 | order: 'desc', |
| 39 | limit: args.limit, |
| 40 | ...windows, |
| 41 | }) |
| 42 | const values = (body?.results?.values ?? []) as any[] |
| 43 | return values.map((v) => ({ |
| 44 | ticker: t, |
| 45 | indicator: args.indicator, |
| 46 | time: iso(v.timestamp), |
| 47 | value: v.value ?? null, |
| 48 | ...(args.indicator === 'macd' ? { signal: v.signal ?? null, histogram: v.histogram ?? null } : {}), |
| 49 | })) |
| 50 | }, |
| 51 | }) |