Alpaca: Alpaca market data, account, positions, and order management, with watchlist, account, and order-blotter views.
| 1 | import { definePlugin, defineView } from '@jaspers-ai/sdk' |
| 2 | import { z } from 'zod' |
| 3 | import { cancelOrder, placeOrder } from './actions' |
| 4 | import { optionBars, optionChain, optionLatestQuote, optionLatestTrade, optionSnapshots, optionTrades } from './options' |
| 5 | import { stockBars, stockLatestQuote, stockLatestTrade, stockQuotes, stockSnapshots, stockTrades } from './stocks' |
| 6 | import { account, assets, orders, positions } from './trading' |
| 7 | import { AccountPanel } from './views/AccountPanel' |
| 8 | import { Blotter } from './views/Blotter' |
| 9 | import { Watchlist } from './views/Watchlist' |
| 10 | |
| 11 | export default definePlugin({ |
| 12 | id: 'alpaca', |
| 13 | secrets: { |
| 14 | key_id: { label: 'Alpaca API key ID (paper account; also used for market data)' }, |
| 15 | secret_key: { label: 'Alpaca API secret key (paper account; also used for market data)' }, |
| 16 | live_key_id: { label: 'Alpaca LIVE account API key ID (only for live_account: true)' }, |
| 17 | live_secret_key: { label: 'Alpaca LIVE account API secret key (only for live_account: true)' }, |
| 18 | }, |
| 19 | sources: { |
| 20 | 'stock-bars': stockBars, |
| 21 | 'stock-quotes': stockQuotes, |
| 22 | 'stock-trades': stockTrades, |
| 23 | 'stock-latest-quote': stockLatestQuote, |
| 24 | 'stock-latest-trade': stockLatestTrade, |
| 25 | 'stock-snapshots': stockSnapshots, |
| 26 | 'option-bars': optionBars, |
| 27 | 'option-trades': optionTrades, |
| 28 | 'option-latest-quote': optionLatestQuote, |
| 29 | 'option-latest-trade': optionLatestTrade, |
| 30 | 'option-snapshots': optionSnapshots, |
| 31 | 'option-chain': optionChain, |
| 32 | account, |
| 33 | positions, |
| 34 | orders, |
| 35 | assets, |
| 36 | 'place-order': placeOrder, |
| 37 | 'cancel-order': cancelOrder, |
| 38 | }, |
| 39 | views: { |
| 40 | watchlist: defineView(Watchlist, { |
| 41 | title: 'Alpaca watchlist', |
| 42 | state: z.object({ |
| 43 | symbols: z.array(z.string()).max(100).default(['AAPL', 'MSFT', 'NVDA']).describe('Stock symbols to show.'), |
| 44 | feed: z.enum(['iex', 'sip', 'delayed_sip']).default('iex').describe('Data feed.'), |
| 45 | }), |
| 46 | output: z.object({ |
| 47 | symbols: z.array(z.string()), |
| 48 | count: z.number(), |
| 49 | rows: z.array(z.object({ symbol: z.string(), last: z.number().nullable(), change_pct: z.number().nullable() })), |
| 50 | }), |
| 51 | instructions: |
| 52 | 'Latest Alpaca snapshots (last, bid, ask, change, change %, volume) for state.symbols, refreshed every 15 s. Set state.symbols and state.feed (iex free, sip paid).', |
| 53 | renders: [stockSnapshots], |
| 54 | summarize: (state, output) => `Alpaca watchlist: ${output.count ?? 0} of ${state.symbols?.length ?? 0} symbols`, |
| 55 | }), |
| 56 | account: defineView(AccountPanel, { |
| 57 | title: 'Alpaca account', |
| 58 | state: z.object({ live_account: z.boolean().default(false).describe('Show the LIVE account instead of paper.') }), |
| 59 | output: z.object({ |
| 60 | mode: z.string(), |
| 61 | equity: z.number().nullable(), |
| 62 | cash: z.number().nullable(), |
| 63 | buying_power: z.number().nullable(), |
| 64 | day_pl: z.number().nullable(), |
| 65 | positions: z.number(), |
| 66 | }), |
| 67 | instructions: |
| 68 | 'The Alpaca account summary and its positions, paper by default. Set state.live_account to true only when the user asks for the live account.', |
| 69 | renders: [account, positions], |
| 70 | summarize: (_state, output) => `Alpaca ${output.mode ?? 'paper'}: equity ${output.equity ?? '–'}, ${output.positions ?? 0} positions`, |
| 71 | }), |
| 72 | orders: defineView(Blotter, { |
| 73 | title: 'Alpaca orders', |
| 74 | state: z.object({ |
| 75 | status: z.enum(['open', 'closed', 'all']).default('all'), |
| 76 | limit: z.number().int().min(1).max(500).default(50), |
| 77 | live_account: z.boolean().default(false).describe('Show the LIVE account instead of paper.'), |
| 78 | }), |
| 79 | output: z.object({ status: z.string(), count: z.number(), open: z.number() }), |
| 80 | instructions: |
| 81 | 'An Alpaca order blotter, paper by default. Set state.status (open|closed|all) and state.limit. Its cancel buttons cancel only on the user\'s click and confirmation.', |
| 82 | renders: [orders], |
| 83 | summarize: (state, output) => `Alpaca orders (${state.status ?? 'all'}): ${output.count ?? 0}, ${output.open ?? 0} open`, |
| 84 | }), |
| 85 | }, |
| 86 | }) |