import { definePlugin, defineSource, defineView } from '@jaspers-ai/sdk' import { z } from 'zod' import { TableView } from './src/TableView.tsx' import { fetchYahooChain } from './src/yahoo.ts' const chain = defineSource({ description: '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.', hosts: [], input: z.object({ symbol: z.string().min(1).default('FLWS').describe('Underlying stock/ETF ticker symbol, like FLWS, WEN, or SPY.'), expiration: z .string() .optional() .describe('Expiration date in YYYY-MM-DD format. Omit for the nearest expiration.'), strikes: z .number() .int() .min(0) .max(200) .default(20) .describe('Number of strikes around ATM spot price to return (0 for all returned strikes).'), }), async run(args, ctx) { return fetchYahooChain(ctx, args.symbol, args.expiration ?? undefined, args.strikes) }, }) export default definePlugin({ id: 'option-chain', capabilities: ['tools'], sources: { chain }, views: { table: defineView(TableView, { title: 'Options Chain', state: z.object({ symbol: z.string().default('FLWS').describe('Ticker symbol to show.'), expiration: z .string() .nullable() .optional() .default(null) .describe('Selected expiration date (YYYY-MM-DD), or null for nearest.'), provider: z .enum(['yahoo', 'alpaca', 'massive', 'databento']) .default('yahoo') .describe('Options data vendor: yahoo (default), alpaca, massive, or databento.'), alpacaFeed: z .enum(['indicative', 'opra']) .default('indicative') .describe('Alpaca options feed: indicative (free) or opra.'), strikes: z.number().default(20).describe('Max strikes around ATM (10, 20, 40, or 0 for All).'), }), output: z.object({ symbol: z.string(), provider: z.string(), expiration: z.string().nullable(), spot: z.number().nullable(), strikeCount: z.number(), expirationsCount: z.number(), atmIv: z.number().nullable(), atmStraddle: z.number().nullable(), pcRatioOi: z.number().nullable(), maxPain: z.number().nullable(), }), instructions: '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).', renders: [chain], summarize: (state, output) => `${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) + '%' : '—'}`, }), }, })