Options Chain: Shows a multi-vendor options chain straddle table with IV, delta, OI, volume, and max pain for a ticker.
| 1 | import { definePlugin, defineSource, defineView } from '@jaspers-ai/sdk' |
| 2 | import { z } from 'zod' |
| 3 | import { TableView } from './src/TableView.tsx' |
| 4 | import { fetchYahooChain } from './src/yahoo.ts' |
| 5 | |
| 6 | const chain = defineSource({ |
| 7 | description: |
| 8 | 'Yahoo Finance options chain straddle table (Calls & Puts side-by-side per strike) for a ticker symbol. Returns underlying spot price, available expirations, summary metrics (ATM IV, ATM straddle, put/call OI & volume ratios, max pain), and strike rows with Bid, Ask, Last, Volume, Open Interest, Implied Volatility %, and Black-Scholes Delta.', |
| 9 | hosts: [], |
| 10 | input: z.object({ |
| 11 | symbol: z.string().min(1).default('FLWS').describe('Underlying stock/ETF ticker symbol, like FLWS, WEN, or SPY.'), |
| 12 | expiration: z |
| 13 | .string() |
| 14 | .optional() |
| 15 | .describe('Expiration date in YYYY-MM-DD format. Omit for the nearest expiration.'), |
| 16 | strikes: z |
| 17 | .number() |
| 18 | .int() |
| 19 | .min(0) |
| 20 | .max(200) |
| 21 | .default(20) |
| 22 | .describe('Number of strikes around ATM spot price to return (0 for all returned strikes).'), |
| 23 | }), |
| 24 | async run(args, ctx) { |
| 25 | return fetchYahooChain(ctx, args.symbol, args.expiration ?? undefined, args.strikes) |
| 26 | }, |
| 27 | }) |
| 28 | |
| 29 | export default definePlugin({ |
| 30 | id: 'option-chain', |
| 31 | capabilities: ['tools'], |
| 32 | sources: { chain }, |
| 33 | views: { |
| 34 | table: defineView(TableView, { |
| 35 | title: 'Options Chain', |
| 36 | state: z.object({ |
| 37 | symbol: z.string().default('FLWS').describe('Ticker symbol to show.'), |
| 38 | expiration: z |
| 39 | .string() |
| 40 | .nullable() |
| 41 | .optional() |
| 42 | .default(null) |
| 43 | .describe('Selected expiration date (YYYY-MM-DD), or null for nearest.'), |
| 44 | provider: z |
| 45 | .enum(['yahoo', 'alpaca', 'massive', 'databento']) |
| 46 | .default('yahoo') |
| 47 | .describe('Options data vendor: yahoo (default), alpaca, massive, or databento.'), |
| 48 | alpacaFeed: z |
| 49 | .enum(['indicative', 'opra']) |
| 50 | .default('indicative') |
| 51 | .describe('Alpaca options feed: indicative (free) or opra.'), |
| 52 | strikes: z.number().default(20).describe('Max strikes around ATM (10, 20, 40, or 0 for All).'), |
| 53 | }), |
| 54 | output: z.object({ |
| 55 | symbol: z.string(), |
| 56 | provider: z.string(), |
| 57 | expiration: z.string().nullable(), |
| 58 | spot: z.number().nullable(), |
| 59 | strikeCount: z.number(), |
| 60 | expirationsCount: z.number(), |
| 61 | atmIv: z.number().nullable(), |
| 62 | atmStraddle: z.number().nullable(), |
| 63 | pcRatioOi: z.number().nullable(), |
| 64 | maxPain: z.number().nullable(), |
| 65 | }), |
| 66 | instructions: |
| 67 | 'Interactive multi-vendor Options Chain straddle view. Set state.symbol (e.g. "FLWS", "WEN", "SPY"), state.provider ("yahoo" default, "alpaca", "massive", or "databento"), state.expiration ("YYYY-MM-DD" or null for nearest), and state.strikes (10, 20, 40, or 0 for All).', |
| 68 | renders: [chain], |
| 69 | summarize: (state, output) => |
| 70 | `${output.symbol || state.symbol || 'FLWS'} (${output.provider || state.provider || 'yahoo'}) ${output.expiration ?? 'nearest'}: spot ${output.spot != null ? '$' + output.spot.toFixed(2) : '—'}, ${output.strikeCount ?? 0} strikes, ATM IV ${output.atmIv != null ? output.atmIv.toFixed(1) + '%' : '—'}`, |
| 71 | }), |
| 72 | }, |
| 73 | }) |