@discomedia/utils 1.0.78 → 1.0.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index-frontend.cjs.map +1 -1
- package/dist/index-frontend.mjs.map +1 -1
- package/dist/index.cjs +117 -0
- package/dist/index.cjs.map +3 -3
- package/dist/index.mjs +115 -0
- package/dist/index.mjs.map +3 -3
- package/dist/package.json +1 -1
- package/dist/test.mjs +4065 -228
- package/dist/test.mjs.map +4 -4
- package/dist/types/disco-mail.d.ts +24 -0
- package/dist/types/disco-mail.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types/disco-mail-types.d.ts +80 -0
- package/dist/types/types/disco-mail-types.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/logging.ts", "../src/market-hours.ts", "../src/market-time.ts", "../src/format-tools.ts", "../src/types/index.ts", "../src/types/llm-types.ts", "../src/misc-utils.ts", "../src/llm-openai.ts", "../src/llm-config.ts", "../src/json-tools.ts", "../src/llm-utils.ts", "../src/llm-images.ts", "../src/llm-deepseek.ts", "../src/llm-openrouter.ts", "../src/performance-timer.ts", "../src/alpaca-trading-api.ts", "../src/alpaca-market-data-api.ts"],
|
|
4
|
-
"sourcesContent": ["import * as mt from './market-time';\nimport * as ft from './format-tools';\nimport * as Types from './types';\nimport * as misc from './misc-utils';\nimport * as llm from './llm-openai';\nimport * as llmImages from './llm-images';\nimport * as deepseek from './llm-deepseek';\nimport * as openrouter from './llm-openrouter';\nimport { PerformanceTimer } from './performance-timer';\n\nimport { AlpacaTradingAPI } from './alpaca-trading-api';\nimport { AlpacaMarketDataAPI } from './alpaca-market-data-api';\nimport { getPackedSettings } from 'http2';\n\n// Re-export all types\nexport * from './types';\n\n// Export key classes directly for easier access\nexport { AlpacaTradingAPI } from './alpaca-trading-api';\nexport { AlpacaMarketDataAPI } from './alpaca-market-data-api';\nexport { supportsTemperature, uploadVisionFile } from './llm-openai';\nexport { OPENAI_IMAGE_MODELS, OPENAI_MODELS, OPENROUTER_MODELS } from './types/llm-types';\n\nexport const disco = {\n types: Types,\n alpaca: {\n TradingAPI: AlpacaTradingAPI,\n MarketDataAPI: AlpacaMarketDataAPI,\n },\n format: {\n capFirstLetter: ft.capFirstLetter,\n currency: ft.formatCurrency,\n number: ft.formatNumber,\n pct: ft.formatPercentage,\n dateTimeForGS: ft.dateTimeForGS,\n },\n llm: {\n call: llm.makeLLMCall,\n uploadVisionFile: llm.uploadVisionFile,\n seek: deepseek.makeDeepseekCall,\n images: llmImages.makeImagesCall,\n open: openrouter.makeOpenRouterCall,\n },\n time: {\n convertDateToMarketTimeZone: mt.convertDateToMarketTimeZone,\n getStartAndEndDates: mt.getStartAndEndDates,\n getMarketOpenClose: mt.getMarketOpenClose,\n getOpenCloseForTradingDay: mt.getOpenCloseForTradingDay,\n getLastFullTradingDate: mt.getLastFullTradingDate,\n getNextMarketDay: mt.getNextMarketDay,\n getPreviousMarketDay: mt.getPreviousMarketDay,\n getMarketTimePeriod: mt.getMarketTimePeriod,\n getMarketStatus: mt.getMarketStatus,\n getNYTimeZone: mt.getNYTimeZone,\n getTradingDate: mt.getTradingDate,\n getTradingStartAndEndDates: mt.getTradingStartAndEndDates,\n getTradingDaysBack: mt.getTradingDaysBack,\n isMarketDay: mt.isMarketDay,\n isWithinMarketHours: mt.isWithinMarketHours,\n countTradingDays: mt.countTradingDays,\n MARKET_TIMES: mt.MARKET_TIMES,\n },\n utils: {\n logIfDebug: misc.logIfDebug,\n fetchWithRetry: misc.fetchWithRetry,\n Timer: PerformanceTimer,\n },\n};\n", "import { LogOptions } from './types/logging-types';\n\n/**\n * Logs a message to the console.\n * @param message The message to log.\n * @param options Optional options.\n * @param options.source The source of the message.\n * @param options.type The type of message to log.\n * @param options.symbol The trading symbol associated with this log.\n * @param options.account The account associated with this log.\n */\nexport function log(message: string, options: LogOptions = { source: 'App', type: 'info' }): void {\n // Format the timestamp\n const date = new Date();\n const timestamp = date.toLocaleString('en-US', { timeZone: 'America/New_York' });\n const account = options?.account;\n const symbol = options?.symbol;\n\n // Build the log message\n const logMessage = `[${timestamp}]${options?.source ? ` [${options.source}] ` : ''}${\n account ? ` [${account}] ` : ''\n }${symbol ? ` [${symbol}] ` : ''}${message}`;\n\n // Use appropriate console method based on type\n if (options?.type === 'error') {\n console.error(logMessage);\n } else if (options?.type === 'warn') {\n console.warn(logMessage);\n } else {\n console.log(logMessage);\n }\n}\n", "// market-hours.ts\n\nexport interface HolidayDetails {\n date: string;\n}\n\nexport interface MarketHolidaysForYear {\n [holidayName: string]: HolidayDetails;\n}\n\nexport interface MarketHolidays {\n [year: number]: MarketHolidaysForYear;\n}\n\nexport interface EarlyCloseDetails {\n date: string;\n time: string;\n optionsTime: string;\n notes: string;\n}\n\nexport interface EarlyClosesForYear {\n [date: string]: EarlyCloseDetails;\n}\n\nexport interface MarketEarlyCloses {\n [year: number]: EarlyClosesForYear;\n}\n\nexport const marketHolidays: MarketHolidays = {\n 2024: {\n \"New Year's Day\": { date: '2024-01-01' },\n 'Martin Luther King, Jr. Day': { date: '2024-01-15' },\n \"Washington's Birthday\": { date: '2024-02-19' },\n 'Good Friday': { date: '2024-03-29' },\n 'Memorial Day': { date: '2024-05-27' },\n 'Juneteenth National Independence Day': { date: '2024-06-19' },\n 'Independence Day': { date: '2024-07-04' },\n 'Labor Day': { date: '2024-09-02' },\n 'Thanksgiving Day': { date: '2024-11-28' },\n 'Christmas Day': { date: '2024-12-25' },\n },\n 2025: {\n \"New Year's Day\": { date: '2025-01-01' },\n 'Jimmy Carter Memorial Day': { date: '2025-01-09' },\n 'Martin Luther King, Jr. Day': { date: '2025-01-20' },\n \"Washington's Birthday\": { date: '2025-02-17' },\n 'Good Friday': { date: '2025-04-18' },\n 'Memorial Day': { date: '2025-05-26' },\n 'Juneteenth National Independence Day': { date: '2025-06-19' },\n 'Independence Day': { date: '2025-07-04' },\n 'Labor Day': { date: '2025-09-01' },\n 'Thanksgiving Day': { date: '2025-11-27' },\n 'Christmas Day': { date: '2025-12-25' },\n },\n 2026: {\n \"New Year's Day\": { date: '2026-01-01' },\n 'Martin Luther King, Jr. Day': { date: '2026-01-19' },\n \"Washington's Birthday\": { date: '2026-02-16' },\n 'Good Friday': { date: '2026-04-03' },\n 'Memorial Day': { date: '2026-05-25' },\n 'Juneteenth National Independence Day': { date: '2026-06-19' },\n 'Independence Day': { date: '2026-07-03' },\n 'Labor Day': { date: '2026-09-07' },\n 'Thanksgiving Day': { date: '2026-11-26' },\n 'Christmas Day': { date: '2026-12-25' },\n },\n};\n\nexport const marketEarlyCloses: MarketEarlyCloses = {\n 2024: {\n '2024-07-03': {\n date: '2024-07-03',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Wednesday, July 3, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2024-11-29': {\n date: '2024-11-29',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Friday, November 29, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2024-12-24': {\n date: '2024-12-24',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Tuesday, December 24, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n },\n 2025: {\n '2025-07-03': {\n date: '2025-07-03',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Thursday, July 3, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2025-11-28': {\n date: '2025-11-28',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Friday, November 28, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2025-12-24': {\n date: '2025-12-24',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Wednesday, December 24, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n },\n 2026: {\n '2026-07-02': {\n date: '2026-07-02',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Independence Day observed, market closes early at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2026-11-27': {\n date: '2026-11-27',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Friday, November 27, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2026-12-24': {\n date: '2026-12-24',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Thursday, December 24, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n },\n};\n", "import { log as baseLog } from './logging';\nimport { LogOptions } from './types/logging-types';\nimport {\n Period,\n IntradayReporting,\n PeriodDates,\n MarketTimeParams,\n OutputFormat,\n MarketOpenCloseResult,\n MarketStatus,\n MarketTimesConfig,\n TradingDaysBackOptions,\n} from './types/market-time-types';\nimport { marketHolidays, marketEarlyCloses } from './market-hours';\n\n// Constants for NY market times (Eastern Time)\nexport const MARKET_CONFIG = {\n TIMEZONE: 'America/New_York',\n UTC_OFFSET_STANDARD: -5, // EST\n UTC_OFFSET_DST: -4, // EDT\n TIMES: {\n EXTENDED_START: { hour: 4, minute: 0 },\n MARKET_OPEN: { hour: 9, minute: 30 },\n EARLY_MARKET_END: { hour: 10, minute: 0 },\n MARKET_CLOSE: { hour: 16, minute: 0 },\n EARLY_CLOSE: { hour: 13, minute: 0 },\n EXTENDED_END: { hour: 20, minute: 0 },\n EARLY_EXTENDED_END: { hour: 17, minute: 0 },\n },\n} as const;\n\nconst log = (message: string, options: LogOptions = { type: 'info' }) => {\n baseLog(message, { ...options, source: 'MarketTime' });\n};\n\n// Helper: Get NY offset for a given UTC date (DST rules for US)\n/**\n * Returns the NY timezone offset (in hours) for a given UTC date, accounting for US DST rules.\n * @param date - UTC date\n * @returns offset in hours (-5 for EST, -4 for EDT)\n */\nfunction getNYOffset(date: Date): number {\n // US DST starts 2nd Sunday in March, ends 1st Sunday in November\n const year = date.getUTCFullYear();\n const dstStart = getNthWeekdayOfMonth(year, 3, 0, 2); // March, Sunday, 2nd\n const dstEnd = getNthWeekdayOfMonth(year, 11, 0, 1); // November, Sunday, 1st\n const utcTime = date.getTime();\n\n if (utcTime >= dstStart.getTime() && utcTime < dstEnd.getTime()) {\n return MARKET_CONFIG.UTC_OFFSET_DST;\n }\n return MARKET_CONFIG.UTC_OFFSET_STANDARD;\n}\n\n// Helper: Get nth weekday of month in UTC\n/**\n * Returns the nth weekday of a given month in UTC.\n * @param year - Year\n * @param month - 1-based month (e.g. March = 3)\n * @param weekday - 0=Sunday, 1=Monday, ...\n * @param n - nth occurrence\n * @returns Date object for the nth weekday\n */\nfunction getNthWeekdayOfMonth(year: number, month: number, weekday: number, n: number): Date {\n // month: 1-based (March = 3), weekday: 0=Sunday\n const firstDay = new Date(Date.UTC(year, month - 1, 1));\n let count = 0;\n for (let d = 1; d <= 31; d++) {\n const date = new Date(Date.UTC(year, month - 1, d));\n if (date.getUTCMonth() !== month - 1) break;\n if (date.getUTCDay() === weekday) {\n count++;\n if (count === n) return date;\n }\n }\n // fallback: last day of month\n return new Date(Date.UTC(year, month - 1, 28));\n}\n\n// Helper: Convert UTC date to NY time (returns new Date object)\n/**\n * Converts a UTC date to NY time (returns a new Date object).\n * @param date - UTC date\n * @returns Date object in NY time\n */\nfunction toNYTime(date: Date): Date {\n const offset = getNYOffset(date);\n // NY offset in hours\n const utcMillis = date.getTime();\n const nyMillis = utcMillis + offset * 60 * 60 * 1000;\n return new Date(nyMillis);\n}\n\n// Helper: Convert NY time to UTC (returns new Date object)\n/**\n * Converts a NY time date to UTC (returns a new Date object).\n * @param date - NY time date\n * @returns Date object in UTC\n */\nfunction fromNYTime(date: Date): Date {\n const offset = getNYOffset(date);\n const nyMillis = date.getTime();\n const utcMillis = nyMillis - offset * 60 * 60 * 1000;\n return new Date(utcMillis);\n}\n\n// Helper: Format date in ISO, unix, etc.\n/**\n * Formats a date in ISO, unix-seconds, or unix-ms format.\n * @param date - Date object\n * @param outputFormat - Output format ('iso', 'unix-seconds', 'unix-ms')\n * @returns Formatted date string or number\n */\nfunction formatDate(date: Date, outputFormat: OutputFormat = 'iso'): string | number {\n switch (outputFormat) {\n case 'unix-seconds':\n return Math.floor(date.getTime() / 1000);\n case 'unix-ms':\n return date.getTime();\n case 'iso':\n default:\n return date.toISOString();\n }\n}\n\n// Helper: Format date in NY locale string\n/**\n * Formats a date in NY locale string.\n * @param date - Date object\n * @returns NY locale string\n */\nfunction formatNYLocale(date: Date): string {\n return date.toLocaleString('en-US', { timeZone: 'America/New_York' });\n}\n\n// Market calendar logic\n/**\n * Market calendar logic for holidays, weekends, and market days.\n */\nclass MarketCalendar {\n /**\n * Checks if a date is a weekend in NY time.\n * @param date - Date object\n * @returns true if weekend, false otherwise\n */\n isWeekend(date: Date): boolean {\n const day = toNYTime(date).getUTCDay();\n return day === 0 || day === 6;\n }\n\n /**\n * Checks if a date is a market holiday in NY time.\n * @param date - Date object\n * @returns true if holiday, false otherwise\n */\n isHoliday(date: Date): boolean {\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth() + 1;\n const day = nyDate.getUTCDate();\n const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n const yearHolidays = marketHolidays[year];\n if (!yearHolidays) return false;\n return Object.values(yearHolidays).some((holiday) => holiday.date === formattedDate);\n }\n\n /**\n * Checks if a date is an early close day in NY time.\n * @param date - Date object\n * @returns true if early close, false otherwise\n */\n isEarlyCloseDay(date: Date): boolean {\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth() + 1;\n const day = nyDate.getUTCDate();\n const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n const yearEarlyCloses = marketEarlyCloses[year];\n return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;\n }\n\n /**\n * Gets the early close time (in minutes from midnight) for a given date.\n * @param date - Date object\n * @returns minutes from midnight or null\n */\n getEarlyCloseTime(date: Date): number | null {\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth() + 1;\n const day = nyDate.getUTCDate();\n const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n const yearEarlyCloses = marketEarlyCloses[year];\n if (yearEarlyCloses && yearEarlyCloses[formattedDate]) {\n const [hours, minutes] = yearEarlyCloses[formattedDate].time.split(':').map(Number);\n return hours * 60 + minutes;\n }\n return null;\n }\n\n /**\n * Checks if a date is a market day (not weekend or holiday).\n * @param date - Date object\n * @returns true if market day, false otherwise\n */\n isMarketDay(date: Date): boolean {\n return !this.isWeekend(date) && !this.isHoliday(date);\n }\n\n /**\n * Gets the next market day after the given date.\n * @param date - Date object\n * @returns Date object for next market day\n */\n getNextMarketDay(date: Date): Date {\n let nextDay = new Date(date.getTime() + 24 * 60 * 60 * 1000);\n while (!this.isMarketDay(nextDay)) {\n nextDay = new Date(nextDay.getTime() + 24 * 60 * 60 * 1000);\n }\n return nextDay;\n }\n\n /**\n * Gets the previous market day before the given date.\n * @param date - Date object\n * @returns Date object for previous market day\n */\n getPreviousMarketDay(date: Date): Date {\n let prevDay = new Date(date.getTime() - 24 * 60 * 60 * 1000);\n while (!this.isMarketDay(prevDay)) {\n prevDay = new Date(prevDay.getTime() - 24 * 60 * 60 * 1000);\n }\n return prevDay;\n }\n}\n\n// Market open/close times\n/**\n * Returns market open/close times for a given date, including extended and early closes.\n * @param date - Date object\n * @returns MarketOpenCloseResult\n */\nfunction getMarketTimes(date: Date): MarketOpenCloseResult {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(date);\n if (!calendar.isMarketDay(date)) {\n return {\n marketOpen: false,\n open: null,\n close: null,\n openExt: null,\n closeExt: null,\n };\n }\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth();\n const day = nyDate.getUTCDate();\n\n // Helper to build NY time for a given hour/minute\n function buildNYTime(hour: number, minute: number): Date {\n const d = new Date(Date.UTC(year, month, day, hour, minute, 0, 0));\n return fromNYTime(d);\n }\n\n let open = buildNYTime(MARKET_CONFIG.TIMES.MARKET_OPEN.hour, MARKET_CONFIG.TIMES.MARKET_OPEN.minute);\n let close = buildNYTime(MARKET_CONFIG.TIMES.MARKET_CLOSE.hour, MARKET_CONFIG.TIMES.MARKET_CLOSE.minute);\n let openExt = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_START.hour, MARKET_CONFIG.TIMES.EXTENDED_START.minute);\n let closeExt = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_END.hour, MARKET_CONFIG.TIMES.EXTENDED_END.minute);\n\n if (calendar.isEarlyCloseDay(date)) {\n close = buildNYTime(MARKET_CONFIG.TIMES.EARLY_CLOSE.hour, MARKET_CONFIG.TIMES.EARLY_CLOSE.minute);\n closeExt = buildNYTime(MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour, MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute);\n }\n\n return {\n marketOpen: true,\n open,\n close,\n openExt,\n closeExt,\n };\n}\n\n// Is within market hours\n/**\n * Checks if a date/time is within market hours, extended hours, or continuous.\n * @param date - Date object\n * @param intradayReporting - 'market_hours', 'extended_hours', or 'continuous'\n * @returns true if within hours, false otherwise\n */\nexport function isWithinMarketHours(date: Date, intradayReporting: IntradayReporting = 'market_hours'): boolean {\n const calendar = new MarketCalendar();\n if (!calendar.isMarketDay(date)) return false;\n const nyDate = toNYTime(date);\n const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();\n\n switch (intradayReporting) {\n case 'extended_hours': {\n let endMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;\n if (calendar.isEarlyCloseDay(date)) {\n endMinutes = MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;\n }\n const startMinutes = MARKET_CONFIG.TIMES.EXTENDED_START.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_START.minute;\n return minutes >= startMinutes && minutes <= endMinutes;\n }\n case 'continuous':\n return true;\n default: {\n let endMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n if (calendar.isEarlyCloseDay(date)) {\n endMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n }\n const startMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n return minutes >= startMinutes && minutes <= endMinutes;\n }\n }\n}\n\n// Get last full trading date\n/**\n * Returns the last full trading date (market close) for a given date.\n * @param currentDate - Date object (default: now)\n * @returns Date object for last full trading date\n */\nfunction getLastFullTradingDateImpl(currentDate: Date = new Date()): Date {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(currentDate);\n const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();\n const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n let marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n if (calendar.isEarlyCloseDay(currentDate)) {\n marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n }\n\n // If not a market day, or before open, or during market hours, return previous market day's close\n if (\n !calendar.isMarketDay(currentDate) ||\n minutes < marketOpenMinutes ||\n (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)\n ) {\n const prevMarketDay = calendar.getPreviousMarketDay(currentDate);\n let prevCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n if (calendar.isEarlyCloseDay(prevMarketDay)) {\n prevCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n }\n const prevNYDate = toNYTime(prevMarketDay);\n const year = prevNYDate.getUTCFullYear();\n const month = prevNYDate.getUTCMonth();\n const day = prevNYDate.getUTCDate();\n const closeHour = Math.floor(prevCloseMinutes / 60);\n const closeMinute = prevCloseMinutes % 60;\n return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));\n }\n\n // After market close or after extended hours, return today's close\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth();\n const day = nyDate.getUTCDate();\n const closeHour = Math.floor(marketCloseMinutes / 60);\n const closeMinute = marketCloseMinutes % 60;\n return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));\n}\n\n// Get day boundaries\n/**\n * Returns the start and end boundaries for a market day, extended hours, or continuous.\n * @param date - Date object\n * @param intradayReporting - 'market_hours', 'extended_hours', or 'continuous'\n * @returns Object with start and end Date\n */\nfunction getDayBoundaries(\n date: Date,\n intradayReporting: IntradayReporting = 'market_hours'\n): { start: Date; end: Date } {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth();\n const day = nyDate.getUTCDate();\n\n function buildNYTime(hour: number, minute: number, sec = 0, ms = 0): Date {\n const d = new Date(Date.UTC(year, month, day, hour, minute, sec, ms));\n return fromNYTime(d);\n }\n\n let start: Date;\n let end: Date;\n\n switch (intradayReporting) {\n case 'extended_hours':\n start = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_START.hour, MARKET_CONFIG.TIMES.EXTENDED_START.minute, 0, 0);\n end = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_END.hour, MARKET_CONFIG.TIMES.EXTENDED_END.minute, 59, 999);\n if (calendar.isEarlyCloseDay(date)) {\n end = buildNYTime(\n MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour,\n MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute,\n 59,\n 999\n );\n }\n break;\n case 'continuous':\n start = new Date(Date.UTC(year, month, day, 0, 0, 0, 0));\n end = new Date(Date.UTC(year, month, day, 23, 59, 59, 999));\n break;\n default:\n start = buildNYTime(MARKET_CONFIG.TIMES.MARKET_OPEN.hour, MARKET_CONFIG.TIMES.MARKET_OPEN.minute, 0, 0);\n end = buildNYTime(MARKET_CONFIG.TIMES.MARKET_CLOSE.hour, MARKET_CONFIG.TIMES.MARKET_CLOSE.minute, 59, 999);\n if (calendar.isEarlyCloseDay(date)) {\n end = buildNYTime(MARKET_CONFIG.TIMES.EARLY_CLOSE.hour, MARKET_CONFIG.TIMES.EARLY_CLOSE.minute, 59, 999);\n }\n break;\n }\n return { start, end };\n}\n\n// Period calculator\n/**\n * Calculates the start date for a given period ending at endDate.\n * @param endDate - Date object\n * @param period - Period string\n * @returns Date object for period start\n */\nfunction calculatePeriodStartDate(endDate: Date, period: Period): Date {\n const calendar = new MarketCalendar();\n let startDate: Date;\n switch (period) {\n case 'YTD':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), 0, 1));\n break;\n case '1D':\n startDate = calendar.getPreviousMarketDay(endDate);\n break;\n case '3D':\n startDate = new Date(endDate.getTime() - 3 * 24 * 60 * 60 * 1000);\n break;\n case '1W':\n startDate = new Date(endDate.getTime() - 7 * 24 * 60 * 60 * 1000);\n break;\n case '2W':\n startDate = new Date(endDate.getTime() - 14 * 24 * 60 * 60 * 1000);\n break;\n case '1M':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), endDate.getUTCMonth() - 1, endDate.getUTCDate()));\n break;\n case '3M':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), endDate.getUTCMonth() - 3, endDate.getUTCDate()));\n break;\n case '6M':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), endDate.getUTCMonth() - 6, endDate.getUTCDate()));\n break;\n case '1Y':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear() - 1, endDate.getUTCMonth(), endDate.getUTCDate()));\n break;\n default:\n throw new Error(`Invalid period: ${period}`);\n }\n // Ensure start date is a market day\n while (!calendar.isMarketDay(startDate)) {\n startDate = calendar.getNextMarketDay(startDate);\n }\n return startDate;\n}\n\n// Get market time period\n/**\n * Returns the start and end dates for a market time period.\n * @param params - MarketTimeParams\n * @returns PeriodDates object\n */\nexport function getMarketTimePeriod(params: MarketTimeParams): PeriodDates {\n const { period, end = new Date(), intraday_reporting = 'market_hours', outputFormat = 'iso' } = params;\n\n if (!period) throw new Error('Period is required');\n const calendar = new MarketCalendar();\n\n const nyEndDate = toNYTime(end);\n let endDate: Date;\n const isCurrentMarketDay = calendar.isMarketDay(end);\n const isWithinHours = isWithinMarketHours(end, intraday_reporting);\n const minutes = nyEndDate.getUTCHours() * 60 + nyEndDate.getUTCMinutes();\n const marketStartMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n\n if (isCurrentMarketDay) {\n if (minutes < marketStartMinutes) {\n // Before market open - use previous day's close\n const lastMarketDay = calendar.getPreviousMarketDay(end);\n const { end: dayEnd } = getDayBoundaries(lastMarketDay, intraday_reporting);\n endDate = dayEnd;\n } else if (isWithinHours) {\n // During market hours - use current time\n endDate = end;\n } else {\n // After market close - use today's close\n const { end: dayEnd } = getDayBoundaries(end, intraday_reporting);\n endDate = dayEnd;\n }\n } else {\n // Not a market day - use previous market day's close\n const lastMarketDay = calendar.getPreviousMarketDay(end);\n const { end: dayEnd } = getDayBoundaries(lastMarketDay, intraday_reporting);\n endDate = dayEnd;\n }\n\n // Calculate start date\n const periodStartDate = calculatePeriodStartDate(endDate, period);\n const { start: dayStart } = getDayBoundaries(periodStartDate, intraday_reporting);\n\n if (endDate.getTime() < dayStart.getTime()) {\n throw new Error('Start date cannot be after end date');\n }\n\n return {\n start: formatDate(dayStart, outputFormat),\n end: formatDate(endDate, outputFormat),\n };\n}\n\n// Market status\n/**\n * Returns the current market status for a given date.\n * @param date - Date object (default: now)\n * @returns MarketStatus object\n */\nfunction getMarketStatusImpl(date: Date = new Date()): MarketStatus {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(date);\n const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();\n const isMarketDay = calendar.isMarketDay(date);\n const isEarlyCloseDay = calendar.isEarlyCloseDay(date);\n\n const extendedStartMinutes = MARKET_CONFIG.TIMES.EXTENDED_START.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_START.minute;\n const marketStartMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n const earlyMarketEndMinutes =\n MARKET_CONFIG.TIMES.EARLY_MARKET_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_MARKET_END.minute;\n\n let marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n let extendedEndMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;\n if (isEarlyCloseDay) {\n marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n extendedEndMinutes =\n MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;\n }\n\n let status: MarketStatus['status'];\n let nextStatus: MarketStatus['nextStatus'];\n let nextStatusTime: Date;\n let marketPeriod: MarketStatus['marketPeriod'];\n\n if (!isMarketDay) {\n status = 'closed';\n nextStatus = 'extended hours';\n marketPeriod = 'closed';\n const nextMarketDay = calendar.getNextMarketDay(date);\n nextStatusTime = getDayBoundaries(nextMarketDay, 'extended_hours').start;\n } else if (minutes < extendedStartMinutes) {\n status = 'closed';\n nextStatus = 'extended hours';\n marketPeriod = 'closed';\n nextStatusTime = getDayBoundaries(date, 'extended_hours').start;\n } else if (minutes < marketStartMinutes) {\n status = 'extended hours';\n nextStatus = 'open';\n marketPeriod = 'preMarket';\n nextStatusTime = getDayBoundaries(date, 'market_hours').start;\n } else if (minutes < marketCloseMinutes) {\n status = 'open';\n nextStatus = 'extended hours';\n marketPeriod = minutes < earlyMarketEndMinutes ? 'earlyMarket' : 'regularMarket';\n nextStatusTime = getDayBoundaries(date, 'market_hours').end;\n } else if (minutes < extendedEndMinutes) {\n status = 'extended hours';\n nextStatus = 'closed';\n marketPeriod = 'afterMarket';\n nextStatusTime = getDayBoundaries(date, 'extended_hours').end;\n } else {\n status = 'closed';\n nextStatus = 'extended hours';\n marketPeriod = 'closed';\n const nextMarketDay = calendar.getNextMarketDay(date);\n nextStatusTime = getDayBoundaries(nextMarketDay, 'extended_hours').start;\n }\n\n // I think using nyDate here may be wrong - should use current time? i.e. date.getTime()\n const nextStatusTimeDifference = nextStatusTime.getTime() - date.getTime();\n\n return {\n time: date,\n timeString: formatNYLocale(nyDate),\n status,\n nextStatus,\n marketPeriod,\n nextStatusTime,\n nextStatusTimeDifference,\n nextStatusTimeString: formatNYLocale(nextStatusTime),\n };\n}\n\n// API exports\n/**\n * Returns market open/close times for a given date.\n * @param options - { date?: Date }\n * @returns MarketOpenCloseResult\n */\nexport function getMarketOpenClose(options: { date?: Date } = {}): MarketOpenCloseResult {\n const { date = new Date() } = options;\n return getMarketTimes(date);\n}\n\n/**\n * Returns the start and end dates for a market time period as Date objects.\n * @param params - MarketTimeParams\n * @returns Object with start and end Date\n */\nexport function getStartAndEndDates(params: MarketTimeParams = {}): { start: Date; end: Date } {\n const { start, end } = getMarketTimePeriod(params);\n return {\n start: typeof start === 'string' || typeof start === 'number' ? new Date(start) : start,\n end: typeof end === 'string' || typeof end === 'number' ? new Date(end) : end,\n };\n}\n\n/**\n * Returns the last full trading date as a Date object.\n */\n/**\n * Returns the last full trading date as a Date object.\n * @param currentDate - Date object (default: now)\n * @returns Date object for last full trading date\n */\nexport function getLastFullTradingDate(currentDate: Date = new Date()): Date {\n return getLastFullTradingDateImpl(currentDate);\n}\n\n/**\n * Returns the last full trading date and formatted YYYYMMDD string.\n */\n/**\n * Returns the last full trading date and formatted YYYY-MM-DD string.\n * @param currentDate - Date object (default: now)\n * @returns Object with date and YYYYMMDD string\n */\nexport function getLastFullTradingDateInfo(currentDate: Date = new Date()): { date: Date; YYYYMMDD: string } {\n const date = getLastFullTradingDateImpl(currentDate);\n return {\n date,\n YYYYMMDD: `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(\n date.getUTCDate()\n ).padStart(2, '0')}`,\n };\n}\n\n/**\n * Returns the next market day after the reference date.\n * @param referenceDate - Date object (default: now)\n * @returns Object with date, yyyymmdd string, and ISO string\n */\nexport function getNextMarketDay({ referenceDate }: { referenceDate?: Date } = {}): {\n date: Date;\n yyyymmdd: string;\n dateISOString: string;\n} {\n const calendar = new MarketCalendar();\n const startDate = referenceDate ?? new Date();\n\n // Find the next trading day (UTC Date object)\n const nextDate = calendar.getNextMarketDay(startDate);\n\n // Convert to NY time before extracting Y-M-D parts\n const nyNext = toNYTime(nextDate);\n const yyyymmdd = `${nyNext.getUTCFullYear()}-${String(nyNext.getUTCMonth() + 1).padStart(2, '0')}-${String(\n nyNext.getUTCDate()\n ).padStart(2, '0')}`;\n\n return {\n date: nextDate, // raw Date, unchanged\n yyyymmdd, // correct trading date string\n dateISOString: nextDate.toISOString(),\n };\n}\n\n/**\n * Returns the previous market day before the reference date.\n * @param referenceDate - Date object (default: now)\n * @returns Object with date, yyyymmdd string, and ISO string\n */\nexport function getPreviousMarketDay({ referenceDate }: { referenceDate?: Date } = {}) {\n const calendar = new MarketCalendar();\n const startDate = referenceDate || new Date();\n const prevDate = calendar.getPreviousMarketDay(startDate);\n\n // convert to NY time first\n const nyPrev = toNYTime(prevDate); // \u2190 already in this file\n const yyyymmdd = `${nyPrev.getUTCFullYear()}-${String(nyPrev.getUTCMonth() + 1).padStart(2, '0')}-${String(\n nyPrev.getUTCDate()\n ).padStart(2, '0')}`;\n\n return {\n date: prevDate,\n yyyymmdd,\n dateISOString: prevDate.toISOString(),\n };\n}\n\n/**\n * Returns the trading date for a given time. Note: Just trims the date string; does not validate if the date is a market day.\n * @param time - a string, number (unix timestamp), or Date object representing the time\n * @returns the trading date as a string in YYYY-MM-DD format\n */\n/**\n * Returns the trading date for a given time in YYYY-MM-DD format (NY time).\n * @param time - string, number, or Date\n * @returns trading date string\n */\nexport function getTradingDate(time: string | number | Date): string {\n const date = typeof time === 'number' ? new Date(time) : typeof time === 'string' ? new Date(time) : time;\n const nyDate = toNYTime(date);\n return `${nyDate.getUTCFullYear()}-${String(nyDate.getUTCMonth() + 1).padStart(2, '0')}-${String(\n nyDate.getUTCDate()\n ).padStart(2, '0')}`;\n}\n\n/**\n * Returns the NY timezone offset string for a given date.\n * @param date - Date object (default: now)\n * @returns '-04:00' for EDT, '-05:00' for EST\n */\nexport function getNYTimeZone(date?: Date): '-04:00' | '-05:00' {\n const offset = getNYOffset(date || new Date());\n return offset === -4 ? '-04:00' : '-05:00';\n}\n\n/**\n * Returns the regular market open and close Date objects for a given trading day string in the\n * America/New_York timezone (NYSE/NASDAQ calendar).\n *\n * This helper is convenient when you have a calendar date like '2025-10-03' and want the precise\n * open and close Date values for that day. It internally:\n * - Determines the NY offset for the day using `getNYTimeZone()`.\n * - Anchors a noon-time Date on that day in NY time to avoid DST edge cases.\n * - Verifies the day is a market day via `isMarketDay()`.\n * - Fetches the open/close times via `getMarketOpenClose()`.\n *\n * Throws if the provided day is not a market day or if open/close times are unavailable.\n *\n * See also:\n * - `getNYTimeZone(date?: Date)`\n * - `isMarketDay(date: Date)`\n * - `getMarketOpenClose(options?: { date?: Date })`\n *\n * @param dateStr - Trading day string in 'YYYY-MM-DD' format (Eastern Time date)\n * @returns An object containing `{ open: Date; close: Date }`\n * @example\n * ```ts\n * const { open, close } = disco.time.getOpenCloseForTradingDay('2025-10-03');\n * ```\n */\nexport function getOpenCloseForTradingDay(dateStr: string): { open: Date; close: Date } {\n // Build a UTC midnight anchor for the date, then derive the NY offset for that day.\n const utcAnchor = new Date(`${dateStr}T00:00:00Z`);\n const nyOffset = getNYTimeZone(utcAnchor); // '-04:00' | '-05:00'\n\n // Create a NY-local noon date to avoid DST midnight transitions.\n const nyNoon = new Date(`${dateStr}T12:00:00${nyOffset}`);\n\n if (!isMarketDay(nyNoon)) {\n throw new Error(`Not a market day in ET: ${dateStr}`);\n }\n\n const { open, close } = getMarketOpenClose({ date: nyNoon });\n if (!open || !close) {\n throw new Error(`No market times available for ${dateStr}`);\n }\n\n return { open, close };\n}\n\n/**\n * Converts any date to the market time zone (America/New_York, Eastern Time).\n * Returns a new Date object representing the same moment in time but adjusted to NY/Eastern timezone.\n * Automatically handles daylight saving time transitions (EST/EDT).\n * \n * @param date - Date object to convert to market time zone\n * @returns Date object in NY/Eastern time zone\n * @example\n * ```typescript\n * const utcDate = new Date('2024-01-15T15:30:00Z'); // 3:30 PM UTC\n * const nyDate = convertDateToMarketTimeZone(utcDate); // 10:30 AM EST (winter) or 11:30 AM EDT (summer)\n * ```\n */\nexport function convertDateToMarketTimeZone(date: Date): Date {\n return toNYTime(date);\n}\n\n/**\n * Returns the current market status for a given date.\n * @param options - { date?: Date }\n * @returns MarketStatus object\n */\nexport function getMarketStatus(options: { date?: Date } = {}): MarketStatus {\n const { date = new Date() } = options;\n return getMarketStatusImpl(date);\n}\n\n/**\n * Checks if a date is a market day.\n * @param date - Date object\n * @returns true if market day, false otherwise\n */\nexport function isMarketDay(date: Date): boolean {\n const calendar = new MarketCalendar();\n return calendar.isMarketDay(date);\n}\n\n/**\n * Returns full trading days from market open to market close.\n * endDate is always the most recent market close (previous day's close if before open, today's close if after open).\n * days: 1 or not specified = that day's open; 2 = previous market day's open, etc.\n */\n/**\n * Returns full trading days from market open to market close.\n * @param options - { endDate?: Date, days?: number }\n * @returns Object with startDate and endDate\n */\nexport function getTradingStartAndEndDates(\n options: {\n endDate?: Date;\n days?: number;\n } = {}\n): { startDate: Date; endDate: Date } {\n const { endDate = new Date(), days = 1 } = options;\n const calendar = new MarketCalendar();\n\n // Find the most recent market close\n let endMarketDay = endDate;\n const nyEnd = toNYTime(endDate);\n const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n const marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n const minutes = nyEnd.getUTCHours() * 60 + nyEnd.getUTCMinutes();\n\n if (\n !calendar.isMarketDay(endDate) ||\n minutes < marketOpenMinutes ||\n (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)\n ) {\n // Before market open, not a market day, or during market hours: use previous market day\n endMarketDay = calendar.getPreviousMarketDay(endDate);\n } else {\n // After market close: use today\n endMarketDay = endDate;\n }\n\n // Get market close for endMarketDay\n const endClose = getMarketOpenClose({ date: endMarketDay }).close!;\n\n // Find start market day by iterating back over market days\n let startMarketDay = endMarketDay;\n let count = Math.max(1, days);\n for (let i = 1; i < count; i++) {\n startMarketDay = calendar.getPreviousMarketDay(startMarketDay);\n }\n // If days > 1, we need to go back (days-1) market days from endMarketDay\n if (days > 1) {\n startMarketDay = endMarketDay;\n for (let i = 1; i < days; i++) {\n startMarketDay = calendar.getPreviousMarketDay(startMarketDay);\n }\n }\n const startOpen = getMarketOpenClose({ date: startMarketDay }).open!;\n\n return { startDate: startOpen, endDate: endClose };\n}\n\n/**\n * Counts trading time between two dates (passed as standard Date objects), excluding weekends and holidays, and closed market hours, using other functions in this library.\n *\n * This function calculates the actual trading time between two dates by:\n * 1. Iterating through each calendar day between startDate and endDate (inclusive)\n * 2. For each day that is a market day (not weekend/holiday), getting market open/close times\n * 3. Calculating the overlap between the time range and market hours for that day\n * 4. Summing up all the trading minutes across all days\n *\n * The function automatically handles:\n * - Weekends (Saturday/Sunday) - skipped entirely\n * - Market holidays - skipped entirely\n * - Early close days (e.g. day before holidays) - uses early close time\n * - Times outside market hours - only counts time within 9:30am-4pm ET (or early close)\n *\n * Examples:\n * - 12pm to 3:30pm same day = 3.5 hours = 210 minutes = 0.54 days\n * - 9:30am to 4pm same day = 6.5 hours = 390 minutes = 1 day\n * - Friday 2pm to Monday 2pm = 6.5 hours (Friday 2pm-4pm + Monday 9:30am-2pm)\n *\n * @param startDate - Start date/time\n * @param endDate - End date/time (default: now)\n * @returns Object containing:\n * - days: Trading time as fraction of full trading days (6.5 hours = 1 day)\n * - hours: Trading time in hours\n * - minutes: Trading time in minutes\n */\nexport function countTradingDays(\n startDate: Date,\n endDate: Date = new Date()\n): {\n days: number;\n hours: number;\n minutes: number;\n} {\n const calendar = new MarketCalendar();\n\n // Ensure start is before end\n if (startDate.getTime() > endDate.getTime()) {\n throw new Error('Start date must be before end date');\n }\n\n let totalMinutes = 0;\n\n // Get the NY dates for iteration\n const startNY = toNYTime(startDate);\n const endNY = toNYTime(endDate);\n\n // Create date at start of first day (in NY time)\n const currentNY = new Date(\n Date.UTC(startNY.getUTCFullYear(), startNY.getUTCMonth(), startNY.getUTCDate(), 0, 0, 0, 0)\n );\n\n // Iterate through each calendar day\n while (currentNY.getTime() <= endNY.getTime()) {\n const currentUTC = fromNYTime(currentNY);\n\n // Check if this is a market day\n if (calendar.isMarketDay(currentUTC)) {\n // Get market hours for this day\n const marketTimes = getMarketTimes(currentUTC);\n\n if (marketTimes.marketOpen && marketTimes.open && marketTimes.close) {\n // Calculate the overlap between our time range and market hours\n const dayStart = Math.max(startDate.getTime(), marketTimes.open.getTime());\n const dayEnd = Math.min(endDate.getTime(), marketTimes.close.getTime());\n\n // Only count if there's actual overlap\n if (dayStart < dayEnd) {\n totalMinutes += (dayEnd - dayStart) / (1000 * 60);\n }\n }\n }\n\n // Move to next day\n currentNY.setUTCDate(currentNY.getUTCDate() + 1);\n }\n\n // Convert to days, hours, minutes\n const MINUTES_PER_TRADING_DAY = 390; // 6.5 hours\n const days = totalMinutes / MINUTES_PER_TRADING_DAY;\n const hours = totalMinutes / 60;\n const minutes = totalMinutes;\n\n return {\n days: Math.round(days * 1000) / 1000, // Round to 3 decimal places\n hours: Math.round(hours * 100) / 100, // Round to 2 decimal places\n minutes: Math.round(minutes),\n };\n}\n\n/**\n * Returns the trading day N days back from a reference date, along with its market open time.\n * Trading days are counted as full or half trading days (days that end count as 1 full trading day).\n * By default, the most recent completed trading day counts as day 1.\n * Set includeMostRecentFullDay to false to count strictly before that day.\n * \n * @param options - Object with:\n * - referenceDate: Date to count back from (default: now)\n * - days: Number of trading days to go back (must be an integer >= 1)\n * - includeMostRecentFullDay: Whether to include the most recent completed trading day (default: true)\n * @returns Object containing:\n * - date: Trading date in YYYY-MM-DD format\n * - marketOpenISO: Market open time as ISO string (e.g., \"2025-11-15T13:30:00.000Z\")\n * - unixTimestamp: Market open time as Unix timestamp in seconds\n * @example\n * ```typescript\n * // Get the trading day 1 day back (most recent full trading day)\n * const result = getTradingDaysBack({ days: 1 });\n * console.log(result.date); // \"2025-11-01\"\n * console.log(result.marketOpenISO); // \"2025-11-01T13:30:00.000Z\"\n * console.log(result.unixTimestamp); // 1730466600\n * \n * // Get the trading day 5 days back from a specific date\n * const result2 = getTradingDaysBack({ \n * referenceDate: new Date('2025-11-15T12:00:00-05:00'), \n * days: 5 \n * });\n * ```\n */\nexport function getTradingDaysBack(options: TradingDaysBackOptions): {\n date: string;\n marketOpenISO: string;\n unixTimestamp: number;\n} {\n const calendar = new MarketCalendar();\n const { referenceDate, days, includeMostRecentFullDay = true } = options;\n const refDate = referenceDate || new Date();\n const daysBack = days;\n\n if (!Number.isInteger(daysBack) || daysBack < 1) {\n throw new Error('days must be an integer >= 1');\n }\n\n // Start from the last full trading date relative to reference\n let targetDate = getLastFullTradingDateImpl(refDate);\n\n if (!includeMostRecentFullDay) {\n targetDate = calendar.getPreviousMarketDay(targetDate);\n }\n\n // Go back the specified number of days (we're already at day 1, so go back days-1 more)\n for (let i = 1; i < daysBack; i++) {\n targetDate = calendar.getPreviousMarketDay(targetDate);\n }\n\n // Get market open time for this date\n const marketTimes = getMarketTimes(targetDate);\n if (!marketTimes.open) {\n throw new Error(`No market open time for target date`);\n }\n\n // Format the date string (YYYY-MM-DD) in NY time\n const nyDate = toNYTime(marketTimes.open);\n const dateStr = `${nyDate.getUTCFullYear()}-${String(nyDate.getUTCMonth() + 1).padStart(2, '0')}-${String(nyDate.getUTCDate()).padStart(2, '0')}`;\n\n const marketOpenISO = marketTimes.open.toISOString();\n const unixTimestamp = Math.floor(marketTimes.open.getTime() / 1000);\n\n return {\n date: dateStr,\n marketOpenISO,\n unixTimestamp,\n };\n}\n\n// Export MARKET_TIMES for compatibility\nexport const MARKET_TIMES: MarketTimesConfig = {\n TIMEZONE: MARKET_CONFIG.TIMEZONE,\n PRE: {\n START: { HOUR: 4, MINUTE: 0, MINUTES: 240 },\n END: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n },\n EARLY_MORNING: {\n START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n END: { HOUR: 10, MINUTE: 0, MINUTES: 600 },\n },\n EARLY_CLOSE_BEFORE_HOLIDAY: {\n START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n END: { HOUR: 13, MINUTE: 0, MINUTES: 780 },\n },\n EARLY_EXTENDED_BEFORE_HOLIDAY: {\n START: { HOUR: 13, MINUTE: 0, MINUTES: 780 },\n END: { HOUR: 17, MINUTE: 0, MINUTES: 1020 },\n },\n REGULAR: {\n START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n END: { HOUR: 16, MINUTE: 0, MINUTES: 960 },\n },\n EXTENDED: {\n START: { HOUR: 4, MINUTE: 0, MINUTES: 240 },\n END: { HOUR: 20, MINUTE: 0, MINUTES: 1200 },\n },\n};\n", "// format-tools.ts\n\n/**\n * Capitalizes the first letter of a string\n * @param {string} str - The string to capitalize\n * @returns {string} The capitalized string, or original value if not a string\n * @example\n * capitalize('hello') // 'Hello'\n * capitalize(123) // 123\n */\nexport function capFirstLetter(str: string): string {\n if (!str || typeof str !== 'string') return str;\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Formats a number as US currency\n * @param {number} value - The number to format\n * @returns {string} The formatted currency string (e.g. '$1,234.56')\n * @example\n * formatCurrency(1234.56) // '$1,234.56'\n * formatCurrency(NaN) // '$0.00'\n */\nexport function formatCurrency(value: number): string {\n if (isNaN(value)) {\n return '$0.00';\n }\n\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n }).format(value);\n}\n\n/**\n * Formats a number with commas\n * @param {number} value - The number to format\n * @returns {string} The formatted number string (e.g. '1,234.56')\n * @example\n * formatNumber(1234.56) // '1,234.56'\n * formatNumber(NaN) // '0'\n */\nexport function formatNumber(value: number): string {\n if (isNaN(value)) {\n return '0';\n }\n\n return new Intl.NumberFormat('en-US').format(value);\n}\n\n/**\n * Formats a number as a percentage\n * @param {number} value - The number to format (e.g. 0.75 for 75%)\n * @param {number} [decimalPlaces=2] - Number of decimal places to show\n * @returns {string} The formatted percentage string (e.g. '75.00%')\n * @example\n * formatPercentage(0.75) // '75.00%'\n * formatPercentage(0.753, 1) // '75.3%'\n */\nexport function formatPercentage(value: number, decimalPlaces: number = 2): string {\n if (isNaN(value)) {\n return '0%';\n }\n return new Intl.NumberFormat('en-US', {\n style: 'percent',\n minimumFractionDigits: decimalPlaces,\n }).format(value);\n}\n\n/**\n * Formats a Date object to Australian datetime format for Google Sheets\n * @param {Date} date - The date to format\n * @returns {string} The formatted datetime string in 'DD/MM/YYYY HH:MM:SS' format\n * @example\n * dateTimeForGS(new Date('2025-01-01T12:34:56')) // '01/01/2025 12:34:56'\n */\nexport function dateTimeForGS(date: Date): string {\n return date\n .toLocaleString('en-AU', {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n })\n .replace(/\\./g, '/');\n}\n", "export * from './alpaca-types';\nexport * from './market-time-types';\nexport * from './ta-types';\nexport * from './llm-types';\nexport * from './logging-types';", "// openai-types.ts\nimport type {\n ChatCompletionMessageParam,\n ChatCompletionTool,\n ChatCompletionMessageToolCall,\n} from 'openai/resources/chat/completions';\nimport type { ImageGenerateParams, ImageModel } from 'openai/resources/images';\nimport type { ResponseFormatTextJSONSchemaConfig, ResponseInputImage } from 'openai/resources/responses/responses';\nimport type { ZodType } from 'zod';\n\n/**\n * Represents OpenAI models\n */\nexport const OPENAI_MODELS = [\n 'gpt-5.6',\n 'gpt-5.6-sol',\n 'gpt-5.6-terra',\n 'gpt-5.6-luna',\n 'gpt-5',\n 'gpt-5-mini',\n 'gpt-5.4-mini',\n 'gpt-5.4-nano',\n 'gpt-5-nano',\n 'gpt-5.1',\n 'gpt-5.4',\n 'gpt-5.5',\n 'gpt-5.5-pro',\n 'gpt-5.2',\n 'gpt-5.2-pro',\n 'gpt-5.1-codex',\n 'gpt-5.1-codex-max',\n] as const;\n\nexport type OpenAIModel = (typeof OPENAI_MODELS)[number];\n\n/**\n * Type guard to check if a model is a supported direct OpenAI model.\n */\nexport function isOpenAIModel(model: string): model is OpenAIModel {\n return OPENAI_MODELS.includes(model as OpenAIModel);\n}\n\n/**\n * Represents OpenAI image models.\n */\nexport const OPENAI_IMAGE_MODELS = [\n 'gpt-image-2',\n 'gpt-image-2-2026-04-21',\n 'gpt-image-1.5',\n 'gpt-image-1',\n 'gpt-image-1-mini',\n 'chatgpt-image-latest',\n 'dall-e-2',\n 'dall-e-3',\n] as const satisfies readonly ImageModel[];\n\nexport type OpenAIImageModel = (typeof OPENAI_IMAGE_MODELS)[number];\n\n/**\n * Type guard to check if a model is a supported OpenAI image model.\n */\nexport function isOpenAIImageModel(model: string): model is OpenAIImageModel {\n return OPENAI_IMAGE_MODELS.includes(model as OpenAIImageModel);\n}\n\n/**\n * Represents Deepseek models\n */\nexport type DeepseekModel = 'deepseek-chat' | 'deepseek-reasoner';\n\n/**\n * Represents OpenRouter models\n */\nexport const OPENROUTER_MODELS = [\n 'openai/gpt-5',\n 'openai/gpt-5-mini',\n 'openai/gpt-5.4-mini',\n 'openai/gpt-5.4-nano',\n 'openai/gpt-5-nano',\n 'openai/gpt-5.1',\n 'openai/gpt-5.4',\n 'openai/gpt-5.4-pro',\n 'openai/gpt-5.5',\n 'openai/gpt-5.5-pro',\n 'openai/gpt-5.2',\n 'openai/gpt-5.2-pro',\n 'openai/gpt-5.1-codex',\n 'openai/gpt-5.1-codex-max',\n 'openai/gpt-oss-120b',\n 'z.ai/glm-4.5',\n 'z.ai/glm-4.5-air',\n 'google/gemini-2.5-flash',\n 'google/gemini-2.5-flash-lite',\n 'deepseek/deepseek-r1-0528',\n 'deepseek/deepseek-chat-v3-0324',\n] as const;\n\nexport type OpenRouterModel = (typeof OPENROUTER_MODELS)[number];\n\n/**\n * Represents pricing information for OpenRouter models\n */\nexport interface OpenRouterPricing {\n input: number; // Cost per 1M input tokens\n output: number; // Cost per 1M output tokens\n context?: number; // Max context tokens\n}\n\n/**\n * Represents all supported LLM models\n */\nexport type LLMModel = OpenAIModel | DeepseekModel | OpenRouterModel;\n\n/**\n * Type guard to check if a model is an OpenRouter model\n */\nexport function isOpenRouterModel(model: string): model is OpenRouterModel {\n return OPENROUTER_MODELS.includes(model as OpenRouterModel);\n}\n\n/**\n * Represents the usage of the LLM.\n */\nexport interface LLMUsage {\n prompt_tokens: number;\n completion_tokens: number;\n reasoning_tokens?: number;\n provider: string;\n model: LLMModel;\n cache_hit_tokens?: number;\n cache_write_tokens?: number;\n cost: number;\n}\n\n/**\n * Represents the options for the LLM.\n */\nexport interface LLMOptions {\n model?: LLMModel;\n temperature?: number;\n top_p?: number;\n frequency_penalty?: number;\n presence_penalty?: number;\n max_completion_tokens?: number;\n tools?: ChatCompletionTool[];\n developerPrompt?: string;\n context?: ChatCompletionMessageParam[];\n store?: boolean;\n reasoning_effort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n reasoning_mode?: 'standard' | 'pro';\n reasoning_context?: 'auto' | 'current_turn' | 'all_turns';\n metadata?: Record<string, string>;\n parallel_tool_calls?: boolean;\n service_tier?: 'auto' | 'default' | 'flex' | 'priority';\n apiKey?: string;\n}\n\n/**\n * Represents the response from the LLM.\n */\nexport interface LLMResponse<T> {\n response: T;\n usage: LLMUsage;\n tool_calls?: ChatCompletionMessageToolCall[];\n}\n\n/**\n * Represents the format of the OpenAI response.\n */\nexport type OpenAIResponseFormat = 'text' | 'json' | ResponseFormatTextJSONSchemaConfig;\n\n/**\n * Represents schema input for structured outputs in OpenAI calls.\n * Can be either a JSON Schema object or a Zod schema.\n */\nexport type OpenAISchemaInput = ResponseFormatTextJSONSchemaConfig['schema'] | ZodType;\n\n/**\n * Supported image detail levels for OpenAI Responses vision inputs.\n */\nexport type OpenAIImageDetail = ResponseInputImage['detail'];\n\n/**\n * A remote image URL to analyze.\n */\nexport interface OpenAIImageURLInput {\n url: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * A base64-encoded image to analyze.\n * If `base64` is a raw base64 string, `mimeType` is used to create a data URL.\n */\nexport interface OpenAIImageBase64Input {\n base64: string;\n mimeType?: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * A fully formed data URL to analyze.\n */\nexport interface OpenAIImageDataURLInput {\n dataUrl: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * An already-uploaded OpenAI file ID to analyze.\n */\nexport interface OpenAIImageFileIDInput {\n fileId: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * A local file path to upload for vision analysis in Node.js environments.\n */\nexport interface OpenAIImageFilePathInput {\n filePath: string;\n filename?: string;\n mimeType?: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * Vision image input accepted by the OpenAI Responses helper.\n */\nexport type OpenAIImageInput =\n | OpenAIImageURLInput\n | OpenAIImageBase64Input\n | OpenAIImageDataURLInput\n | OpenAIImageFileIDInput\n | OpenAIImageFilePathInput;\n\n/**\n * Represents the options for the OpenAI Images API.\n * Extends the official ImageGenerateParams but with more user-friendly option names.\n */\nexport interface ImageGenerationOptions {\n model?: DiscoImageModel;\n size?: ImageGenerateParams['size'];\n outputFormat?: 'jpeg' | 'png' | 'webp';\n compression?: number;\n quality?: ImageGenerateParams['quality'];\n count?: number | null;\n apiKey?: string;\n background?: ImageGenerateParams['background'];\n moderation?: ImageGenerateParams['moderation'];\n /**\n * Optional multimodal LLM to pair with image outputs (e.g., gpt-5.4).\n */\n visionModel?: LLMModel;\n}\n\nexport type DiscoImageModel = OpenAIImageModel;\n\n/**\n * Context message for conversation history\n */\nexport interface ContextMessage {\n role: 'user' | 'assistant' | 'system' | 'developer';\n content: string;\n}\n\n\n// Re-export OpenAI types for convenience\nexport type { ImageModel, ImageGenerateParams } from 'openai/resources/images';\nexport type { ImagesResponse, Image } from 'openai/resources/images';\nexport type { Tool } from 'openai/resources/responses/responses';\n", "// Utility function for debug logging\n\n// Define the possible log types as a const array for better type inference\nconst LOG_TYPES = ['info', 'warn', 'error', 'debug', 'trace'] as const;\n// Create a union type from the array\ntype LogType = (typeof LOG_TYPES)[number];\n\n/**\n * Debug logging utility that respects environment debug flags.\n * Logs messages to the console based on the specified log level.\n *\n * @param message - The message to log.\n * @param data - Optional data to log alongside the message. This can be any type of data.\n * @param type - Log level. One of: 'info' | 'warn' | 'error' | 'debug' | 'trace'. Defaults to 'info'.\n *\n * @example\n * logIfDebug(\"User login failed\", { userId: 123 }, \"error\");\n * logIfDebug(\"Cache miss\", undefined, \"warn\");\n * logIfDebug(\"Processing request\", { requestId: \"abc\" }, \"debug\");\n */\nexport const logIfDebug = (message: string, data?: unknown, type: LogType = 'info') => {\n const prefix = `[DEBUG][${type.toUpperCase()}]`;\n const formattedData = data !== undefined ? JSON.stringify(data, null, 2) : '';\n\n switch (type) {\n case 'error':\n console.error(prefix, message, formattedData);\n break;\n case 'warn':\n console.warn(prefix, message, formattedData);\n break;\n case 'debug':\n console.debug(prefix, message, formattedData);\n break;\n case 'trace':\n console.trace(prefix, message, formattedData);\n break;\n case 'info':\n default:\n console.info(prefix, message, formattedData);\n }\n};\n\n/**\n * Masks the middle part of an API key, returning only the first 2 and last 2 characters.\n * If the API key is very short (<= 4 characters), it will be returned as is.\n *\n * @param keyValue - The API key to mask.\n * @returns The masked API key.\n *\n * @example\n * maskApiKey(\"12341239856677\"); // Returns \"12****77\"\n */\nfunction maskApiKey(keyValue: string): string {\n if (keyValue.length <= 4) {\n return keyValue;\n }\n const firstTwo = keyValue.slice(0, 2);\n const lastTwo = keyValue.slice(-2);\n return `${firstTwo}****${lastTwo}`;\n}\n\n/**\n * Hides (masks) the value of any query parameter that is \"apiKey\" (case-insensitive),\n * replacing the middle part with **** and keeping only the first 2 and last 2 characters.\n *\n * @param url - The URL containing the query parameters.\n * @returns The URL with the masked API key.\n *\n * @example\n * hideApiKeyFromurl(\"https://xxx.com/s/23/fdsa/?apiKey=12341239856677\");\n * // Returns \"https://xxx.com/s/23/fdsa/?apiKey=12****77\"\n */\nexport function hideApiKeyFromurl(url: string): string {\n try {\n const parsedUrl = new URL(url);\n\n // We iterate over all search params and look for one named 'apikey' (case-insensitive)\n for (const [key, value] of parsedUrl.searchParams.entries()) {\n if (key.toLowerCase() === 'apikey') {\n const masked = maskApiKey(value);\n parsedUrl.searchParams.set(key, masked);\n }\n }\n\n return parsedUrl.toString();\n } catch {\n // If we can't parse it as a valid URL, just return the original string\n return url;\n }\n}\n\ninterface ErrorDetails {\n type: string;\n reason: string;\n status: number | null;\n retryAfter?: number;\n}\n\n/**\n * Extracts meaningful error information from various error types.\n * @param error - The error to analyze.\n * @param response - Optional response object for HTTP errors.\n * @returns Structured error details.\n */\nfunction extractErrorDetails(error: unknown, response?: Response): ErrorDetails {\n const errMsg = error instanceof Error ? error.message : String(error);\n const errName = error instanceof Error ? error.name : 'Error';\n if (errName === 'TypeError' && errMsg.includes('fetch')) {\n return { type: 'NETWORK_ERROR', reason: 'Network connectivity issue', status: null };\n }\n if (errMsg.includes('HTTP error: 429')) {\n const match = errMsg.match(/RATE_LIMIT: 429:(\\d+)/);\n const retryAfter = match ? parseInt(match[1]) : undefined;\n return { type: 'RATE_LIMIT', reason: 'Rate limit exceeded', status: 429, retryAfter };\n }\n if (errMsg.includes('HTTP error: 401') || errMsg.includes('AUTH_ERROR: 401')) {\n return { type: 'AUTH_ERROR', reason: 'Authentication failed - invalid API key', status: 401 };\n }\n if (errMsg.includes('HTTP error: 403') || errMsg.includes('AUTH_ERROR: 403')) {\n return { type: 'AUTH_ERROR', reason: 'Access forbidden - insufficient permissions', status: 403 };\n }\n if (errMsg.includes('SERVER_ERROR:')) {\n const status = parseInt(errMsg.split('SERVER_ERROR: ')[1]) || 500;\n return { type: 'SERVER_ERROR', reason: `Server error (${status})`, status };\n }\n if (errMsg.includes('CLIENT_ERROR:')) {\n const status = parseInt(errMsg.split('CLIENT_ERROR: ')[1]) || 400;\n return { type: 'CLIENT_ERROR', reason: `Client error (${status})`, status };\n }\n return { type: 'UNKNOWN', reason: errMsg || 'Unknown error', status: null };\n}\n\n/**\n * Fetches a resource with intelligent retry logic for handling transient errors.\n * Features enhanced error logging, rate limit detection, and adaptive backoff.\n *\n * @param url - The URL to fetch.\n * @param options - Optional fetch options.\n * @param retries - The number of retry attempts. Defaults to 3.\n * @param initialBackoff - The initial backoff time in milliseconds. Defaults to 1000.\n * @returns A promise that resolves to the response.\n *\n * @throws Will throw an error if the fetch fails after the specified number of retries.\n */\nexport async function fetchWithRetry(\n url: string,\n options: RequestInit = {},\n retries: number = 3,\n initialBackoff: number = 1000,\n): Promise<Response> {\n let backoff = initialBackoff;\n\n for (let attempt = 1; attempt <= retries; attempt++) {\n try {\n const response = await fetch(url, options);\n if (!response.ok) {\n // Enhanced HTTP error handling with specific error types\n if (response.status === 429) {\n // Check for Retry-After header\n const retryAfter = response.headers.get('Retry-After');\n const retryDelay = retryAfter ? parseInt(retryAfter) * 1000 : null;\n\n throw new Error(`RATE_LIMIT: ${response.status}${retryDelay ? `:${retryDelay}` : ''}`);\n }\n if ([500, 502, 503, 504].includes(response.status)) {\n throw new Error(`SERVER_ERROR: ${response.status}`);\n }\n if ([401, 403].includes(response.status)) {\n throw new Error(`AUTH_ERROR: ${response.status}`);\n }\n if (response.status >= 400 && response.status < 500) {\n // Don't retry most 4xx client errors\n throw new Error(`CLIENT_ERROR: ${response.status}`);\n }\n throw new Error(`HTTP_ERROR: ${response.status}`);\n }\n return response;\n } catch (error) {\n if (attempt === retries) {\n throw error;\n }\n\n // Extract meaningful error information\n const errorDetails = extractErrorDetails(error);\n let adaptiveBackoff = backoff;\n\n // Adaptive backoff based on error type\n if (errorDetails.type === 'RATE_LIMIT') {\n // Use Retry-After header if available, otherwise use minimum 5s for rate limits\n if (errorDetails.retryAfter) {\n adaptiveBackoff = errorDetails.retryAfter;\n } else {\n adaptiveBackoff = Math.max(backoff, 5000);\n }\n } else if (errorDetails.type === 'AUTH_ERROR') {\n // Don't retry auth errors - fail fast\n console.error(`Authentication error for ${hideApiKeyFromurl(url)}: ${errorDetails.reason}`, {\n attemptNumber: attempt,\n errorType: errorDetails.type,\n httpStatus: errorDetails.status,\n url: hideApiKeyFromurl(url),\n source: 'fetchWithRetry',\n timestamp: new Date().toISOString(),\n });\n throw error;\n } else if (errorDetails.type === 'CLIENT_ERROR') {\n // Don't retry client errors (except 429 which is handled above)\n console.error(`Client error for ${hideApiKeyFromurl(url)}: ${errorDetails.reason}`, {\n attemptNumber: attempt,\n errorType: errorDetails.type,\n httpStatus: errorDetails.status,\n url: hideApiKeyFromurl(url),\n source: 'fetchWithRetry',\n timestamp: new Date().toISOString(),\n });\n throw error;\n }\n\n // Enhanced error logging with structured data\n console.warn(\n `Fetch attempt ${attempt} of ${retries} for ${hideApiKeyFromurl(url)} failed: ${\n errorDetails.reason\n }. Retrying in ${adaptiveBackoff}ms...`,\n {\n attemptNumber: attempt,\n totalRetries: retries,\n errorType: errorDetails.type,\n httpStatus: errorDetails.status,\n retryDelay: adaptiveBackoff,\n url: hideApiKeyFromurl(url),\n source: 'fetchWithRetry',\n timestamp: new Date().toISOString(),\n },\n );\n\n await new Promise((resolve) => setTimeout(resolve, adaptiveBackoff));\n backoff = Math.min(backoff * 2, 30000); // Cap at 30 seconds\n }\n }\n throw new Error('Failed to fetch after multiple attempts');\n}\n", "// llm-openai.ts\n\nimport OpenAI from 'openai';\nimport { zodTextFormat } from 'openai/helpers/zod';\nimport type { ZodType } from 'zod';\n\nimport type {\n Tool,\n ResponseInput,\n EasyInputMessage,\n ResponseInputImage,\n ResponseInputText,\n} from 'openai/resources/responses/responses';\n\nimport { calculateCost, DEFAULT_MODEL } from './llm-config';\nimport { parseResponse, normalizeModelName } from './llm-utils';\nimport { isOpenAIModel } from './types';\nimport type {\n LLMResponse,\n LLMOptions,\n LLMModel,\n OpenAIResponseFormat,\n ContextMessage,\n OpenAISchemaInput,\n OpenAIImageInput,\n OpenAIImageDetail,\n} from './types';\nimport type {\n ResponseCreateParamsNonStreaming,\n ResponseOutputItem,\n ResponseFunctionToolCall,\n ResponseCodeInterpreterToolCall,\n ResponseOutputMessage,\n ResponseOutputText,\n ResponseFormatTextJSONSchemaConfig,\n} from 'openai/resources/responses/responses';\n\nexport const DEFAULT_OPTIONS: LLMOptions = {\n model: DEFAULT_MODEL,\n parallel_tool_calls: false,\n};\n\nconst DEFAULT_IMAGE_MIME_TYPE = 'image/webp';\n\n/**\n * Checks if the given direct OpenAI model supports the temperature parameter.\n * @param model The model to check.\n * @returns True if the model supports the temperature parameter, false otherwise.\n */\nexport function supportsTemperature(_model: string): boolean {\n return false;\n}\n\nfunction isZodSchema(schema: OpenAISchemaInput): schema is ZodType {\n return typeof schema === 'object' && schema !== null && 'safeParse' in schema;\n}\n\nfunction buildJsonSchemaFormat(\n schema: OpenAISchemaInput,\n schemaName: string,\n schemaDescription?: string,\n schemaStrict?: boolean\n): ResponseFormatTextJSONSchemaConfig {\n if (isZodSchema(schema)) {\n const zodFormat = zodTextFormat(\n schema,\n schemaName,\n schemaDescription\n ? {\n description: schemaDescription,\n }\n : undefined\n );\n\n return {\n type: 'json_schema',\n name: zodFormat.name,\n schema: zodFormat.schema,\n ...(zodFormat.description ? { description: zodFormat.description } : {}),\n ...(schemaStrict !== undefined ? { strict: schemaStrict } : { strict: zodFormat.strict }),\n };\n }\n\n return {\n type: 'json_schema',\n name: schemaName,\n schema,\n ...(schemaDescription ? { description: schemaDescription } : {}),\n ...(schemaStrict !== undefined ? { strict: schemaStrict } : {}),\n };\n}\n\nfunction resolveOpenAIApiKey(apiKey?: string): string {\n const resolvedApiKey = apiKey || process.env.OPENAI_API_KEY;\n\n if (!resolvedApiKey) {\n throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');\n }\n\n return resolvedApiKey;\n}\n\nfunction createOpenAIClient(apiKey: string): OpenAI {\n return new OpenAI({\n apiKey,\n });\n}\n\nfunction normalizeImageDataUrl(imageData: string, mimeType = DEFAULT_IMAGE_MIME_TYPE): string {\n return imageData.startsWith('data:') ? imageData : `data:${mimeType};base64,${imageData}`;\n}\n\nfunction getFilenameFromPath(filePath: string): string {\n const normalizedPath = filePath.replace(/\\\\/g, '/');\n const pathSegments = normalizedPath.split('/');\n const filename = pathSegments[pathSegments.length - 1];\n\n if (!filename) {\n throw new Error(`Could not determine a filename from file path: ${filePath}`);\n }\n\n return filename;\n}\n\nfunction inferImageMimeType(filePath: string): string | undefined {\n const normalizedPath = filePath.toLowerCase();\n\n if (normalizedPath.endsWith('.png')) {\n return 'image/png';\n }\n\n if (normalizedPath.endsWith('.jpg') || normalizedPath.endsWith('.jpeg')) {\n return 'image/jpeg';\n }\n\n if (normalizedPath.endsWith('.webp')) {\n return 'image/webp';\n }\n\n if (normalizedPath.endsWith('.gif')) {\n return 'image/gif';\n }\n\n return undefined;\n}\n\nasync function readLocalFileBytes(filePath: string): Promise<Uint8Array> {\n try {\n const dynamicImport = new Function('specifier', 'return import(specifier);') as (\n specifier: string\n ) => Promise<{ readFile: (path: string) => Promise<Uint8Array> }>;\n const { readFile } = await dynamicImport('node:fs/promises');\n\n return await readFile(filePath);\n } catch {\n throw new Error('Local image file uploads require a Node.js runtime with access to node:fs/promises');\n }\n}\n\nasync function uploadVisionFileFromPath(\n openai: OpenAI,\n filePath: string,\n filename?: string,\n mimeType?: string\n): Promise<string> {\n const fileBytes = await readLocalFileBytes(filePath);\n const resolvedFilename = filename || getFilenameFromPath(filePath);\n const resolvedMimeType = mimeType || inferImageMimeType(filePath);\n const uploadableFile = await OpenAI.toFile(\n fileBytes,\n resolvedFilename,\n resolvedMimeType ? { type: resolvedMimeType } : undefined\n );\n\n const uploadedFile = await openai.files.create({\n file: uploadableFile,\n purpose: 'vision',\n });\n\n return uploadedFile.id;\n}\n\nfunction collectImageInputs(\n image: OpenAIImageInput | undefined,\n images: OpenAIImageInput[] | undefined,\n imageBase64: string | undefined\n): OpenAIImageInput[] {\n const collectedImages: OpenAIImageInput[] = [];\n\n if (image) {\n collectedImages.push(image);\n }\n\n if (images && images.length > 0) {\n collectedImages.push(...images);\n }\n\n if (imageBase64) {\n collectedImages.push({ base64: imageBase64 });\n }\n\n return collectedImages;\n}\n\nfunction hasLocalFileImage(images: OpenAIImageInput[]): boolean {\n return images.some((image) => 'filePath' in image);\n}\n\nasync function buildImageContentPart(\n image: OpenAIImageInput,\n defaultDetail: OpenAIImageDetail,\n openai?: OpenAI\n): Promise<ResponseInputImage> {\n const detail = image.detail ?? defaultDetail;\n\n if ('url' in image) {\n return {\n type: 'input_image',\n detail,\n image_url: image.url,\n };\n }\n\n if ('dataUrl' in image) {\n return {\n type: 'input_image',\n detail,\n image_url: image.dataUrl,\n };\n }\n\n if ('base64' in image) {\n return {\n type: 'input_image',\n detail,\n image_url: normalizeImageDataUrl(image.base64, image.mimeType),\n };\n }\n\n if ('fileId' in image) {\n return {\n type: 'input_image',\n detail,\n file_id: image.fileId,\n };\n }\n\n if (!openai) {\n throw new Error('A local image file path was provided, but no OpenAI client is available to upload it');\n }\n\n const fileId = await uploadVisionFileFromPath(openai, image.filePath, image.filename, image.mimeType);\n return {\n type: 'input_image',\n detail,\n file_id: fileId,\n };\n}\n\nasync function buildPromptContent(\n input: string,\n imageInputs: OpenAIImageInput[],\n imageDetail: OpenAIImageDetail,\n openai?: OpenAI\n): Promise<string | Array<ResponseInputText | ResponseInputImage>> {\n if (imageInputs.length === 0) {\n return input;\n }\n\n const imageContent = await Promise.all(imageInputs.map((image) => buildImageContentPart(image, imageDetail, openai)));\n\n return [{ type: 'input_text', text: input }, ...imageContent];\n}\n\nexport async function uploadVisionFile(\n filePath: string,\n options: {\n apiKey?: string;\n filename?: string;\n mimeType?: string;\n } = {}\n): Promise<string> {\n const resolvedApiKey = resolveOpenAIApiKey(options.apiKey);\n const openai = createOpenAIClient(resolvedApiKey);\n\n return await uploadVisionFileFromPath(openai, filePath, options.filename, options.mimeType);\n}\n\n/**\n * Makes a call to OpenAI's Responses API for more advanced use cases with built-in tools.\n *\n * This function provides access to the Responses API which supports:\n * - Built-in tools (web search, file search, computer use, code interpreter, image generation)\n * - Background processing\n * - Conversation state management\n * - GPT-5 reasoning controls\n *\n * @example\n * // Basic text response\n * const response = await makeResponsesAPICall('What is the weather like?');\n *\n * @example\n * // With web search tool\n * const response = await makeResponsesAPICall('Latest news about AI', {\n * tools: [{ type: 'web_search_preview' }]\n * });\n *\n * @param input - The input content. Can be:\n * - A string for simple text prompts\n * - An array of input items for complex/multi-modal content\n * @param options - Configuration options for the Responses API\n * @returns Promise<LLMResponse<T>> - The response in the same format as makeLLMCall\n * @throws Error if the API call fails\n */\nexport const makeResponsesAPICall = async <T = string>(\n input: string | ResponseCreateParamsNonStreaming['input'],\n options: Omit<ResponseCreateParamsNonStreaming, 'input' | 'model'> & {\n apiKey?: string;\n model?: string;\n } = {}\n): Promise<LLMResponse<T>> => {\n const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);\n if (!isOpenAIModel(normalizedModel)) {\n throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);\n }\n\n const apiKey = resolveOpenAIApiKey(options.apiKey);\n const openai = createOpenAIClient(apiKey);\n\n // Remove apiKey from options before creating request body\n const { apiKey: _, model: __, ...cleanOptions } = options;\n\n const requestBody: ResponseCreateParamsNonStreaming = {\n model: normalizedModel,\n input,\n ...cleanOptions,\n };\n\n // Make the API call to the Responses endpoint\n const response = await openai.responses.create(requestBody);\n const cacheHitTokens = response.usage?.input_tokens_details?.cached_tokens || 0;\n const cacheWriteTokens = response.usage?.input_tokens_details?.cache_write_tokens || 0;\n\n // Extract tool calls from the output\n const toolCalls = response.output\n ?.filter((item: ResponseOutputItem): item is ResponseFunctionToolCall => item.type === 'function_call')\n .map((toolCall: ResponseFunctionToolCall) => ({\n id: toolCall.call_id,\n type: 'function' as const,\n function: {\n name: toolCall.name,\n arguments: toolCall.arguments,\n },\n }));\n\n // Extract code interpreter outputs if present\n const codeInterpreterCalls = response.output?.filter(\n (item: ResponseOutputItem): item is ResponseCodeInterpreterToolCall => item.type === 'code_interpreter_call'\n );\n let codeInterpreterOutputs: ResponseCodeInterpreterToolCall['outputs'] | undefined = undefined;\n if (codeInterpreterCalls && codeInterpreterCalls.length > 0) {\n // Each code_interpreter_call has an 'outputs' array property\n codeInterpreterOutputs = codeInterpreterCalls.flatMap((ci) => {\n // Return outputs if present, otherwise empty array\n if (ci.outputs) return ci.outputs;\n return [];\n });\n }\n\n // Handle tool calls differently\n if (toolCalls && toolCalls.length > 0) {\n return {\n response: {\n tool_calls: toolCalls.map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments),\n })),\n } as T,\n usage: {\n prompt_tokens: response.usage?.input_tokens || 0,\n completion_tokens: response.usage?.output_tokens || 0,\n reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,\n provider: 'openai',\n model: normalizedModel,\n cache_hit_tokens: cacheHitTokens,\n cache_write_tokens: cacheWriteTokens,\n cost: calculateCost(\n 'openai',\n normalizedModel,\n response.usage?.input_tokens || 0,\n response.usage?.output_tokens || 0,\n response.usage?.output_tokens_details?.reasoning_tokens || 0,\n cacheHitTokens,\n cacheWriteTokens\n ),\n },\n tool_calls: toolCalls,\n ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),\n };\n }\n\n // Extract text content from the response output\n const textContent =\n response.output\n ?.filter((item: ResponseOutputItem): item is ResponseOutputMessage => item.type === 'message')\n .map((item: ResponseOutputMessage) =>\n item.content\n .filter((content): content is ResponseOutputText => content.type === 'output_text')\n .map((content) => content.text)\n .join('')\n )\n .join('') || '';\n\n // Determine the format for parsing the response\n let parsingFormat: OpenAIResponseFormat = 'text';\n const requestedFormat = requestBody.text?.format;\n if (requestedFormat?.type === 'json_object') {\n parsingFormat = 'json';\n } else if (requestedFormat?.type === 'json_schema') {\n parsingFormat = requestedFormat;\n }\n\n // Handle regular responses\n const parsedResponse = await parseResponse<T>(textContent, parsingFormat);\n if (parsedResponse === null) {\n throw new Error('Failed to parse response from Responses API');\n }\n\n return {\n response: parsedResponse,\n usage: {\n prompt_tokens: response.usage?.input_tokens || 0,\n completion_tokens: response.usage?.output_tokens || 0,\n reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,\n provider: 'openai',\n model: normalizedModel,\n cache_hit_tokens: cacheHitTokens,\n cache_write_tokens: cacheWriteTokens,\n cost: calculateCost(\n 'openai',\n normalizedModel,\n response.usage?.input_tokens || 0,\n response.usage?.output_tokens || 0,\n response.usage?.output_tokens_details?.reasoning_tokens || 0,\n cacheHitTokens,\n cacheWriteTokens\n ),\n },\n tool_calls: toolCalls,\n ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),\n };\n};\n\n/**\n * Makes a call to the OpenAI Responses API for advanced use cases with built-in tools.\n *\n * @param input The text prompt to send to the model (e.g., \"What's in this image?\")\n * @param options The options for the Responses API call, including optional image data and context.\n * @return A promise that resolves to the response from the Responses API.\n *\n * @example\n * // With conversation context\n * const response = await makeLLMCall(\"What did I ask about earlier?\", {\n * context: [\n * { role: 'user', content: 'What is the capital of France?' },\n * { role: 'assistant', content: 'The capital of France is Paris.' }\n * ]\n * });\n */\nexport async function makeLLMCall<T = string>(\n input: string,\n options: {\n apiKey?: string;\n model?: LLMModel;\n responseFormat?: OpenAIResponseFormat;\n schema?: OpenAISchemaInput;\n schemaName?: string;\n schemaDescription?: string;\n schemaStrict?: boolean;\n tools?: Tool[];\n useCodeInterpreter?: boolean;\n useWebSearch?: boolean;\n image?: OpenAIImageInput;\n images?: OpenAIImageInput[];\n imageBase64?: string;\n imageDetail?: OpenAIImageDetail;\n context?: ContextMessage[];\n reasoningEffort?: LLMOptions['reasoning_effort'];\n reasoningMode?: LLMOptions['reasoning_mode'];\n reasoningContext?: LLMOptions['reasoning_context'];\n } = {}\n): Promise<LLMResponse<T>> {\n const {\n apiKey,\n model = DEFAULT_MODEL,\n responseFormat = 'text',\n schema,\n schemaName = 'response',\n schemaDescription,\n schemaStrict,\n tools,\n useCodeInterpreter = false,\n useWebSearch = false,\n image,\n images,\n imageBase64,\n imageDetail = 'high',\n context,\n reasoningEffort,\n reasoningMode,\n reasoningContext,\n } = options;\n\n // Validate model\n const normalizedModel = normalizeModelName(model);\n if (!isOpenAIModel(normalizedModel)) {\n throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);\n }\n\n const resolvedApiKey = resolveOpenAIApiKey(apiKey);\n const imageInputs = collectImageInputs(image, images, imageBase64);\n const openai = hasLocalFileImage(imageInputs) ? createOpenAIClient(resolvedApiKey) : undefined;\n const promptContent = await buildPromptContent(input, imageInputs, imageDetail, openai);\n\n // Process input for conversation context and image analysis\n let processedInput: string | ResponseInput;\n\n if (context && context.length > 0) {\n // Build conversation array with context\n const conversationMessages: EasyInputMessage[] = [];\n\n // Add context messages\n for (const contextMsg of context) {\n conversationMessages.push({\n role: contextMsg.role,\n content: contextMsg.content,\n type: 'message',\n });\n }\n\n // Add current input message\n if (imageInputs.length > 0) {\n // Current message includes text and one or more images\n conversationMessages.push({\n role: 'user',\n content: promptContent,\n type: 'message',\n });\n } else {\n // Current message is just text\n conversationMessages.push({\n role: 'user',\n content: input,\n type: 'message',\n });\n }\n\n processedInput = conversationMessages;\n } else if (imageInputs.length > 0) {\n // No context, but has image(s)\n processedInput = [\n {\n role: 'user',\n content: promptContent,\n type: 'message',\n },\n ];\n } else {\n // No context, no image - simple string input\n processedInput = input;\n }\n\n // Build the options object for makeResponsesAPICall\n let responsesOptions: Parameters<typeof makeResponsesAPICall>[1] = {\n apiKey: resolvedApiKey,\n model: normalizedModel,\n parallel_tool_calls: false,\n tools,\n };\n\n // Only include temperature if the model supports it\n if (supportsTemperature(normalizedModel)) {\n responsesOptions.temperature = 0.2;\n }\n\n if (reasoningEffort || reasoningMode || reasoningContext) {\n responsesOptions.reasoning = {\n ...(reasoningEffort ? { effort: reasoningEffort } : {}),\n ...(reasoningMode ? { mode: reasoningMode } : {}),\n ...(reasoningContext ? { context: reasoningContext } : {}),\n };\n }\n\n // Configure response format\n if (schema) {\n responsesOptions.text = {\n format: buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStrict),\n };\n } else if (responseFormat === 'json') {\n responsesOptions.text = { format: { type: 'json_object' } };\n } else if (typeof responseFormat === 'object' && responseFormat.type === 'json_schema') {\n responsesOptions.text = { format: responseFormat };\n }\n\n // Configure built-in tools\n if (useCodeInterpreter) {\n responsesOptions.tools = [{ type: 'code_interpreter', container: { type: 'auto' } }];\n responsesOptions.include = ['code_interpreter_call.outputs'];\n }\n\n if (useWebSearch) {\n responsesOptions.tools = [{ type: 'web_search_preview' }];\n }\n\n return await makeResponsesAPICall<T>(processedInput, responsesOptions);\n}\n", "// llm-openai-config.ts\nimport type { ImageGenerateParams } from 'openai/resources/images';\nimport type { OpenAIImageModel, OpenAIModel } from './types/llm-types';\n\nexport const DEFAULT_MODEL: OpenAIModel = 'gpt-5.6-luna';\n\nexport const DEFAULT_DEVELOPER_PROMPT = `\n You are a highly experienced coding, business analyst, and financial analyst associate.\n Help with coding, business process design and analysis, data generation and refinement, content creation, financial analysis, and more.\n When presented with a coding problem, logic problem, or other problem benefiting from systematic thinking, think through it step by step before giving your final answer.\n Present complete, high-confidence, final answers only. Do not rephrase to be more brief or omit parts of answers.\n Respond only with final content (e.g. code, a json or yaml object, a formatted string, or a markdown document) and nothing else. Do not reply with a preamble, introduction, or conclusion.\n`;\n\ninterface AIModelCosts {\n [modelName: string]: {\n inputCost: number;\n outputCost: number;\n cacheHitCost?: number;\n cacheWriteCost?: number;\n };\n}\n\nconst GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS = 272_000;\nconst GPT_5_HIGH_CONTEXT_INPUT_MULTIPLIER = 2;\nconst GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER = 1.5;\n\n/** Token costs in USD per 1M tokens. Last updated July 2026 from the OpenAI API pricing page. */\nexport const openAiModelCosts: AIModelCosts = {\n 'gpt-5.6': {\n inputCost: 5 / 1_000_000,\n cacheHitCost: 0.5 / 1_000_000,\n cacheWriteCost: 6.25 / 1_000_000,\n outputCost: 30 / 1_000_000,\n },\n 'gpt-5.6-sol': {\n inputCost: 5 / 1_000_000,\n cacheHitCost: 0.5 / 1_000_000,\n cacheWriteCost: 6.25 / 1_000_000,\n outputCost: 30 / 1_000_000,\n },\n 'gpt-5.6-terra': {\n inputCost: 2.5 / 1_000_000,\n cacheHitCost: 0.25 / 1_000_000,\n cacheWriteCost: 3.125 / 1_000_000,\n outputCost: 15 / 1_000_000,\n },\n 'gpt-5.6-luna': {\n inputCost: 1 / 1_000_000,\n cacheHitCost: 0.1 / 1_000_000,\n cacheWriteCost: 1.25 / 1_000_000,\n outputCost: 6 / 1_000_000,\n },\n 'gpt-5': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n 'gpt-5-mini': {\n inputCost: 0.25 / 1_000_000,\n cacheHitCost: 0.025 / 1_000_000,\n outputCost: 2 / 1_000_000,\n },\n 'gpt-5.4-mini': {\n inputCost: 0.75 / 1_000_000,\n cacheHitCost: 0.075 / 1_000_000,\n outputCost: 4.5 / 1_000_000,\n },\n 'gpt-5.4-nano': {\n inputCost: 0.2 / 1_000_000,\n cacheHitCost: 0.02 / 1_000_000,\n outputCost: 1.25 / 1_000_000,\n },\n 'gpt-5-nano': {\n inputCost: 0.05 / 1_000_000,\n cacheHitCost: 0.005 / 1_000_000,\n outputCost: 0.4 / 1_000_000,\n },\n 'gpt-5.1': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n 'gpt-5.4': {\n inputCost: 2.5 / 1_000_000,\n cacheHitCost: 0.25 / 1_000_000,\n outputCost: 15 / 1_000_000,\n },\n 'gpt-5.5': {\n inputCost: 5 / 1_000_000,\n cacheHitCost: 0.5 / 1_000_000,\n outputCost: 30 / 1_000_000,\n },\n 'gpt-5.5-pro': {\n inputCost: 30 / 1_000_000,\n outputCost: 180 / 1_000_000,\n },\n 'gpt-5.2': {\n inputCost: 1.75 / 1_000_000,\n cacheHitCost: 0.175 / 1_000_000,\n outputCost: 14 / 1_000_000,\n },\n 'gpt-5.2-pro': {\n inputCost: 21 / 1_000_000,\n outputCost: 168 / 1_000_000,\n },\n 'gpt-5.1-codex': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n 'gpt-5.1-codex-max': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n};\n\nexport const deepseekModelCosts: AIModelCosts = {\n 'deepseek-chat': {\n inputCost: 0.27 / 1_000_000, // $0.27 per 1M tokens (Cache miss price)\n cacheHitCost: 0.07 / 1_000_000, // $0.07 per 1M tokens (Cache hit price)\n outputCost: 1.1 / 1_000_000, // $1.10 per 1M tokens\n },\n 'deepseek-reasoner': {\n inputCost: 0.55 / 1_000_000, // $0.55 per 1M tokens (Cache miss price)\n cacheHitCost: 0.14 / 1_000_000, // $0.14 per 1M tokens (Cache hit price)\n outputCost: 2.19 / 1_000_000, // $2.19 per 1M tokens\n },\n};\n\nfunction shouldUseGPT5HighContextPricing(model: string, inputTokens: number): boolean {\n return (\n (model === 'gpt-5.4' || model === 'gpt-5.5' || model === 'gpt-5.6' || model === 'gpt-5.6-sol' || model === 'gpt-5.6-terra' || model === 'gpt-5.6-luna') &&\n inputTokens > GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS\n );\n}\n\nexport type PricedOpenAIImageModel =\n | 'gpt-image-2'\n | 'gpt-image-2-2026-04-21'\n | 'gpt-image-1.5'\n | 'gpt-image-1'\n | 'gpt-image-1-mini';\nexport type OpenAIImagePricingQuality = 'low' | 'medium' | 'high';\nexport type OpenAIImagePricingSize = '1024x1024' | '1024x1536' | '1536x1024';\n\nexport const DEFAULT_IMAGE_PRICING_QUALITY: OpenAIImagePricingQuality = 'high';\nexport const DEFAULT_IMAGE_PRICING_SIZE: OpenAIImagePricingSize = '1024x1024';\n\nconst PRICED_OPENAI_IMAGE_MODELS: readonly PricedOpenAIImageModel[] = [\n 'gpt-image-2',\n 'gpt-image-2-2026-04-21',\n 'gpt-image-1.5',\n 'gpt-image-1',\n 'gpt-image-1-mini',\n];\nconst OPENAI_IMAGE_PRICING_SIZES: readonly OpenAIImagePricingSize[] = ['1024x1024', '1024x1536', '1536x1024'];\n\n/**\n * Estimated image output costs in USD per image for common GPT Image sizes.\n * Last updated May 2026 from the OpenAI image generation guide. Text and image\n * input token costs for prompts and edit inputs are not included.\n */\nexport const openAiImageCostByQualityAndSize: Record<\n PricedOpenAIImageModel,\n Record<OpenAIImagePricingQuality, Record<OpenAIImagePricingSize, number>>\n> = {\n 'gpt-image-2': {\n low: {\n '1024x1024': 0.006,\n '1024x1536': 0.005,\n '1536x1024': 0.005,\n },\n medium: {\n '1024x1024': 0.053,\n '1024x1536': 0.041,\n '1536x1024': 0.041,\n },\n high: {\n '1024x1024': 0.211,\n '1024x1536': 0.165,\n '1536x1024': 0.165,\n },\n },\n 'gpt-image-2-2026-04-21': {\n low: {\n '1024x1024': 0.006,\n '1024x1536': 0.005,\n '1536x1024': 0.005,\n },\n medium: {\n '1024x1024': 0.053,\n '1024x1536': 0.041,\n '1536x1024': 0.041,\n },\n high: {\n '1024x1024': 0.211,\n '1024x1536': 0.165,\n '1536x1024': 0.165,\n },\n },\n 'gpt-image-1.5': {\n low: {\n '1024x1024': 0.009,\n '1024x1536': 0.013,\n '1536x1024': 0.013,\n },\n medium: {\n '1024x1024': 0.034,\n '1024x1536': 0.05,\n '1536x1024': 0.05,\n },\n high: {\n '1024x1024': 0.133,\n '1024x1536': 0.2,\n '1536x1024': 0.2,\n },\n },\n 'gpt-image-1': {\n low: {\n '1024x1024': 0.011,\n '1024x1536': 0.016,\n '1536x1024': 0.016,\n },\n medium: {\n '1024x1024': 0.042,\n '1024x1536': 0.063,\n '1536x1024': 0.063,\n },\n high: {\n '1024x1024': 0.167,\n '1024x1536': 0.25,\n '1536x1024': 0.25,\n },\n },\n 'gpt-image-1-mini': {\n low: {\n '1024x1024': 0.005,\n '1024x1536': 0.006,\n '1536x1024': 0.006,\n },\n medium: {\n '1024x1024': 0.011,\n '1024x1536': 0.015,\n '1536x1024': 0.015,\n },\n high: {\n '1024x1024': 0.036,\n '1024x1536': 0.052,\n '1536x1024': 0.052,\n },\n },\n};\n\n/** Default image output costs in USD per image for legacy callers. */\nexport const openAiImageCosts: Record<PricedOpenAIImageModel, number> = {\n 'gpt-image-2':\n openAiImageCostByQualityAndSize['gpt-image-2'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n 'gpt-image-2-2026-04-21':\n openAiImageCostByQualityAndSize['gpt-image-2-2026-04-21'][DEFAULT_IMAGE_PRICING_QUALITY][\n DEFAULT_IMAGE_PRICING_SIZE\n ],\n 'gpt-image-1.5':\n openAiImageCostByQualityAndSize['gpt-image-1.5'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n 'gpt-image-1':\n openAiImageCostByQualityAndSize['gpt-image-1'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n 'gpt-image-1-mini':\n openAiImageCostByQualityAndSize['gpt-image-1-mini'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n};\n\nfunction isPricedOpenAIImageModel(model: string): model is PricedOpenAIImageModel {\n return PRICED_OPENAI_IMAGE_MODELS.includes(model as PricedOpenAIImageModel);\n}\n\nfunction isOpenAIImagePricingSize(size: string): size is OpenAIImagePricingSize {\n return OPENAI_IMAGE_PRICING_SIZES.includes(size as OpenAIImagePricingSize);\n}\n\nfunction resolveImagePricingQuality(quality?: ImageGenerateParams['quality']): OpenAIImagePricingQuality {\n if (quality === 'low' || quality === 'medium' || quality === 'high') {\n return quality;\n }\n\n return DEFAULT_IMAGE_PRICING_QUALITY;\n}\n\nfunction resolveImagePricingSize(size?: ImageGenerateParams['size']): OpenAIImagePricingSize {\n if (typeof size === 'string' && isOpenAIImagePricingSize(size)) {\n return size;\n }\n\n return DEFAULT_IMAGE_PRICING_SIZE;\n}\n\n/**\n * Calculates the cost of generating images using OpenAI's Images API.\n *\n * @param model The image generation model name.\n * @param imageCount The number of images generated.\n * @param quality The requested image quality.\n * @param size The requested image size.\n * @returns The cost of generating the images in USD.\n */\nexport function calculateImageCost(\n model: OpenAIImageModel | string,\n imageCount: number,\n quality?: ImageGenerateParams['quality'],\n size?: ImageGenerateParams['size']\n): number {\n if (typeof model !== 'string' || typeof imageCount !== 'number' || imageCount <= 0) {\n return 0;\n }\n\n if (!isPricedOpenAIImageModel(model)) return 0;\n\n const pricingQuality = resolveImagePricingQuality(quality);\n const pricingSize = resolveImagePricingSize(size);\n const costPerImage = openAiImageCostByQualityAndSize[model][pricingQuality][pricingSize];\n\n return imageCount * costPerImage;\n}\n\n/**\n * Calculates the cost of calling a language model in USD based on the provider and model, tokens, and given costs per 1M tokens.\n *\n * @param provider The provider of the language model. Supported providers are 'openai' and 'deepseek'.\n * @param model The name of the language model. Supported models are listed in the `openAiModelCosts` and `deepseekModelCosts` objects.\n * @param inputTokens The number of input tokens passed to the language model.\n * @param outputTokens The number of output tokens generated by the language model.\n * @param reasoningTokens The number of output tokens generated by the language model for reasoning.\n * @param cacheHitTokens The number of input tokens billed at cached-input rates.\n * @param cacheWriteTokens The number of input tokens billed at cache-write rates.\n * @returns The cost of calling the language model in USD.\n */\nexport function calculateCost(\n provider: string,\n model: string,\n inputTokens: number,\n outputTokens: number,\n reasoningTokens?: number,\n cacheHitTokens?: number,\n cacheWriteTokens?: number\n): number {\n if (\n typeof provider !== 'string' ||\n typeof model !== 'string' ||\n typeof inputTokens !== 'number' ||\n typeof outputTokens !== 'number' ||\n (reasoningTokens !== undefined && typeof reasoningTokens !== 'number') ||\n (cacheHitTokens !== undefined && typeof cacheHitTokens !== 'number') ||\n (cacheWriteTokens !== undefined && typeof cacheWriteTokens !== 'number')\n ) {\n return 0;\n }\n\n const modelCosts = provider === 'deepseek' ? deepseekModelCosts[model] : openAiModelCosts[model];\n\n if (!modelCosts) return 0;\n\n const boundedCacheHitTokens = Math.min(Math.max(cacheHitTokens || 0, 0), inputTokens);\n const boundedCacheWriteTokens = Math.min(Math.max(cacheWriteTokens || 0, 0), inputTokens - boundedCacheHitTokens);\n const uncachedInputTokens = inputTokens - boundedCacheHitTokens - boundedCacheWriteTokens;\n const inputCost =\n uncachedInputTokens * modelCosts.inputCost +\n boundedCacheHitTokens * (modelCosts.cacheHitCost || modelCosts.inputCost) +\n boundedCacheWriteTokens * (modelCosts.cacheWriteCost || modelCosts.inputCost);\n\n let outputCost = outputTokens * modelCosts.outputCost;\n let reasoningCost = (reasoningTokens || 0) * modelCosts.outputCost;\n\n if (provider === 'openai' && shouldUseGPT5HighContextPricing(model, inputTokens)) {\n return (\n inputCost * GPT_5_HIGH_CONTEXT_INPUT_MULTIPLIER +\n outputCost * GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER +\n reasoningCost * GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER\n );\n }\n\n return inputCost + outputCost + reasoningCost;\n}\n", "import OpenAI from 'openai';\nimport { DEFAULT_MODEL } from './llm-config';\n/**\n * Fix a broken JSON string by attempting to extract and parse valid JSON content. This function is very lenient and will attempt to fix many types of JSON errors, including unbalanced brackets, missing or extra commas, improperly escaped $ signs, unquoted strings, trailing commas, missing closing brackets or braces, etc.\n * @param {string} jsonStr - The broken JSON string to fix\n * @returns {JsonValue} - The parsed JSON value\n */\nexport function fixBrokenJson(jsonStr: string): JsonValue {\n // Pre-process: Fix improperly escaped $ signs\n jsonStr = jsonStr.replace(/\\\\\\$/g, '$');\n\n let index = 0;\n\n function parse(): JsonValue {\n const results: JsonValue[] = [];\n while (index < jsonStr.length) {\n skipWhitespace();\n const value = parseValue();\n if (value !== undefined) {\n results.push(value);\n } else {\n index++; // Skip invalid character\n }\n }\n return results.length === 1 ? results[0] : results;\n }\n\n function parseValue(): JsonValue | undefined {\n skipWhitespace();\n const char = getChar();\n if (!char) return undefined;\n if (char === '{') return parseObject();\n if (char === '[') return parseArray();\n if (char === '\"' || char === \"'\") return parseString();\n if (char === 't' && jsonStr.slice(index, index + 4).toLowerCase() === 'true') {\n index += 4;\n return true;\n }\n if (char === 'f' && jsonStr.slice(index, index + 5).toLowerCase() === 'false') {\n index += 5;\n return false;\n }\n if (char === 'n' && jsonStr.slice(index, index + 4).toLowerCase() === 'null') {\n index += 4;\n return null;\n }\n if (/[a-zA-Z]/.test(char)) return parseString(); // Unquoted string\n if (char === '-' || char === '.' || /\\d/.test(char)) return parseNumber();\n return undefined; // Unknown character\n }\n\n function parseObject(): JsonObject {\n const obj: JsonObject = {};\n index++; // Skip opening brace\n skipWhitespace();\n while (index < jsonStr.length && getChar() !== '}') {\n skipWhitespace();\n const key = parseString();\n if (key === undefined) {\n console.warn(`Expected key at position ${index}`);\n index++;\n continue;\n }\n skipWhitespace();\n if (getChar() === ':') {\n index++; // Skip colon\n } else {\n console.warn(`Missing colon after key \"${key}\" at position ${index}`);\n }\n skipWhitespace();\n const value = parseValue();\n if (value === undefined) {\n console.warn(`Expected value for key \"${key}\" at position ${index}`);\n index++;\n continue;\n }\n obj[key] = value;\n skipWhitespace();\n if (getChar() === ',') {\n index++; // Skip comma\n } else {\n break;\n }\n skipWhitespace();\n }\n if (getChar() === '}') {\n index++; // Skip closing brace\n } else {\n // Add a closing brace if it's missing\n jsonStr += '}';\n }\n return obj;\n }\n\n function parseArray(): JsonArray {\n const arr: JsonArray = [];\n index++; // Skip opening bracket\n skipWhitespace();\n while (index < jsonStr.length && getChar() !== ']') {\n const value = parseValue();\n if (value === undefined) {\n console.warn(`Expected value at position ${index}`);\n index++;\n } else {\n arr.push(value);\n }\n skipWhitespace();\n if (getChar() === ',') {\n index++; // Skip comma\n } else {\n break;\n }\n skipWhitespace();\n }\n if (getChar() === ']') {\n index++; // Skip closing bracket\n } else {\n console.warn(`Missing closing bracket for array at position ${index}`);\n }\n return arr;\n }\n\n function parseString(): string {\n const startChar = getChar();\n let result = '';\n let isQuoted = false;\n let delimiter = '';\n\n if (startChar === '\"' || startChar === \"'\") {\n isQuoted = true;\n delimiter = startChar;\n index++; // Skip opening quote\n }\n\n while (index < jsonStr.length) {\n const char = getChar();\n if (isQuoted) {\n if (char === delimiter) {\n index++; // Skip closing quote\n return result;\n } else if (char === '\\\\') {\n index++;\n const escapeChar = getChar();\n const escapeSequences: { [key: string]: string } = {\n n: '\\n',\n r: '\\r',\n t: '\\t',\n b: '\\b',\n f: '\\f',\n '\\\\': '\\\\',\n '/': '/',\n '\"': '\"',\n \"'\": \"'\",\n $: '$',\n };\n result += escapeSequences[escapeChar] || escapeChar;\n } else {\n result += char;\n }\n index++;\n } else {\n if (/\\s|,|}|]|\\:/.test(char)) {\n return result;\n } else {\n result += char;\n index++;\n }\n }\n }\n if (isQuoted) {\n console.warn(`Missing closing quote for string starting at position ${index}`);\n }\n return result;\n }\n\n function parseNumber(): number | undefined {\n const numberRegex = /^-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?/;\n const match = numberRegex.exec(jsonStr.slice(index));\n if (match) {\n index += match[0].length;\n return parseFloat(match[0]);\n } else {\n console.warn(`Invalid number at position ${index}`);\n index++;\n return undefined;\n }\n }\n\n function getChar(): string {\n return jsonStr[index];\n }\n\n function skipWhitespace(): void {\n while (/\\s/.test(getChar())) index++;\n }\n\n try {\n return parse();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`Error parsing JSON at position ${index}: ${msg}`);\n return null;\n }\n}\n\n/**\n * Returns true if the given JSON string is valid, false otherwise.\n *\n * This function simply attempts to parse the given string as JSON and returns true if successful, or false if an error is thrown.\n *\n * @param {string} jsonString The JSON string to validate.\n * @returns {boolean} True if the JSON string is valid, false otherwise.\n */\nexport function isValidJson(jsonString: string): boolean {\n try {\n JSON.parse(jsonString);\n return true;\n } catch {\n return false;\n }\n}\n\n// Types just for fixing JSON with AI\ninterface JsonObject {\n [key: string]: JsonValue;\n}\ntype JsonArray = JsonValue[];\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\n\nlet openai: OpenAI;\n\n/**\n * Initializes an instance of the OpenAI client, using the provided API key or the value of the OPENAI_API_KEY environment variable if no key is provided.\n * @param apiKey - the API key to use, or undefined to use the value of the OPENAI_API_KEY environment variable\n * @returns an instance of the OpenAI client\n * @throws an error if the API key is not provided and the OPENAI_API_KEY environment variable is not set\n */\nfunction initializeOpenAI(apiKey?: string): OpenAI {\n const key = apiKey || process.env.OPENAI_API_KEY;\n if (!key) {\n throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');\n }\n return new OpenAI({\n apiKey: key,\n defaultHeaders: { 'User-Agent': 'My Server-side Application (compatible; OpenAI API Client)' },\n });\n}\n\n/**\n * Fixes broken JSON by sending it to OpenAI to fix it.\n * If the model fails to return valid JSON, an error is thrown.\n * @param jsonStr - the broken JSON to fix\n * @param apiKey - the OpenAI API key to use, or undefined to use the value of the OPENAI_API_KEY environment variable\n * @returns the fixed JSON\n * @throws an error if the model fails to return valid JSON\n */\nexport async function fixJsonWithAI(jsonStr: string, apiKey?: string): Promise<JsonValue> {\n try {\n if (!openai) {\n openai = initializeOpenAI();\n }\n\n const completion = await openai.chat.completions.create({\n model: DEFAULT_MODEL,\n messages: [\n {\n role: 'system',\n content: 'You are a JSON fixer. Return only valid JSON without any additional text or explanation.',\n },\n {\n role: 'user',\n content: `Fix this broken JSON:\\n${jsonStr}`,\n },\n ],\n response_format: { type: 'json_object' },\n });\n\n const fixedJson = completion.choices[0]?.message?.content;\n\n if (fixedJson && isValidJson(fixedJson)) {\n return JSON.parse(fixedJson);\n }\n throw new Error('Failed to fix JSON with AI');\n } catch (err: unknown) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n throw new Error(`Error fixing JSON with AI: ${errorMessage}`);\n }\n}\n", "// llm-utils.ts\n\nimport { LLMModel, OpenAIModel, OpenAIResponseFormat } from './types';\nimport { fixBrokenJson, fixJsonWithAI } from './json-tools';\n\nexport function normalizeModelName(model: string): LLMModel {\n return model.replace(/_/g, '-').toLowerCase() as LLMModel;\n}\n\nexport const CODE_BLOCK_TYPES = ['javascript', 'js', 'graphql', 'json', 'typescript', 'python', 'markdown', 'yaml'];\n\n /**\n * Tries to parse JSON from the given content string according to the specified\n * response format. If the response format is 'json' or a JSON schema object, it\n * will attempt to parse the content using multiple strategies. If any of the\n * strategies succeed, it will return the parsed JSON object. If all of them fail,\n * it will throw an error.\n *\n * @param content The content string to parse\n * @param responseFormat The desired format of the response\n * @returns The parsed JSON object or null if it fails\n */\nexport async function parseResponse<T>(content: string, responseFormat: OpenAIResponseFormat): Promise<T | null> {\n if (!content) return null;\n\n if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat?.type === 'json_schema')) {\n let cleanedContent = content.trim();\n let detectedType: string | null = null;\n\n // Remove code block markers if present\n const startsWithCodeBlock = CODE_BLOCK_TYPES.some((type) => {\n if (cleanedContent.startsWith(`\\`\\`\\`${type}`)) {\n detectedType = type;\n return true;\n }\n return false;\n });\n\n if (startsWithCodeBlock && cleanedContent.endsWith('```')) {\n const firstLineEndIndex = cleanedContent.indexOf('\\n');\n if (firstLineEndIndex !== -1) {\n cleanedContent = cleanedContent.slice(firstLineEndIndex + 1, -3).trim();\n console.log(`Code block for type ${detectedType} detected and removed. Cleaned content: ${cleanedContent}`);\n }\n }\n\n // Multiple JSON parsing strategies\n const jsonParsingStrategies = [\n // Strategy 1: Direct parsing\n () => {\n try {\n return JSON.parse(cleanedContent);\n } catch {\n return null;\n }\n },\n // Strategy 2: Extract JSON from between first {} or []\n () => {\n const jsonMatch = cleanedContent.match(/[\\{\\[].*[\\}\\]]/s);\n if (jsonMatch) {\n try {\n return JSON.parse(jsonMatch[0]);\n } catch {\n return null;\n }\n }\n return null;\n },\n // Strategy 3: Remove leading/trailing text and try parsing\n () => {\n const jsonMatch = cleanedContent.replace(/^[^{[]*|[^}\\]]*$/g, '');\n try {\n return JSON.parse(jsonMatch);\n } catch {\n return null;\n }\n },\n // Strategy 4: Use fixJsonWithAI\n () => {\n return fixJsonWithAI(cleanedContent);\n },\n // Strategy 5: Use fixBrokenJson\n () => {\n return fixBrokenJson(cleanedContent);\n },\n ];\n\n // Try each parsing strategy\n for (const strategy of jsonParsingStrategies) {\n const result = await strategy();\n if (result !== null) {\n return result as T;\n }\n }\n\n // If all strategies fail, throw an error\n console.error(`Failed to parse JSON from content: ${cleanedContent}. Original JSON: ${content}`);\n throw new Error('Unable to parse JSON response');\n } else {\n return content as T;\n }\n}\n", "import OpenAI from 'openai';\nimport { ImageGenerationOptions, LLMModel, DiscoImageModel, OPENAI_MODELS } from './types';\nimport { calculateImageCost } from './llm-config';\nimport { ImageGenerateParams, ImagesResponse } from 'openai/resources/images';\n\n/**\n * Enhanced ImagesResponse that includes cost calculation\n */\nexport interface ImageResponseWithUsage extends ImagesResponse {\n usage?: ImagesResponse['usage'] & {\n provider: string;\n model: DiscoImageModel;\n cost: number;\n visionModel?: LLMModel;\n };\n}\n\nexport const DEFAULT_IMAGE_MODEL: DiscoImageModel = 'gpt-image-2';\n\nexport const resolveImageModel = (model?: DiscoImageModel): DiscoImageModel => model ?? DEFAULT_IMAGE_MODEL;\n\nconst MULTIMODAL_VISION_MODELS: ReadonlySet<LLMModel> = new Set(OPENAI_MODELS);\n\n/**\n * Makes a call to the OpenAI Images API to generate images based on a text prompt.\n *\n * This function provides access to OpenAI's image generation capabilities with support for:\n * - Different output formats (JPEG, PNG, WebP)\n * - Various image sizes and quality settings\n * - Multiple image generation in a single call\n * - Base64 encoded image data return\n *\n * @example\n * // Basic image generation\n * const response = await makeImagesCall('A beautiful sunset over mountains');\n *\n * @example\n * // Custom options\n * const response = await makeImagesCall('A birthday cake', {\n * size: '1024x1024',\n * outputFormat: 'png',\n * quality: 'high',\n * count: 2\n * });\n *\n * @param prompt - The text prompt describing the image to generate\n * @param options - Configuration options for image generation. Includes:\n * - size: Image dimensions (uses OpenAI's size options)\n * - outputFormat: Image format ('jpeg', 'png', 'webp') - defaults to 'webp'\n * - compression: Compression level (number) - defaults to 50\n * - quality: Quality setting (uses OpenAI's quality options) - defaults to 'high'\n * - count: Number of images to generate - defaults to 1\n * - background: Background setting for transparency support\n * - moderation: Content moderation level\n * - apiKey: OpenAI API key (optional, falls back to environment variable)\n * @returns Promise<ImageResponseWithUsage> - The image generation response with cost information\n * @throws Error if the API call fails or invalid parameters are provided\n */\nexport async function makeImagesCall(\n prompt: string,\n options: ImageGenerationOptions = {}\n): Promise<ImageResponseWithUsage> {\n const {\n model,\n size = 'auto',\n outputFormat = 'webp',\n compression = 50,\n quality = 'high',\n count = 1,\n background = 'auto',\n moderation = 'auto',\n apiKey,\n visionModel,\n } = options;\n const imageModel = resolveImageModel(model);\n const supportedVisionModel = visionModel && MULTIMODAL_VISION_MODELS.has(visionModel) ? visionModel : undefined;\n if (visionModel && !supportedVisionModel) {\n console.warn(\n `Vision model ${visionModel} is not recognized as a multimodal OpenAI model. Ignoring for image usage metadata.`\n );\n }\n\n // Get API key\n const effectiveApiKey = apiKey || process.env.OPENAI_API_KEY;\n if (!effectiveApiKey) {\n throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');\n }\n\n // Validate inputs\n if (!prompt || typeof prompt !== 'string') {\n throw new Error('Prompt must be a non-empty string');\n }\n\n if (count && (count < 1 || count > 10)) {\n throw new Error('Count must be between 1 and 10');\n }\n\n if (compression && (compression < 0 || compression > 100)) {\n throw new Error('Compression must be between 0 and 100');\n }\n\n const openai = new OpenAI({\n apiKey: effectiveApiKey,\n });\n\n // Build the request parameters using OpenAI's type\n const requestParams: ImageGenerateParams = {\n model: imageModel,\n prompt,\n n: count || 1,\n size: size || 'auto',\n quality: quality || 'auto',\n background: background || 'auto',\n moderation: moderation || 'auto',\n };\n\n // Add output format if specified\n if (outputFormat) {\n requestParams.output_format = outputFormat;\n }\n\n // Add compression if specified\n if (compression !== undefined) {\n requestParams.output_compression = compression;\n }\n\n try {\n // Make the API call\n const response = await openai.images.generate(requestParams);\n\n // Validate response\n if (!response.data || response.data.length === 0) {\n throw new Error('No images returned from OpenAI Images API');\n }\n\n // Calculate cost\n const cost = calculateImageCost(imageModel, count || 1, quality, size);\n\n // Return the response with enhanced usage information\n const enhancedResponse: ImageResponseWithUsage = {\n ...response,\n usage: {\n // OpenAI Images response may not include usage details per image; preserve if present\n ...(response.usage ?? {\n input_tokens: 0,\n input_tokens_details: { image_tokens: 0, text_tokens: 0 },\n output_tokens: 0,\n total_tokens: 0,\n }),\n provider: 'openai',\n model: imageModel,\n cost,\n ...(supportedVisionModel ? { visionModel: supportedVisionModel } : {}),\n },\n };\n\n return enhancedResponse;\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n throw new Error(`OpenAI Images API call failed: ${message}`);\n }\n} \n", "import OpenAI from 'openai';\nimport {\n ChatCompletionContentPart,\n ChatCompletionMessageParam,\n ChatCompletionCreateParams,\n} from 'openai/resources/chat';\n\nimport { calculateCost } from './llm-config';\nimport { parseResponse, normalizeModelName } from './llm-utils';\nimport { LLMResponse, LLMOptions, OpenAIModel, OpenAIResponseFormat, DeepseekModel, LLMModel } from './types';\n\n/**\n * Default options for Deepseek API calls\n */\nconst DEFAULT_DEEPSEEK_OPTIONS = {\n defaultModel: 'deepseek-chat' as DeepseekModel,\n};\n\n/**\n * Checks if the given model is a supported Deepseek model\n * @param model The model to check\n * @returns True if the model is supported, false otherwise\n */\nconst isSupportedDeepseekModel = (model: string): model is DeepseekModel => {\n return ['deepseek-chat', 'deepseek-reasoner'].includes(model);\n};\n\n/**\n * Checks if the given Deepseek model supports JSON output format\n * @param model The model to check\n * @returns True if JSON output is supported, false otherwise\n */\nconst supportsJsonOutput = (model: string): boolean => {\n return model === 'deepseek-chat';\n};\n\n/**\n * Checks if the given Deepseek model supports tool calling\n * @param model The model to check\n * @returns True if tool calling is supported, false otherwise\n */\nconst supportsToolCalling = (model: string): boolean => {\n return model === 'deepseek-chat';\n};\n\n/**\n * Gets the appropriate response format option for Deepseek API\n * \n * @param responseFormat The desired response format\n * @param model The model being used\n * @returns Object representing the Deepseek response format option\n */\nfunction getDeepseekResponseFormatOption(responseFormat: OpenAIResponseFormat, model: string): { type: 'text' } | { type: 'json_object' } {\n // Check if the model supports JSON output\n if (responseFormat !== 'text' && !supportsJsonOutput(model)) {\n console.warn(`Model ${model} does not support JSON output. Using text format instead.`);\n return { type: 'text' };\n }\n\n if (responseFormat === 'text') {\n return { type: 'text' };\n }\n if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) {\n return { type: 'json_object' };\n }\n return { type: 'text' };\n}\n\n/**\n * Creates a completion using the Deepseek API\n * \n * @param content The content to pass to the API\n * @param responseFormat The desired format of the response\n * @param options Additional options for the API call\n * @returns Promise resolving to the API response\n */\nasync function createDeepseekCompletion(\n content: string | ChatCompletionContentPart[],\n responseFormat: OpenAIResponseFormat,\n options: LLMOptions = {}\n) {\n // Extract the model or use default\n const modelOption = options.model || DEFAULT_DEEPSEEK_OPTIONS.defaultModel;\n const normalizedModel = normalizeModelName(modelOption);\n \n // Validate model\n if (!isSupportedDeepseekModel(normalizedModel)) {\n throw new Error(`Unsupported Deepseek model: ${normalizedModel}. Please use 'deepseek-chat' or 'deepseek-reasoner'.`);\n }\n\n // Check if tools are requested with a model that doesn't support them\n if (options.tools && options.tools.length > 0 && !supportsToolCalling(normalizedModel)) {\n throw new Error(`Model ${normalizedModel} does not support tool calling.`);\n }\n\n const apiKey = options.apiKey || process.env.DEEPSEEK_API_KEY;\n if (!apiKey) {\n throw new Error('Deepseek API key is not provided and DEEPSEEK_API_KEY environment variable is not set');\n }\n\n // Initialize OpenAI client with Deepseek API URL\n const openai = new OpenAI({\n apiKey,\n baseURL: 'https://api.deepseek.com',\n });\n\n const messages: ChatCompletionMessageParam[] = [];\n\n // Add system message with developer prompt if present\n if (options.developerPrompt) {\n messages.push({\n role: 'system',\n content: options.developerPrompt,\n });\n }\n\n // Add context if present\n if (options.context) {\n messages.push(...options.context);\n }\n\n // Add user content\n if (typeof content === 'string') {\n messages.push({\n role: 'user',\n content,\n });\n } else {\n messages.push({\n role: 'user',\n content,\n });\n }\n\n // If JSON response format, include a hint in the system prompt\n if ((responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) \n && supportsJsonOutput(normalizedModel)) {\n // If there's no system message yet, add one\n if (!messages.some(m => m.role === 'system')) {\n messages.unshift({\n role: 'system',\n content: 'Please respond in valid JSON format.',\n });\n } else {\n // Append to existing system message\n const systemMsgIndex = messages.findIndex(m => m.role === 'system');\n const systemMsg = messages[systemMsgIndex];\n if (typeof systemMsg.content === 'string') {\n messages[systemMsgIndex] = {\n ...systemMsg,\n content: `${systemMsg.content} Please respond in valid JSON format.`,\n };\n }\n }\n }\n\n const queryOptions: ChatCompletionCreateParams = {\n model: normalizedModel,\n messages,\n response_format: getDeepseekResponseFormatOption(responseFormat, normalizedModel),\n temperature: options.temperature,\n top_p: options.top_p,\n frequency_penalty: options.frequency_penalty,\n presence_penalty: options.presence_penalty,\n max_tokens: options.max_completion_tokens,\n };\n\n // Only add tools if the model supports them\n if (options.tools && supportsToolCalling(normalizedModel)) {\n queryOptions.tools = options.tools;\n }\n\n try {\n const completion = await openai.chat.completions.create(queryOptions);\n\n return {\n id: completion.id,\n content: completion.choices[0]?.message?.content || '',\n tool_calls: completion.choices[0]?.message?.tool_calls,\n usage: completion.usage || {\n prompt_tokens: 0,\n completion_tokens: 0,\n total_tokens: 0,\n },\n system_fingerprint: completion.system_fingerprint,\n provider: 'deepseek',\n model: normalizedModel as DeepseekModel,\n };\n } catch (error) {\n console.error('Error calling Deepseek API:', error);\n throw error;\n }\n}\n\n/**\n * Makes a call to the Deepseek AI API.\n *\n * @param content The content to pass to the LLM. Can be a string or an array of content parts.\n * @param responseFormat The format of the response. Defaults to 'json'.\n * @param options Configuration options including model ('deepseek-chat' or 'deepseek-reasoner'), tools, and apiKey.\n * @return A promise that resolves to the response from the Deepseek API.\n */\nexport const makeDeepseekCall = async <T = string>(\n content: string | ChatCompletionContentPart[],\n responseFormat: OpenAIResponseFormat = 'json',\n options: LLMOptions = {}\n): Promise<LLMResponse<T>> => {\n // Set default model if not provided\n const mergedOptions = {\n ...options,\n };\n\n if (!mergedOptions.model) {\n mergedOptions.model = DEFAULT_DEEPSEEK_OPTIONS.defaultModel;\n }\n\n const modelName = normalizeModelName(mergedOptions.model as string);\n \n // Check if the requested response format is compatible with the model\n if (responseFormat !== 'text' && !supportsJsonOutput(modelName)) {\n console.warn(`Model ${modelName} does not support JSON output. Will return error in the response.`);\n return {\n response: {\n error: `Model ${modelName} does not support JSON output format.`\n } as unknown as T,\n usage: {\n prompt_tokens: 0,\n completion_tokens: 0,\n reasoning_tokens: 0,\n provider: 'deepseek',\n model: modelName as DeepseekModel,\n cache_hit_tokens: 0,\n cost: 0,\n },\n tool_calls: undefined,\n };\n }\n\n // Check if tools are requested with a model that doesn't support them\n if (mergedOptions.tools && mergedOptions.tools.length > 0 && !supportsToolCalling(modelName)) {\n console.warn(`Model ${modelName} does not support tool calling. Will return error in the response.`);\n return {\n response: {\n error: `Model ${modelName} does not support tool calling.`\n } as unknown as T,\n usage: {\n prompt_tokens: 0,\n completion_tokens: 0,\n reasoning_tokens: 0,\n provider: 'deepseek',\n model: modelName as DeepseekModel,\n cache_hit_tokens: 0,\n cost: 0,\n },\n tool_calls: undefined,\n };\n }\n\n try {\n const completion = await createDeepseekCompletion(content, responseFormat, mergedOptions);\n\n // Handle tool calls similarly to OpenAI\n if (completion.tool_calls && completion.tool_calls.length > 0) {\n const fnCalls = completion.tool_calls\n .filter((tc) => tc.type === 'function')\n .map((tc) => ({\n id: tc.id,\n name: (tc as Extract<typeof tc, { type: 'function' }>).function.name,\n arguments: JSON.parse((tc as Extract<typeof tc, { type: 'function' }>).function.arguments),\n }));\n return {\n response: { tool_calls: fnCalls } as T,\n usage: {\n prompt_tokens: completion.usage.prompt_tokens,\n completion_tokens: completion.usage.completion_tokens,\n reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately\n provider: 'deepseek',\n model: completion.model,\n cache_hit_tokens: 0, // Not provided directly in API response\n cost: calculateCost(\n 'deepseek',\n completion.model,\n completion.usage.prompt_tokens,\n completion.usage.completion_tokens,\n 0,\n 0 // Cache hit tokens (not provided in the response)\n ),\n },\n tool_calls: completion.tool_calls,\n };\n }\n\n // Handle regular responses\n const parsedResponse = await parseResponse<T>(completion.content, responseFormat);\n if (parsedResponse === null) {\n throw new Error('Failed to parse Deepseek response');\n }\n\n return {\n response: parsedResponse,\n usage: {\n prompt_tokens: completion.usage.prompt_tokens,\n completion_tokens: completion.usage.completion_tokens,\n reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately\n provider: 'deepseek',\n model: completion.model,\n cache_hit_tokens: 0, // Not provided directly in API response\n cost: calculateCost(\n 'deepseek',\n completion.model,\n completion.usage.prompt_tokens,\n completion.usage.completion_tokens,\n 0,\n 0 // Cache hit tokens (not provided in the response)\n ),\n },\n tool_calls: completion.tool_calls,\n };\n } catch (error) {\n // If there's an error due to incompatible features, return a structured error\n console.error('Error in Deepseek API call:', error);\n return {\n response: {\n error: error instanceof Error ? error.message : 'Unknown error'\n } as unknown as T,\n usage: {\n prompt_tokens: 0,\n completion_tokens: 0,\n reasoning_tokens: 0,\n provider: 'deepseek',\n model: modelName as DeepseekModel,\n cache_hit_tokens: 0,\n cost: 0,\n },\n tool_calls: undefined,\n };\n }\n};\n", "// llm-openrouter.ts\n\nimport OpenAI from 'openai';\nimport type {\n ChatCompletionMessageParam,\n ChatCompletionMessageToolCall,\n ChatCompletionTool,\n ChatCompletionToolChoiceOption,\n} from 'openai/resources/chat/completions';\n\nimport { calculateCost, DEFAULT_MODEL } from './llm-config';\nimport { parseResponse, normalizeModelName } from './llm-utils';\nimport type {\n LLMResponse,\n ContextMessage,\n OpenAIResponseFormat,\n LLMModel,\n OpenAIModel,\n DeepseekModel,\n OpenRouterModel,\n} from './types/llm-types';\nimport { isOpenRouterModel } from './types/llm-types';\n\n// Use the SDK's tool choice type, compatible with OpenRouter\ntype ToolChoice = ChatCompletionToolChoiceOption;\n\n// Map our ContextMessage to OpenAI chat message\nfunction mapContextToMessages(context: ContextMessage[]): ChatCompletionMessageParam[] {\n return context.map((msg) => {\n const role = msg.role === 'developer' ? 'system' : msg.role;\n return { role, content: msg.content } as ChatCompletionMessageParam;\n });\n}\n\nfunction toOpenRouterModel(model?: string): string {\n if (model && model.includes('/')) return model;\n const base = normalizeModelName(model || DEFAULT_MODEL);\n return `openai/${base}`;\n}\n\n// Normalize model name for pricing\nfunction normalizeModelForPricing(model: string | undefined): { provider: 'openai' | 'deepseek'; coreModel: string } {\n if (!model) return { provider: 'openai', coreModel: normalizeModelName(DEFAULT_MODEL) };\n const [maybeProvider, maybeModel] = model.includes('/') ? model.split('/') : ['openai', model];\n const provider = (maybeProvider === 'deepseek' ? 'deepseek' : 'openai') as 'openai' | 'deepseek';\n const coreModel = normalizeModelName(maybeModel || model);\n return { provider, coreModel };\n}\n\nexport interface OpenRouterCallOptions {\n apiKey?: string;\n model?: OpenRouterModel | string; // OpenRouter model id (e.g., \"openai/gpt-5-mini\") or plain (\"gpt-5-mini\")\n responseFormat?: 'text' | 'json' | OpenAIResponseFormat;\n tools?: ChatCompletionTool[];\n toolChoice?: ToolChoice;\n context?: ContextMessage[];\n developerPrompt?: string;\n temperature?: number;\n max_tokens?: number;\n top_p?: number;\n frequency_penalty?: number;\n presence_penalty?: number;\n stop?: string | string[];\n seed?: number;\n // Optional headers for OpenRouter ranking\n referer?: string;\n title?: string;\n}\n\n/**\n * Make a call through OpenRouter using the OpenAI Chat Completions-compatible API.\n * Supports: JSON mode, model selection, message history, and tools.\n */\nexport async function makeOpenRouterCall<T = string>(\n input: string,\n options: OpenRouterCallOptions = {}\n): Promise<LLMResponse<T>> {\n const {\n apiKey = process.env.OPENROUTER_API_KEY,\n model,\n responseFormat = 'text',\n tools,\n toolChoice,\n context,\n developerPrompt,\n temperature = 0.2,\n max_tokens,\n top_p,\n frequency_penalty,\n presence_penalty,\n stop,\n seed,\n referer = process.env.OPENROUTER_SITE_URL,\n title = process.env.OPENROUTER_SITE_NAME,\n } = options;\n\n if (!apiKey) {\n throw new Error('OpenRouter API key is not provided and OPENROUTER_API_KEY is not set');\n }\n\n const client = new OpenAI({\n apiKey,\n baseURL: 'https://openrouter.ai/api/v1',\n defaultHeaders: {\n ...(referer ? { 'HTTP-Referer': referer } : {}),\n ...(title ? { 'X-Title': title } : {}),\n },\n });\n\n const messages: ChatCompletionMessageParam[] = [];\n if (developerPrompt && developerPrompt.trim()) {\n messages.push({ role: 'system', content: developerPrompt });\n }\n if (context && context.length > 0) {\n messages.push(...mapContextToMessages(context));\n }\n messages.push({ role: 'user', content: input });\n\n // Configure response_format\n let response_format: { type: 'json_object' } | undefined;\n let parsingFormat: OpenAIResponseFormat = 'text';\n if (responseFormat === 'json') {\n response_format = { type: 'json_object' };\n parsingFormat = 'json';\n } else if (typeof responseFormat === 'object') {\n response_format = { type: 'json_object' };\n parsingFormat = responseFormat;\n }\n\n const modelId = toOpenRouterModel(model);\n\n const completion = await client.chat.completions.create({\n model: modelId,\n messages,\n response_format,\n tools,\n tool_choice: toolChoice,\n temperature,\n max_tokens,\n top_p,\n frequency_penalty,\n presence_penalty,\n stop,\n seed,\n });\n\n const choice = completion.choices && completion.choices.length > 0 ? completion.choices[0] : undefined;\n const message = (choice && 'message' in choice ? choice.message : undefined) as\n | { content: string | null; role: string; tool_calls?: ChatCompletionMessageToolCall[] }\n | undefined;\n\n const { provider: pricingProvider, coreModel } = normalizeModelForPricing(modelId);\n const promptTokens = completion.usage?.prompt_tokens ?? 0;\n const completionTokens = completion.usage?.completion_tokens ?? 0;\n const cost = calculateCost(pricingProvider, coreModel, promptTokens, completionTokens);\n\n // Tool calls branch: return empty string response and expose tool_calls on LLMResponse\n const hasToolCalls = Array.isArray(message?.tool_calls) && message!.tool_calls!.length > 0;\n if (hasToolCalls) {\n const usageModel: LLMModel = isOpenRouterModel(modelId) ? modelId : (DEFAULT_MODEL as LLMModel);\n return {\n response: '' as T,\n usage: {\n prompt_tokens: promptTokens,\n completion_tokens: completionTokens,\n provider: 'openrouter',\n model: usageModel,\n cost,\n },\n tool_calls: message!.tool_calls as ChatCompletionMessageToolCall[],\n };\n }\n\n const rawText = typeof message?.content === 'string' ? message.content : '';\n const parsed = await parseResponse<T>(rawText, parsingFormat);\n if (parsed === null) {\n throw new Error('Failed to parse OpenRouter response');\n }\n\n // Ensure the model value conforms to LLMModel; otherwise fall back to DEFAULT_MODEL\n const usageModel: LLMModel = isOpenRouterModel(modelId) ? modelId : (DEFAULT_MODEL as LLMModel);\n\n return {\n response: parsed,\n usage: {\n prompt_tokens: promptTokens,\n completion_tokens: completionTokens,\n provider: 'openrouter',\n model: usageModel,\n cost,\n },\n ...(hasToolCalls ? { tool_calls: message!.tool_calls as ChatCompletionMessageToolCall[] } : {}),\n };\n}\n\nexport default makeOpenRouterCall;\n", "/**\n * A class to measure performance of code execution.\n *\n * This utility records elapsed time during execution and provides a detailed \n * breakdown of elapsed time between checkpoints.\n *\n * Usage example:\n * const timer = new PerformanceTimer();\n * timer.checkpoint('Start Processing');\n * // ... code for processing\n * timer.checkpoint('After Task 1');\n * // ... additional processing code\n * timer.stop();\n * console.log(timer.generateReport());\n *\n * Methods:\n * - checkpoint(label: string): Record a timestamped checkpoint.\n * - stop(): Stop the timer and compute the total elapsed time.\n * - generateReport(): Return a performance report with total time and phases.\n * - formatPerformanceReport(): Return a formatted string of the performance report.\n * - getElapsedSeconds(): Get the current elapsed time in seconds.\n */\nexport class PerformanceTimer {\n private startTime: number;\n private checkpoints: Map<string, number>;\n private totalTime: number | null;\n\n constructor() {\n this.startTime = performance.now();\n this.checkpoints = new Map();\n this.totalTime = null;\n }\n\n /**\n * Gets the current elapsed time in seconds.\n * \n * @returns The elapsed time in seconds with 3 decimal places of precision.\n */\n getElapsedSeconds(): number {\n const elapsedMs = this.totalTime ?? (performance.now() - this.startTime);\n return Number((elapsedMs / 1000).toFixed(3));\n }\n\n /**\n * Records a checkpoint with the given label.\n *\n * @param label - A descriptive label for the checkpoint.\n */\n checkpoint(label: string): void {\n this.checkpoints.set(label, performance.now());\n }\n\n /**\n * Stops the timer and sets the total elapsed time.\n */\n stop(): void {\n this.totalTime = performance.now() - this.startTime;\n }\n\n /**\n * Generates a performance report containing the total elapsed time and \n * breakdown of phases between checkpoints.\n *\n * @returns A performance report object.\n * @throws Error if the timer is not stopped before generating the report.\n */\n analyseReportData(): PerformanceReport {\n if (this.totalTime === null) {\n throw new Error('Timer must be stopped before generating report');\n }\n\n const report: PerformanceReport = {\n totalTime: this.totalTime,\n phases: []\n };\n\n let lastTime = this.startTime;\n\n // Convert checkpoints to a sorted array by time\n const sortedCheckpoints = Array.from(this.checkpoints.entries())\n .sort((a, b) => a[1] - b[1]);\n\n for (const [label, time] of sortedCheckpoints) {\n const duration = time - lastTime;\n if (duration < 0) {\n throw new Error(`Negative duration detected for checkpoint: ${label}`);\n }\n report.phases.push({\n label,\n duration\n });\n lastTime = time;\n }\n\n // Add final phase from last checkpoint to stop\n if (sortedCheckpoints.length > 0) {\n const finalDuration = this.totalTime - lastTime;\n report.phases.push({\n label: 'Final Processing',\n duration: Math.max(finalDuration, 0) // Prevent negative duration\n });\n }\n return report;\n }\n\n /**\n * Returns a formatted string of the performance report.\n *\n * @returns A string detailing the total execution time and phase breakdown.\n */\n public generateReport(): string {\n const report = this.analyseReportData();\n \n // Format numbers with thousands separators and 2 decimal places\n const formatNumber = (num: number) => \n num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });\n\n // Calculate column widths\n const maxLabelLength = Math.max(...report.phases.map(p => p.label.length), 30);\n const maxDurationLength = Math.max(...report.phases.map(p => formatNumber(p.duration).length), 10);\n\n // Create table header\n let output = `\u2554${'\u2550'.repeat(maxLabelLength + 2)}\u2566${'\u2550'.repeat(maxDurationLength + 2)}\u2557\\n`;\n output += `\u2551 ${'Phase'.padEnd(maxLabelLength)} \u2551 ${'Time (ms)'.padEnd(maxDurationLength)} \u2551\\n`;\n output += `\u2560${'\u2550'.repeat(maxLabelLength + 2)}\u256C${'\u2550'.repeat(maxDurationLength + 2)}\u2563\\n`;\n\n // Add table rows\n report.phases.forEach(phase => {\n output += `\u2551 ${phase.label.padEnd(maxLabelLength)} \u2551 ${formatNumber(phase.duration).padStart(maxDurationLength)} \u2551\\n`;\n });\n\n // Add table footer with total\n output += `\u2560${'\u2550'.repeat(maxLabelLength + 2)}\u256C${'\u2550'.repeat(maxDurationLength + 2)}\u2563\\n`;\n output += `\u2551 ${'Total'.padEnd(maxLabelLength)} \u2551 ${formatNumber(report.totalTime).padStart(maxDurationLength)} \u2551\\n`;\n output += `\u255A${'\u2550'.repeat(maxLabelLength + 2)}\u2569${'\u2550'.repeat(maxDurationLength + 2)}\u255D\\n`;\n\n return output;\n }\n}\n\n/**\n * Interface representing a single phase of performance measurement.\n */\nexport interface PerformancePhase {\n label: string;\n duration: number;\n}\n\n/**\n * Interface representing the full performance report.\n */\nexport interface PerformanceReport {\n totalTime: number;\n phases: PerformancePhase[];\n}\n", "import WebSocket from 'ws';\nimport { log as baseLog } from './logging';\nimport {\n AlpacaAccountDetails,\n AlpacaAPIErrorResponse,\n AlpacaCredentials,\n AlpacaRequestContext,\n AlpacaPosition,\n AssetClass,\n GetOptionContractsParams,\n GetOrdersParams,\n JsonObject,\n JsonValue,\n OptionAccountActivity,\n OptionContract,\n OptionContractsResponse,\n AlpacaOrder,\n OrderLeg,\n TradeUpdate,\n CreateOrderParams,\n CreateMultiLegOrderParams,\n PortfolioHistoryResponse,\n EquitiesTradeOptions,\n} from './types/alpaca-types';\nimport { LogOptions } from './types/logging-types';\nimport { marketDataAPI } from './alpaca-market-data-api';\nimport { getTradingDate } from './market-time';\n\nconst limitPriceSlippagePercent100 = 0.1; // 0.1%\n\ntype AlpacaRequestBody = CreateOrderParams | CreateMultiLegOrderParams | JsonObject;\n\nclass AlpacaRequestError extends Error {\n readonly method: string;\n readonly status: number | null;\n readonly url: string;\n readonly responseCode: number | null;\n readonly responseDetails: AlpacaAPIErrorResponse | null;\n readonly rawResponse: string | null;\n readonly symbol?: string;\n\n constructor(params: {\n message: string;\n method: string;\n status?: number;\n url: string;\n responseCode?: number | null;\n responseDetails?: AlpacaAPIErrorResponse | null;\n rawResponse?: string | null;\n symbol?: string;\n }) {\n super(params.message);\n this.name = 'AlpacaRequestError';\n this.method = params.method;\n this.status = params.status ?? null;\n this.url = params.url;\n this.responseCode = params.responseCode ?? null;\n this.responseDetails = params.responseDetails ?? null;\n this.rawResponse = params.rawResponse ?? null;\n this.symbol = params.symbol;\n }\n}\n\n/** \nWebsocket example\n const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials\n alpacaAPI.onTradeUpdate((update: TradeUpdate) => {\n this.log(`Received trade update: event ${update.event} for an order to ${update.order.side} ${update.order.qty} of ${update.order.symbol}`);\n });\n alpacaAPI.connectWebsocket(); // necessary to connect to the WebSocket\n\nPortfolio History examples\n // Get standard portfolio history\n const portfolioHistory = await alpacaAPI.getPortfolioHistory({\n timeframe: '1D',\n period: '1M'\n });\n\n // Get daily portfolio history with current day included (if available from hourly data)\n const dailyHistory = await alpacaAPI.getPortfolioDailyHistory({\n period: '1M'\n });\n*/\n\nexport class AlpacaTradingAPI {\n static new(credentials: AlpacaCredentials): AlpacaTradingAPI {\n return new AlpacaTradingAPI(credentials) as AlpacaTradingAPI;\n }\n\n static getInstance(credentials: AlpacaCredentials): AlpacaTradingAPI {\n return new AlpacaTradingAPI(credentials) as AlpacaTradingAPI;\n }\n\n private ws: WebSocket | null = null;\n private headers: Record<string, string>;\n private tradeUpdateCallback: ((update: TradeUpdate) => void) | null = null;\n private credentials: AlpacaCredentials;\n private apiBaseUrl: string;\n private wsUrl: string;\n private authenticated = false;\n private connecting = false;\n private reconnectDelay = 10000; // 10 seconds between reconnection attempts\n private reconnectTimeout: NodeJS.Timeout | null = null;\n private messageHandlers: Map<string, (data: any) => void> = new Map();\n private debugLogging = false;\n private manualDisconnect = false;\n\n /**\n * Constructor for AlpacaTradingAPI\n * @param credentials - Alpaca credentials,\n * accountName: string; // The account identifier used inthis.logs and tracking\n * apiKey: string; // Alpaca API key\n * apiSecret: string; // Alpaca API secret\n * type: AlpacaAccountType;\n * orderType: AlpacaOrderType;\n * @param options - Optional options\n * debugLogging: boolean; // Whether to log messages of type 'debug'\n */\n constructor(credentials: AlpacaCredentials, options?: { debugLogging?: boolean }) {\n this.credentials = credentials;\n\n // Set URLs based on account type\n this.apiBaseUrl =\n credentials.type === 'PAPER' ? 'https://paper-api.alpaca.markets/v2' : 'https://api.alpaca.markets/v2';\n\n this.wsUrl =\n credentials.type === 'PAPER' ? 'wss://paper-api.alpaca.markets/stream' : 'wss://api.alpaca.markets/stream';\n\n this.headers = {\n 'APCA-API-KEY-ID': credentials.apiKey,\n 'APCA-API-SECRET-KEY': credentials.apiSecret,\n 'Content-Type': 'application/json',\n };\n\n // Initialize message handlers\n this.messageHandlers.set('authorization', this.handleAuthMessage.bind(this));\n this.messageHandlers.set('listening', this.handleListenMessage.bind(this));\n this.messageHandlers.set('trade_updates', this.handleTradeUpdate.bind(this));\n\n this.debugLogging = options?.debugLogging || false;\n }\n\n private log(message: string, options: LogOptions = { type: 'info' }): void {\n if (this.debugLogging && options.type === 'debug') {\n return;\n }\n baseLog(message, { ...options, source: 'AlpacaTradingAPI', account: this.credentials.accountName });\n }\n\n /**\n * Round a price to the nearest 2 decimal places for Alpaca, or 4 decimal places for prices less than $1\n * @param price - The price to round\n * @returns The rounded price\n */\n private roundPriceForAlpaca = (price: number): number => {\n return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;\n };\n\n private isJsonObject(value: JsonValue): value is JsonObject {\n return value !== null && !Array.isArray(value) && typeof value === 'object';\n }\n\n private parseAlpacaAPIErrorResponse(rawResponse: string): AlpacaAPIErrorResponse | null {\n if (rawResponse.trim() === '') {\n return null;\n }\n\n try {\n const parsedValue = JSON.parse(rawResponse) as JsonValue;\n if (!this.isJsonObject(parsedValue)) {\n return null;\n }\n\n const code = parsedValue['code'];\n const message = parsedValue['message'];\n const symbol = parsedValue['symbol'];\n\n if (typeof code !== 'number' || typeof message !== 'string') {\n return null;\n }\n\n if (symbol !== undefined && typeof symbol !== 'string') {\n return null;\n }\n\n return parsedValue as AlpacaAPIErrorResponse;\n } catch {\n return null;\n }\n }\n\n private formatJsonValueForLog(value: JsonValue | undefined): string {\n if (value === undefined) {\n return 'undefined';\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');\n }\n\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'object') {\n return JSON.stringify(value);\n }\n\n return `${value}`;\n }\n\n private formatAlpacaAPIErrorDetails(errorResponse: AlpacaAPIErrorResponse): string {\n return Object.entries(errorResponse)\n .filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')\n .map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)\n .join(', ');\n }\n\n private formatRequestAction(requestContext?: AlpacaRequestContext): string {\n return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';\n }\n\n private buildAlpacaAPIErrorMessage(params: {\n requestContext?: AlpacaRequestContext;\n status: number;\n url: string;\n errorResponse: AlpacaAPIErrorResponse | null;\n rawResponse: string;\n }): string {\n const { requestContext, status, url, errorResponse, rawResponse } = params;\n const action = this.formatRequestAction(requestContext);\n const message = errorResponse?.message ?? (rawResponse || 'No error body returned');\n const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';\n const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';\n const detailText =\n detailSummary !== ''\n ? ` Details: ${detailSummary}.`\n : rawResponse.trim() !== '' && errorResponse === null\n ? ` Response: ${rawResponse}.`\n : '';\n\n return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;\n }\n\n private buildRequestExecutionErrorMessage(params: {\n requestContext?: AlpacaRequestContext;\n url: string;\n errorMessage: string;\n }): string {\n const { requestContext, url, errorMessage } = params;\n const action = this.formatRequestAction(requestContext);\n return `${action}: ${errorMessage}. Url: ${url}`;\n }\n\n private handleAuthMessage(data: any): void {\n if (data.status === 'authorized') {\n this.authenticated = true;\n this.log('WebSocket authenticated');\n } else {\n this.log(`Authentication failed: ${data.message || 'Unknown error'}`, {\n type: 'error',\n });\n }\n }\n\n private handleListenMessage(data: any): void {\n if (data.streams?.includes('trade_updates')) {\n this.log('Successfully subscribed to trade updates');\n }\n }\n\n private handleTradeUpdate(data: TradeUpdate): void {\n if (this.tradeUpdateCallback) {\n this.log(\n `Trade update: ${data.event} to ${data.order.side} ${data.order.qty} shares${\n data.event === 'partial_fill' ? ` (filled shares: ${data.order.filled_qty})` : ''\n }, type ${data.order.type}`,\n {\n symbol: data.order.symbol,\n type: 'debug',\n }\n );\n this.tradeUpdateCallback(data);\n }\n }\n\n private handleMessage(message: string): void {\n try {\n const data = JSON.parse(message);\n const handler = this.messageHandlers.get(data.stream);\n\n if (handler) {\n handler(data.data);\n } else {\n this.log(`Received message for unknown stream: ${data.stream}`, {\n type: 'warn',\n });\n }\n } catch (error) {\n this.log('Failed to parse WebSocket message', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n }\n }\n\n connectWebsocket(): void {\n // Reset manual disconnect flag to allow reconnection logic\n this.manualDisconnect = false;\n if (this.connecting) {\n this.log('Connection attempt skipped - already connecting');\n return;\n }\n\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.log('Connection attempt skipped - already connected');\n return;\n }\n\n this.connecting = true;\n\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws.terminate();\n this.ws = null;\n }\n\n this.log(`Connecting to WebSocket at ${this.wsUrl}...`);\n\n this.ws = new WebSocket(this.wsUrl);\n\n this.ws.on('open', async () => {\n try {\n this.log('WebSocket connected');\n await this.authenticate();\n await this.subscribeToTradeUpdates();\n this.connecting = false;\n } catch (error) {\n this.log('Failed to setup WebSocket connection', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n this.ws?.close();\n }\n });\n\n this.ws.on('message', (data: WebSocket.Data) => {\n this.handleMessage(data.toString());\n });\n\n this.ws.on('error', (error) => {\n this.log('WebSocket error', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n this.connecting = false;\n });\n\n this.ws.on('close', () => {\n this.log('WebSocket connection closed');\n this.authenticated = false;\n this.connecting = false;\n\n // Clear any existing reconnect timeout\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n\n // Schedule reconnection unless this was a manual disconnect\n if (!this.manualDisconnect) {\n this.reconnectTimeout = setTimeout(() => {\n this.log('Attempting to reconnect...');\n this.connectWebsocket();\n }, this.reconnectDelay);\n }\n });\n }\n\n /**\n * Cleanly disconnect from the WebSocket and stop auto-reconnects\n */\n disconnect(): void {\n // Prevent auto-reconnect scheduling\n this.manualDisconnect = true;\n\n // Clear any scheduled reconnect\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n\n if (this.ws) {\n this.log('Disconnecting WebSocket...');\n\n // Remove listeners first to avoid duplicate handlers after reconnects\n this.ws.removeAllListeners();\n\n try {\n // Attempt graceful close\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close(1000, 'Client disconnect');\n } else {\n this.ws.terminate();\n }\n } catch {\n // Fallback terminate on any error\n try {\n this.ws.terminate();\n } catch {\n /* no-op */\n }\n }\n\n this.ws = null;\n }\n\n this.authenticated = false;\n this.connecting = false;\n this.log('WebSocket disconnected');\n }\n\n private async authenticate(): Promise<void> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not ready for authentication');\n }\n\n const authMessage = {\n action: 'auth',\n key: this.credentials.apiKey,\n secret: this.credentials.apiSecret,\n };\n\n this.ws.send(JSON.stringify(authMessage));\n\n return new Promise((resolve, reject) => {\n const authTimeout = setTimeout(() => {\n this.log('Authentication timeout', { type: 'error' });\n reject(new Error('Authentication timed out'));\n }, 10000);\n\n const handleAuthResponse = (data: WebSocket.Data) => {\n try {\n const message = JSON.parse(data.toString());\n if (message.stream === 'authorization') {\n this.ws?.removeListener('message', handleAuthResponse);\n clearTimeout(authTimeout);\n\n if (message.data?.status === 'authorized') {\n this.authenticated = true;\n resolve();\n } else {\n const error = `Authentication failed: ${message.data?.message || 'Unknown error'}`;\n this.log(error, { type: 'error' });\n reject(new Error(error));\n }\n }\n } catch (error) {\n this.log('Failed to parse auth response', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n }\n };\n\n this.ws?.on('message', handleAuthResponse);\n });\n }\n\n private async subscribeToTradeUpdates(): Promise<void> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN || !this.authenticated) {\n throw new Error('WebSocket not ready for subscription');\n }\n\n const listenMessage = {\n action: 'listen',\n data: {\n streams: ['trade_updates'],\n },\n };\n\n this.ws.send(JSON.stringify(listenMessage));\n\n return new Promise((resolve, reject) => {\n const listenTimeout = setTimeout(() => {\n reject(new Error('Subscribe timeout'));\n }, 10000);\n\n const handleListenResponse = (data: WebSocket.Data) => {\n try {\n const message = JSON.parse(data.toString());\n if (message.stream === 'listening') {\n this.ws?.removeListener('message', handleListenResponse);\n clearTimeout(listenTimeout);\n\n if (message.data?.streams?.includes('trade_updates')) {\n resolve();\n } else {\n reject(new Error('Failed to subscribe to trade updates'));\n }\n }\n } catch (error) {\n this.log('Failed to parse listen response', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n }\n };\n\n this.ws?.on('message', handleListenResponse);\n });\n }\n\n private async makeRequest<TResponse>(\n endpoint: string,\n method: string = 'GET',\n body?: AlpacaRequestBody,\n queryString: string = '',\n requestContext?: AlpacaRequestContext\n ): Promise<TResponse> {\n const url = `${this.apiBaseUrl}${endpoint}${queryString}`;\n try {\n const response = await fetch(url, {\n method,\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const rawResponse = await response.text();\n const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);\n const symbol = requestContext?.symbol ?? errorResponse?.symbol;\n const error = new AlpacaRequestError({\n message: this.buildAlpacaAPIErrorMessage({\n requestContext,\n status: response.status,\n url,\n errorResponse,\n rawResponse,\n }),\n method,\n status: response.status,\n url,\n responseCode: errorResponse?.code ?? null,\n responseDetails: errorResponse,\n rawResponse,\n symbol,\n });\n\n this.log(error.message, { symbol, type: 'error' });\n throw error;\n }\n\n // Handle responses with no content (e.g., 204 No Content)\n if (response.status === 204 || response.headers.get('content-length') === '0') {\n return null as TResponse;\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType && contentType.includes('application/json')) {\n return (await response.json()) as TResponse;\n }\n\n // For non-JSON responses, return the text content\n const textContent = await response.text();\n return (textContent || null) as TResponse;\n } catch (error) {\n if (error instanceof AlpacaRequestError) {\n throw error;\n }\n\n const normalizedError = error instanceof Error ? error : new Error(`${error}`);\n const symbol = requestContext?.symbol;\n const requestError = new AlpacaRequestError({\n message: this.buildRequestExecutionErrorMessage({\n requestContext,\n url,\n errorMessage: normalizedError.message,\n }),\n method,\n url,\n rawResponse: null,\n symbol,\n });\n\n this.log(requestError.message, { symbol, type: 'error' });\n throw requestError;\n }\n }\n\n async getPositions(assetClass?: AssetClass): Promise<AlpacaPosition[]> {\n const positions = await this.makeRequest<AlpacaPosition[]>('/positions', 'GET', undefined, '', {\n action: 'Get positions',\n });\n if (assetClass) {\n return positions.filter((position) => position.asset_class === assetClass);\n }\n return positions;\n }\n\n /**\n * Get all orders\n * @param params (GetOrdersParams) - optional parameters to filter the orders\n * - status: 'open' | 'closed' | 'all'\n * - limit: number\n * - after: string\n * - until: string\n * - direction: 'asc' | 'desc'\n * - nested: boolean\n * - symbols: string[], an array of all the symbols\n * - side: 'buy' | 'sell'\n * @returns all orders\n */\n async getOrders(params: GetOrdersParams = {}): Promise<AlpacaOrder[]> {\n const queryParams = new URLSearchParams();\n\n if (params.status) queryParams.append('status', params.status);\n if (params.limit) queryParams.append('limit', params.limit.toString());\n if (params.after) queryParams.append('after', params.after);\n if (params.until) queryParams.append('until', params.until);\n if (params.direction) queryParams.append('direction', params.direction);\n if (params.nested) queryParams.append('nested', params.nested.toString());\n if (params.symbols) queryParams.append('symbols', params.symbols.join(','));\n if (params.side) queryParams.append('side', params.side);\n\n const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n return this.makeRequest<AlpacaOrder[]>(endpoint, 'GET', undefined, '', {\n action: 'Get orders',\n symbol: params.symbols?.join(','),\n });\n }\n\n async getAccountDetails(): Promise<AlpacaAccountDetails> {\n return this.makeRequest<AlpacaAccountDetails>('/account', 'GET', undefined, '', {\n action: 'Get account details',\n });\n }\n\n /**\n * Create a trailing stop order\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param trailPercent100 (number) - the trail percent of the order (scale 100, i.e. 0.5 = 0.5%)\n * @param position_intent (string) - the position intent of the order\n * @param client_order_id (string) - optional client order id\n * @returns The created trailing stop order\n */\n async createTrailingStop(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n trailPercent100: number,\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating trailing stop ${side.toUpperCase()} ${qty} shares for ${symbol} with trail percent ${trailPercent100}%`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n order_class: 'simple',\n type: 'trailing_stop',\n trail_percent: trailPercent100.toString(),\n time_in_force: 'gtc',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create trailing stop order',\n symbol,\n });\n }\n\n /**\n * Create a stop order (stop or stop-limit)\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param stopPrice (number) - the stop price that triggers the order\n * @param position_intent (string) - the position intent of the order\n * @param limitPrice (number) - optional limit price (if provided, creates a stop-limit order)\n * @param client_order_id (string) - optional client order id\n * @returns The created stop order\n */\n async createStopOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n stopPrice: number,\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n limitPrice?: number,\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n const isStopLimit = limitPrice !== undefined;\n const orderType = isStopLimit ? 'stop-limit' : 'stop';\n\n this.log(\n `Creating ${orderType} ${side.toUpperCase()} ${qty} shares for ${symbol} with stop price ${stopPrice}${isStopLimit ? ` and limit price ${limitPrice}` : ''}`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n order_class: 'simple',\n type: isStopLimit ? 'stop_limit' : 'stop',\n stop_price: this.roundPriceForAlpaca(stopPrice).toString(),\n time_in_force: 'gtc',\n };\n\n if (limitPrice !== undefined) {\n body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: `Create ${orderType} order`,\n symbol,\n });\n }\n\n /**\n * Create a market order\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param position_intent (string) - the position intent of the order. Important for knowing if a position needs a trailing stop.\n * @param client_order_id (string) - optional client order id\n */\n async createMarketOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(`Creating market order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {\n symbol,\n });\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'market',\n time_in_force: 'day',\n order_class: 'simple',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create market order',\n symbol,\n });\n }\n\n /**\n * Create a Market on Open (MOO) order - executes in the opening auction\n *\n * IMPORTANT TIMING CONSTRAINTS:\n * - Valid submission window: After 7:00pm ET and before 9:28am ET\n * - Orders submitted between 9:28am and 7:00pm ET will be REJECTED\n * - Orders submitted after 7:00pm ET are queued for the next trading day's opening auction\n * - Example: An order at 8:00pm Monday will execute at Tuesday's market open (9:30am)\n *\n * @param symbol - The symbol of the order\n * @param qty - The quantity of shares\n * @param side - Buy or sell\n * @param position_intent - The position intent (buy_to_open, sell_to_close, etc.)\n * @param client_order_id - Optional client order id\n * @returns The created order\n */\n async createMOOOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(`Creating Market on Open order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {\n symbol,\n });\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'market',\n time_in_force: 'opg',\n order_class: 'simple',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create market on open order',\n symbol,\n });\n }\n\n /**\n * Create a Market on Close (MOC) order - executes in the closing auction\n *\n * IMPORTANT TIMING CONSTRAINTS:\n * - Valid submission window: After 7:00pm ET (previous day) and before 3:50pm ET (same day)\n * - Orders submitted between 3:50pm and 7:00pm ET will be REJECTED\n * - Orders submitted after 7:00pm ET are queued for the next trading day's closing auction\n * - Example: An order at 8:00pm Monday will execute at Tuesday's market close (4:00pm)\n *\n * @param symbol - The symbol of the order\n * @param qty - The quantity of shares\n * @param side - Buy or sell\n * @param position_intent - The position intent (buy_to_open, sell_to_close, etc.)\n * @param client_order_id - Optional client order id\n * @returns The created order\n */\n async createMOCOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(`Creating Market on Close order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {\n symbol,\n });\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'market',\n time_in_force: 'cls',\n order_class: 'simple',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create market on close order',\n symbol,\n });\n }\n\n /**\n * Create an OCO (One-Cancels-Other) order with take profit and stop loss\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order (buy or sell)\n * @param position_intent (string) - the position intent of the order\n * @param limitPrice (number) - the limit price for the entry order (OCO orders must be limit orders)\n * @param takeProfitPrice (number) - the take profit price\n * @param stopLossPrice (number) - the stop loss price\n * @param stopLossLimitPrice (number) - optional limit price for stop loss (creates stop-limit instead of stop)\n * @param client_order_id (string) - optional client order id\n * @returns The created OCO order\n */\n async createOCOOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n limitPrice: number,\n takeProfitPrice: number,\n stopLossPrice: number,\n stopLossLimitPrice?: number,\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating OCO order ${side.toUpperCase()} ${qty} shares for ${symbol} at limit ${limitPrice} with take profit ${takeProfitPrice} and stop loss ${stopLossPrice}`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n order_class: 'oco',\n type: 'limit',\n limit_price: this.roundPriceForAlpaca(limitPrice).toString(),\n time_in_force: 'gtc',\n take_profit: {\n limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),\n },\n stop_loss: {\n stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),\n },\n };\n\n // If stop loss limit price is provided, create stop-limit order\n if (stopLossLimitPrice !== undefined) {\n body.stop_loss = {\n stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),\n limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),\n };\n }\n\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create OCO order',\n symbol,\n });\n }\n\n /**\n * Get the current trail percent for a symbol, assuming that it has an open position and a trailing stop order to close it. Because this relies on an orders request for one symbol, you can't do it too often.\n * @param symbol (string) - the symbol of the order\n * @returns the current trail percent\n */\n async getCurrentTrailPercent(symbol: string): Promise<number | null> {\n const orders = await this.getOrders({\n status: 'open',\n symbols: [symbol],\n });\n\n const trailingStopOrder = orders.find(\n (order) =>\n order.type === 'trailing_stop' &&\n (order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close')\n );\n\n if (!trailingStopOrder) {\n this.log(`No closing trailing stop order found for ${symbol}`, {\n symbol,\n });\n return null;\n }\n\n if (!trailingStopOrder.trail_percent) {\n this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {\n symbol,\n });\n return null;\n }\n\n const trailPercent = parseFloat(trailingStopOrder.trail_percent);\n return trailPercent;\n }\n\n /**\n * Update the trail percent for a trailing stop order\n * @param symbol (string) - the symbol of the order\n * @param trailPercent100 (number) - the trail percent of the order (scale 100, i.e. 0.5 = 0.5%)\n */\n async updateTrailingStop(symbol: string, trailPercent100: number): Promise<void> {\n // First get all open orders for this symbol\n const orders = await this.getOrders({\n status: 'open',\n symbols: [symbol],\n });\n\n // Find the trailing stop order\n const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop');\n\n if (!trailingStopOrder) {\n this.log(`No open trailing stop order found for ${symbol}`, { type: 'error', symbol });\n return;\n }\n\n // Check if the trail_percent is already set to the desired value\n const currentTrailPercent = trailingStopOrder.trail_percent ? parseFloat(trailingStopOrder.trail_percent) : null;\n\n // Compare with a small epsilon to handle floating point precision\n const epsilon = 0.0001;\n if (currentTrailPercent !== null && Math.abs(currentTrailPercent - trailPercent100) < epsilon) {\n this.log(\n `Trailing stop for ${symbol} already set to ${trailPercent100}% (current: ${currentTrailPercent}%), skipping update`,\n {\n symbol,\n }\n );\n return;\n }\n\n this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {\n symbol,\n });\n\n await this.makeRequest<AlpacaOrder>(\n `/orders/${trailingStopOrder.id}`,\n 'PATCH',\n { trail: trailPercent100.toString() },\n '',\n {\n action: 'Update trailing stop order',\n symbol,\n }\n );\n }\n\n /**\n * Cancel all open orders\n */\n async cancelAllOrders(): Promise<void> {\n this.log(`Canceling all open orders`);\n try {\n await this.makeRequest<null>('/orders', 'DELETE', undefined, '', {\n action: 'Cancel all open orders',\n });\n } catch (error) {\n if (!(error instanceof AlpacaRequestError)) {\n this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {\n type: 'error',\n });\n }\n }\n }\n\n /**\n * Cancel a specific order by its ID\n * @param orderId The id of the order to cancel\n * @throws Error if the order is not cancelable (status 422) or if the order doesn't exist\n * @returns Promise that resolves when the order is successfully canceled\n */\n async cancelOrder(orderId: string): Promise<void> {\n this.log(`Attempting to cancel order ${orderId}`);\n\n try {\n await this.makeRequest<null>(`/orders/${orderId}`, 'DELETE', undefined, '', {\n action: `Cancel order ${orderId}`,\n });\n this.log(`Successfully canceled order ${orderId}`);\n } catch (error) {\n // If the error is a 422, it means the order is not cancelable\n if (error instanceof AlpacaRequestError && error.status === 422) {\n throw new Error(`Order ${orderId} is not cancelable`);\n }\n // Re-throw other errors\n throw error;\n }\n }\n\n /**\n * Create a limit order\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param limitPrice (number) - the limit price of the order\n * @param position_intent (string) - the position intent of the order\n * @param extended_hours (boolean) - whether the order is in extended hours\n * @param client_order_id (string) - the client order id of the order\n */\n async createLimitOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n limitPrice: number,\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n extended_hours: boolean = false,\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating limit order for ${symbol}: ${side} ${qty} shares at $${limitPrice.toFixed(2)} (${position_intent})`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'limit',\n limit_price: this.roundPriceForAlpaca(limitPrice).toString(),\n time_in_force: 'day',\n order_class: 'simple',\n extended_hours,\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create limit order',\n symbol,\n });\n }\n\n /**\n * Close all equities positions\n * @param options (object) - the options for closing the positions\n * - cancel_orders (boolean) - whether to cancel related orders\n * - useLimitOrders (boolean) - whether to use limit orders to close the positions\n */\n async closeAllPositions(\n options: { cancel_orders: boolean; useLimitOrders: boolean } = { cancel_orders: true, useLimitOrders: false }\n ): Promise<void> {\n this.log(\n `Closing all positions${options.useLimitOrders ? ' using limit orders' : ''}${\n options.cancel_orders ? ' and canceling open orders' : ''\n }`\n );\n\n if (options.useLimitOrders) {\n // Get all positions\n const positions = await this.getPositions('us_equity');\n\n if (positions.length === 0) {\n this.log('No positions to close');\n return;\n }\n\n this.log(`Found ${positions.length} positions to close`);\n\n // Get latest quotes for all positions\n const symbols = positions.map((position) => position.symbol);\n const quotesResponse = await marketDataAPI.getLatestQuotes(symbols);\n\n const lengthOfQuotes = Object.keys(quotesResponse.quotes).length;\n if (lengthOfQuotes === 0) {\n this.log('No quotes available for positions, received 0 quotes', {\n type: 'error',\n });\n return;\n }\n\n if (lengthOfQuotes !== positions.length) {\n this.log(\n `Received ${lengthOfQuotes} quotes for ${positions.length} positions, expected ${positions.length} quotes`,\n { type: 'warn' }\n );\n return;\n }\n\n // Create limit orders to close each position\n for (const position of positions) {\n const quote = quotesResponse.quotes[position.symbol];\n if (!quote) {\n this.log(`No quote available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n const qty = Math.abs(parseFloat(position.qty));\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n // Get the current price from the quote\n const currentPrice = side === 'sell' ? quote.bp : quote.ap; // Use bid for sells, ask for buys\n\n if (!currentPrice) {\n this.log(`No valid price available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n // Apply slippage from config\n const limitSlippagePercent1 = limitPriceSlippagePercent100 / 100;\n const limitPrice =\n side === 'sell'\n ? this.roundPriceForAlpaca(currentPrice * (1 - limitSlippagePercent1)) // Sell slightly lower\n : this.roundPriceForAlpaca(currentPrice * (1 + limitSlippagePercent1)); // Buy slightly higher\n\n this.log(\n `Creating limit order to close ${position.symbol} position: ${side} ${qty} shares at $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: position.symbol,\n }\n );\n\n await this.createLimitOrder(position.symbol, qty, side, limitPrice, positionIntent);\n }\n } else {\n await this.makeRequest<null>('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {\n action: 'Close all positions',\n });\n }\n }\n\n /**\n * Close all equities positions using limit orders during extended hours trading\n * @param cancelOrders Whether to cancel related orders (default: true)\n * @returns Promise that resolves when all positions are closed\n */\n async closeAllPositionsAfterHours(): Promise<void> {\n this.log('Closing all positions using limit orders during extended hours trading');\n\n // Get all positions\n const positions = await this.getPositions();\n this.log(`Found ${positions.length} positions to close`);\n\n if (positions.length === 0) {\n this.log('No positions to close');\n return;\n }\n\n await this.cancelAllOrders();\n this.log(`Cancelled all open orders`);\n\n // Get latest quotes for all positions\n const symbols = positions.map((position) => position.symbol);\n const quotesResponse = await marketDataAPI.getLatestQuotes(symbols);\n\n // Create limit orders to close each position\n for (const position of positions) {\n const quote = quotesResponse.quotes[position.symbol];\n if (!quote) {\n this.log(`No quote available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n const qty = Math.abs(parseFloat(position.qty));\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n // Get the current price from the quote\n const currentPrice = side === 'sell' ? quote.bp : quote.ap; // Use bid for sells, ask for buys\n\n if (!currentPrice) {\n this.log(`No valid price available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n // Apply slippage from config\n const limitSlippagePercent1 = limitPriceSlippagePercent100 / 100;\n const limitPrice =\n side === 'sell'\n ? this.roundPriceForAlpaca(currentPrice * (1 - limitSlippagePercent1)) // Sell slightly lower\n : this.roundPriceForAlpaca(currentPrice * (1 + limitSlippagePercent1)); // Buy slightly higher\n\n this.log(\n `Creating extended hours limit order to close ${\n position.symbol\n } position: ${side} ${qty} shares at $${limitPrice.toFixed(2)}`,\n {\n symbol: position.symbol,\n }\n );\n\n await this.createLimitOrder(\n position.symbol,\n qty,\n side,\n limitPrice,\n positionIntent,\n true // Enable extended hours trading\n );\n }\n\n this.log(`All positions closed: ${positions.map((p) => p.symbol).join(', ')}`);\n }\n\n onTradeUpdate(callback: (update: TradeUpdate) => void): void {\n this.tradeUpdateCallback = callback;\n }\n\n /**\n * Get portfolio history for the account\n * @param params Parameters for the portfolio history request\n * @returns Portfolio history data\n */\n async getPortfolioHistory(params: {\n timeframe?: '1Min' | '5Min' | '15Min' | '1H' | '1D';\n period?: string;\n start?: string; // Start date in ISO format\n end?: string; // End date in ISO format\n extended_hours?: boolean;\n date_end?: string;\n }): Promise<PortfolioHistoryResponse> {\n const queryParams = new URLSearchParams();\n if (params.timeframe) queryParams.append('timeframe', params.timeframe);\n if (params.period) queryParams.append('period', params.period);\n if (params.extended_hours !== undefined) queryParams.append('extended_hours', params.extended_hours.toString());\n if (params.start) queryParams.append('start', params.start);\n if (params.end) queryParams.append('end', params.end);\n if (params.date_end) queryParams.append('date_end', params.date_end);\n\n const response = await this.makeRequest<PortfolioHistoryResponse>(\n `/account/portfolio/history?${queryParams.toString()}`,\n 'GET',\n undefined,\n '',\n {\n action: 'Get portfolio history',\n }\n );\n return response;\n }\n\n /**\n * Get portfolio daily history for the account, ensuring the most recent day is included\n * by combining daily and hourly history if needed.\n *\n * This function performs two API calls:\n * 1. Retrieves daily portfolio history\n * 2. Retrieves hourly portfolio history to check for more recent data\n *\n * If hourly history has timestamps more recent than the last timestamp in daily history,\n * it appends one additional day to the daily history using the most recent hourly values.\n *\n * @param params Parameters for the portfolio history request (same as getPortfolioHistory except timeframe is forced to '1D')\n * @returns Portfolio history data with daily timeframe, including the most recent day if available from hourly data\n */\n async getPortfolioDailyHistory(params: {\n period?: string;\n start?: string; // Start date in ISO format\n end?: string; // End date in ISO format\n extended_hours?: boolean;\n date_end?: string;\n }): Promise<PortfolioHistoryResponse> {\n // Get daily and hourly history in parallel\n const dailyParams = { ...params, timeframe: '1D' as const };\n const hourlyParams = { timeframe: '1Min' as const, period: '1D' };\n\n const [dailyHistory, hourlyHistory] = await Promise.all([\n this.getPortfolioHistory(dailyParams),\n this.getPortfolioHistory(hourlyParams),\n ]);\n\n // If no hourly history, return daily as-is\n if (!hourlyHistory.timestamp || hourlyHistory.timestamp.length === 0) {\n return dailyHistory;\n }\n\n // Get the last timestamp from daily history\n const lastDailyTimestamp = dailyHistory.timestamp[dailyHistory.timestamp.length - 1];\n\n // Check if hourly history has more recent data\n const recentHourlyData = hourlyHistory.timestamp\n .map((timestamp, index) => ({ timestamp, index }))\n .filter(({ timestamp }) => timestamp > lastDailyTimestamp);\n\n // If no more recent hourly data, return daily history as-is\n if (recentHourlyData.length === 0) {\n return dailyHistory;\n }\n\n // Get the most recent hourly data point\n const mostRecentHourly = recentHourlyData[recentHourlyData.length - 1];\n const mostRecentIndex = mostRecentHourly.index;\n\n // Calculate the timestamp for the new daily entry.\n // Alpaca's daily history timestamps are at 00:00:00Z for the calendar day\n // following the NY trading date. Derive the trading date in NY time from the\n // most recent intraday timestamp, then set the new daily timestamp to\n // midnight UTC of the next calendar day.\n const mostRecentMs = mostRecentHourly.timestamp * 1000; // hourly timestamps are seconds\n const tradingDateStr = getTradingDate(new Date(mostRecentMs)); // e.g., '2025-09-05' (NY trading date)\n const [yearStr, monthStr, dayStr] = tradingDateStr.split('-');\n const year = Number(yearStr);\n const month = Number(monthStr); // 1-based\n const day = Number(dayStr);\n const newDailyTimestamp = Math.floor(Date.UTC(year, month - 1, day + 1, 0, 0, 0, 0) / 1000);\n\n // Create a new daily history entry with the most recent hourly values\n const updatedDailyHistory: PortfolioHistoryResponse = {\n ...dailyHistory,\n timestamp: [...dailyHistory.timestamp, newDailyTimestamp],\n equity: [...dailyHistory.equity, hourlyHistory.equity[mostRecentIndex]],\n profit_loss: [...dailyHistory.profit_loss, hourlyHistory.profit_loss[mostRecentIndex]],\n profit_loss_pct: [...dailyHistory.profit_loss_pct, hourlyHistory.profit_loss_pct[mostRecentIndex]],\n };\n\n return updatedDailyHistory;\n }\n\n /**\n * Get option contracts based on specified parameters\n * @param params Parameters to filter option contracts\n * @returns Option contracts matching the criteria\n */\n async getOptionContracts(params: GetOptionContractsParams): Promise<OptionContractsResponse> {\n const queryParams = new URLSearchParams();\n\n queryParams.append('underlying_symbols', params.underlying_symbols.join(','));\n\n if (params.expiration_date_gte) queryParams.append('expiration_date_gte', params.expiration_date_gte);\n if (params.expiration_date_lte) queryParams.append('expiration_date_lte', params.expiration_date_lte);\n if (params.strike_price_gte) queryParams.append('strike_price_gte', params.strike_price_gte);\n if (params.strike_price_lte) queryParams.append('strike_price_lte', params.strike_price_lte);\n if (params.type) queryParams.append('type', params.type);\n if (params.status) queryParams.append('status', params.status);\n if (params.limit) queryParams.append('limit', params.limit.toString());\n if (params.page_token) queryParams.append('page_token', params.page_token);\n\n this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {\n symbol: params.underlying_symbols.join(', '),\n });\n\n const response = await this.makeRequest<OptionContractsResponse>(\n `/options/contracts?${queryParams.toString()}`,\n 'GET',\n undefined,\n '',\n {\n action: 'Get option contracts',\n symbol: params.underlying_symbols.join(', '),\n }\n );\n this.log(`Found ${response.option_contracts.length} option contracts`, {\n symbol: params.underlying_symbols.join(', '),\n });\n return response;\n }\n\n /**\n * Get a specific option contract by symbol or ID\n * @param symbolOrId The symbol or ID of the option contract\n * @returns The option contract details\n */\n async getOptionContract(symbolOrId: string): Promise<OptionContract> {\n this.log(`Fetching option contract details for ${symbolOrId}`, {\n symbol: symbolOrId,\n });\n const response = await this.makeRequest<OptionContract>(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {\n action: 'Get option contract details',\n symbol: symbolOrId,\n });\n this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {\n symbol: symbolOrId,\n });\n return response;\n }\n\n /**\n * Create a simple option order (market or limit)\n * @param symbol Option contract symbol\n * @param qty Quantity of contracts (must be a whole number)\n * @param side Buy or sell\n * @param position_intent Position intent (buy_to_open, buy_to_close, sell_to_open, sell_to_close)\n * @param type Order type (market or limit)\n * @param limitPrice Limit price (required for limit orders)\n * @returns The created order\n */\n async createOptionOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n type: 'market' | 'limit',\n limitPrice?: number\n ): Promise<AlpacaOrder> {\n if (!Number.isInteger(qty) || qty <= 0) {\n this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });\n }\n\n if (type === 'limit' && limitPrice === undefined) {\n this.log('Limit price is required for limit orders', { symbol, type: 'error' });\n }\n\n this.log(\n `Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${\n type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''\n }`,\n {\n symbol,\n }\n );\n\n const orderData: CreateOrderParams = {\n symbol,\n qty: qty.toString(),\n side,\n position_intent,\n type,\n time_in_force: 'day',\n order_class: 'simple',\n extended_hours: false,\n };\n\n if (type === 'limit' && limitPrice !== undefined) {\n orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', orderData, '', {\n action: 'Create option order',\n symbol,\n });\n }\n\n /**\n * Create a multi-leg option order\n * @param legs Array of order legs\n * @param qty Quantity of the multi-leg order (must be a whole number)\n * @param type Order type (market or limit)\n * @param limitPrice Limit price (required for limit orders)\n * @returns The created multi-leg order\n */\n async createMultiLegOptionOrder(\n legs: OrderLeg[],\n qty: number,\n type: 'market' | 'limit',\n limitPrice?: number\n ): Promise<AlpacaOrder> {\n const legSymbols = legs.map((leg) => leg.symbol).join(', ');\n\n if (!Number.isInteger(qty) || qty <= 0) {\n this.log('Quantity must be a positive whole number for option orders', {\n symbol: legSymbols,\n type: 'error',\n });\n }\n\n if (type === 'limit' && limitPrice === undefined) {\n this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });\n }\n\n if (legs.length < 2) {\n this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });\n }\n\n this.log(\n `Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${\n type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''\n }`,\n {\n symbol: legSymbols,\n }\n );\n\n const orderData: CreateMultiLegOrderParams = {\n order_class: 'mleg',\n qty: qty.toString(),\n type,\n time_in_force: 'day',\n legs,\n };\n\n if (type === 'limit' && limitPrice !== undefined) {\n orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', orderData, '', {\n action: 'Create multi-leg option order',\n symbol: legSymbols,\n });\n }\n\n /**\n * Exercise an option contract\n * @param symbolOrContractId The symbol or ID of the option contract to exercise\n * @returns Response from the exercise request\n */\n async exerciseOption(symbolOrContractId: string): Promise<null> {\n this.log(`Exercising option contract ${symbolOrContractId}`, {\n symbol: symbolOrContractId,\n });\n return this.makeRequest<null>(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {\n action: 'Exercise option contract',\n symbol: symbolOrContractId,\n });\n }\n\n /**\n * Get option positions\n * @returns Array of option positions\n */\n async getOptionPositions(): Promise<AlpacaPosition[]> {\n this.log('Fetching option positions');\n const positions = await this.getPositions('us_option');\n return positions;\n }\n\n async getOptionsOpenSpreadTrades(): Promise<void> {\n this.log('Fetching option open trades');\n // this function will get all open positions, extract the symbol and see when they were created.\n // figures out when the earliest date was (should be today)\n // then it pulls all orders after the earliest date that were closed and that were of class 'mleg'\n // Each of these contains two orders. they look like this:\n }\n\n /**\n * Get option account activities (exercises, assignments, expirations)\n * @param activityType Type of option activity to filter by\n * @param date Date to filter activities (YYYY-MM-DD format)\n * @returns Array of option account activities\n */\n async getOptionActivities(\n activityType?: 'OPEXC' | 'OPASN' | 'OPEXP',\n date?: string\n ): Promise<OptionAccountActivity[]> {\n const queryParams = new URLSearchParams();\n\n if (activityType) {\n queryParams.append('activity_types', activityType);\n } else {\n queryParams.append('activity_types', 'OPEXC,OPASN,OPEXP');\n }\n\n if (date) {\n queryParams.append('date', date);\n }\n\n this.log(\n `Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`\n );\n\n return this.makeRequest<OptionAccountActivity[]>(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {\n action: 'Get option activities',\n });\n }\n\n /**\n * Create a long call spread (buy lower strike call, sell higher strike call)\n * @param lowerStrikeCallSymbol Symbol of the lower strike call option\n * @param higherStrikeCallSymbol Symbol of the higher strike call option\n * @param qty Quantity of spreads to create (must be a whole number)\n * @param limitPrice Limit price for the spread\n * @returns The created multi-leg order\n */\n async createLongCallSpread(\n lowerStrikeCallSymbol: string,\n higherStrikeCallSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating long call spread: Buy ${lowerStrikeCallSymbol}, Sell ${higherStrikeCallSymbol}, Qty: ${qty}, Price: $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: `${lowerStrikeCallSymbol},${higherStrikeCallSymbol}`,\n }\n );\n\n const legs: OrderLeg[] = [\n {\n symbol: lowerStrikeCallSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n {\n symbol: higherStrikeCallSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Create a long put spread (buy higher strike put, sell lower strike put)\n * @param higherStrikePutSymbol Symbol of the higher strike put option\n * @param lowerStrikePutSymbol Symbol of the lower strike put option\n * @param qty Quantity of spreads to create (must be a whole number)\n * @param limitPrice Limit price for the spread\n * @returns The created multi-leg order\n */\n async createLongPutSpread(\n higherStrikePutSymbol: string,\n lowerStrikePutSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating long put spread: Buy ${higherStrikePutSymbol}, Sell ${lowerStrikePutSymbol}, Qty: ${qty}, Price: $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: `${higherStrikePutSymbol},${lowerStrikePutSymbol}`,\n }\n );\n\n const legs: OrderLeg[] = [\n {\n symbol: higherStrikePutSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n {\n symbol: lowerStrikePutSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Create an iron condor (sell call spread and put spread)\n * @param longPutSymbol Symbol of the lower strike put (long)\n * @param shortPutSymbol Symbol of the higher strike put (short)\n * @param shortCallSymbol Symbol of the lower strike call (short)\n * @param longCallSymbol Symbol of the higher strike call (long)\n * @param qty Quantity of iron condors to create (must be a whole number)\n * @param limitPrice Limit price for the iron condor (credit)\n * @returns The created multi-leg order\n */\n async createIronCondor(\n longPutSymbol: string,\n shortPutSymbol: string,\n shortCallSymbol: string,\n longCallSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(`Creating iron condor with ${qty} contracts at $${limitPrice.toFixed(2)}`, {\n symbol: `${longPutSymbol},${shortPutSymbol},${shortCallSymbol},${longCallSymbol}`,\n });\n\n const legs: OrderLeg[] = [\n {\n symbol: longPutSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n {\n symbol: shortPutSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n {\n symbol: shortCallSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n {\n symbol: longCallSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Create a covered call (sell call option against owned stock)\n * @param stockSymbol Symbol of the underlying stock\n * @param callOptionSymbol Symbol of the call option to sell\n * @param qty Quantity of covered calls to create (must be a whole number)\n * @param limitPrice Limit price for the call option\n * @returns The created order\n */\n async createCoveredCall(\n stockSymbol: string,\n callOptionSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating covered call: Sell ${callOptionSymbol} against ${stockSymbol}, Qty: ${qty}, Price: $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: `${stockSymbol},${callOptionSymbol}`,\n }\n );\n\n // For covered calls, we don't need to include the stock leg if we already own the shares\n // We just create a simple sell order for the call option\n return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);\n }\n\n /**\n * Roll an option position to a new expiration or strike\n * @param currentOptionSymbol Symbol of the current option position\n * @param newOptionSymbol Symbol of the new option to roll to\n * @param qty Quantity of options to roll (must be a whole number)\n * @param currentPositionSide Side of the current position ('buy' or 'sell')\n * @param limitPrice Net limit price for the roll\n * @returns The created multi-leg order\n */\n async rollOptionPosition(\n currentOptionSymbol: string,\n newOptionSymbol: string,\n qty: number,\n currentPositionSide: 'buy' | 'sell',\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(`Rolling ${qty} ${currentOptionSymbol} to ${newOptionSymbol} at net price $${limitPrice.toFixed(2)}`, {\n symbol: `${currentOptionSymbol},${newOptionSymbol}`,\n });\n\n // If current position is long, we need to sell to close and buy to open\n // If current position is short, we need to buy to close and sell to open\n const closePositionSide = currentPositionSide === 'buy' ? 'sell' : 'buy';\n const openPositionSide = currentPositionSide;\n\n const closePositionIntent = closePositionSide === 'buy' ? 'buy_to_close' : 'sell_to_close';\n const openPositionIntent = openPositionSide === 'buy' ? 'buy_to_open' : 'sell_to_open';\n\n const legs: OrderLeg[] = [\n {\n symbol: currentOptionSymbol,\n ratio_qty: '1',\n side: closePositionSide,\n position_intent: closePositionIntent,\n },\n {\n symbol: newOptionSymbol,\n ratio_qty: '1',\n side: openPositionSide,\n position_intent: openPositionIntent,\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Get option chain for a specific underlying symbol and expiration date\n * @param underlyingSymbol The underlying stock symbol\n * @param expirationDate The expiration date (YYYY-MM-DD format)\n * @returns Option contracts for the specified symbol and expiration date\n */\n async getOptionChain(underlyingSymbol: string, expirationDate: string): Promise<OptionContract[]> {\n this.log(`Fetching option chain for ${underlyingSymbol} with expiration date ${expirationDate}`, {\n symbol: underlyingSymbol,\n });\n\n try {\n const params: GetOptionContractsParams = {\n underlying_symbols: [underlyingSymbol],\n expiration_date_gte: expirationDate,\n expiration_date_lte: expirationDate,\n status: 'active',\n limit: 500, // Get a large number to ensure we get all strikes\n };\n\n const response = await this.getOptionContracts(params);\n return response.option_contracts || [];\n } catch (error) {\n if (!(error instanceof AlpacaRequestError)) {\n this.log(\n `Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`,\n {\n type: 'error',\n symbol: underlyingSymbol,\n }\n );\n }\n return [];\n }\n }\n\n /**\n * Get all available expiration dates for a specific underlying symbol\n * @param underlyingSymbol The underlying stock symbol\n * @returns Array of available expiration dates\n */\n async getOptionExpirationDates(underlyingSymbol: string): Promise<string[]> {\n this.log(`Fetching available expiration dates for ${underlyingSymbol}`, {\n symbol: underlyingSymbol,\n });\n\n try {\n const params: GetOptionContractsParams = {\n underlying_symbols: [underlyingSymbol],\n status: 'active',\n limit: 1000, // Get a large number to ensure we get contracts with all expiration dates\n };\n\n const response = await this.getOptionContracts(params);\n\n // Extract unique expiration dates\n const expirationDates = new Set<string>();\n if (response.option_contracts) {\n response.option_contracts.forEach((contract) => {\n expirationDates.add(contract.expiration_date);\n });\n }\n\n // Convert to array and sort\n return Array.from(expirationDates).sort();\n } catch (error) {\n if (!(error instanceof AlpacaRequestError)) {\n this.log(\n `Failed to fetch expiration dates for ${underlyingSymbol}: ${\n error instanceof Error ? error.message : `${error}`\n }`,\n {\n type: 'error',\n symbol: underlyingSymbol,\n }\n );\n }\n return [];\n }\n }\n\n /**\n * Get the current options trading level for the account\n * @returns The options trading level (0-3)\n */\n async getOptionsTradingLevel(): Promise<number> {\n this.log('Fetching options trading level');\n\n const accountDetails = await this.getAccountDetails();\n return accountDetails.options_trading_level || 0;\n }\n\n /**\n * Check if the account has options trading enabled\n * @returns Boolean indicating if options trading is enabled\n */\n async isOptionsEnabled(): Promise<boolean> {\n this.log('Checking if options trading is enabled');\n\n const accountDetails = await this.getAccountDetails();\n\n // Check if options trading level is 2 or higher (Level 2+ allows buying calls/puts)\n // Level 0: Options disabled\n // Level 1: Only covered calls and cash-secured puts\n // Level 2+: Can buy calls and puts (required for executeOptionsOrder)\n const optionsLevel = accountDetails.options_trading_level || 0;\n const isEnabled = optionsLevel >= 2;\n\n this.log(`Options trading level: ${optionsLevel}, enabled: ${isEnabled}`);\n\n return isEnabled;\n }\n\n /**\n * Close all option positions\n * @param cancelOrders Whether to cancel related orders (default: true)\n * @returns Response from the close positions request\n */\n async closeAllOptionPositions(cancelOrders: boolean = true): Promise<void> {\n this.log(`Closing all option positions${cancelOrders ? ' and canceling related orders' : ''}`);\n\n const optionPositions = await this.getOptionPositions();\n\n if (optionPositions.length === 0) {\n this.log('No option positions to close');\n return;\n }\n\n // Create market orders to close each position\n for (const position of optionPositions) {\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n this.log(`Closing ${position.side} position of ${position.qty} contracts for ${position.symbol}`, {\n symbol: position.symbol,\n });\n\n await this.createOptionOrder(position.symbol, parseInt(position.qty), side, positionIntent, 'market');\n }\n\n if (cancelOrders) {\n // Get all open option orders\n const orders = await this.getOrders({ status: 'open' });\n const optionOrders = orders.filter((order) => order.asset_class === 'us_option');\n\n // Cancel each open option order\n for (const order of optionOrders) {\n this.log(`Canceling open order for ${order.symbol}`, {\n symbol: order.symbol,\n });\n await this.makeRequest<null>(`/orders/${order.id}`, 'DELETE', undefined, '', {\n action: `Cancel option order ${order.id}`,\n symbol: order.symbol,\n });\n }\n }\n }\n\n /**\n * Close a specific option position\n * @param symbol The option contract symbol\n * @param qty Optional quantity to close (defaults to entire position)\n * @returns The created order\n */\n async closeOptionPosition(symbol: string, qty?: number): Promise<AlpacaOrder> {\n this.log(`Closing option position for ${symbol}${qty ? ` (${qty} contracts)` : ''}`, {\n symbol,\n });\n\n // Get the position details\n const positions = await this.getOptionPositions();\n const position = positions.find((p) => p.symbol === symbol);\n\n if (!position) {\n throw new Error(`No position found for option contract ${symbol}`);\n }\n\n const quantityToClose = qty || parseInt(position.qty);\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');\n }\n\n /**\n * Create a complete equities trade with optional stop loss and take profit\n * @param params Trade parameters including symbol, qty, side, and optional referencePrice\n * @param options Trade options including order type, extended hours, stop loss, and take profit settings\n * @returns The created order\n */\n async createEquitiesTrade(\n params: {\n symbol: string;\n qty: number;\n side: 'buy' | 'sell';\n referencePrice?: number;\n },\n options?: EquitiesTradeOptions\n ): Promise<AlpacaOrder> {\n const { symbol, qty, side, referencePrice } = params;\n const {\n type = 'market',\n limitPrice,\n extendedHours = false,\n useStopLoss = false,\n stopPrice,\n stopPercent100,\n useTakeProfit = false,\n takeProfitPrice,\n takeProfitPercent100,\n clientOrderId,\n } = options || {};\n\n // Validation: Extended hours + market order is not allowed\n if (extendedHours && type === 'market') {\n this.log('Cannot create market order with extended hours enabled', {\n symbol,\n type: 'error',\n });\n throw new Error('Cannot create market order with extended hours enabled');\n }\n\n // Validation: Limit orders require limit price\n if (type === 'limit' && limitPrice === undefined) {\n this.log('Limit price is required for limit orders', {\n symbol,\n type: 'error',\n });\n throw new Error('Limit price is required for limit orders');\n }\n\n let calculatedStopPrice: number | undefined;\n let calculatedTakeProfitPrice: number | undefined;\n\n // Handle stop loss validation and calculation\n if (useStopLoss) {\n if (stopPrice === undefined && stopPercent100 === undefined) {\n this.log('Either stopPrice or stopPercent100 must be provided when useStopLoss is true', {\n symbol,\n type: 'error',\n });\n throw new Error('Either stopPrice or stopPercent100 must be provided when useStopLoss is true');\n }\n\n if (stopPercent100 !== undefined) {\n if (referencePrice === undefined) {\n this.log('referencePrice is required when using stopPercent100', {\n symbol,\n type: 'error',\n });\n throw new Error('referencePrice is required when using stopPercent100');\n }\n\n // Calculate stop price based on percentage and side\n const stopPercentDecimal = stopPercent100 / 100;\n if (side === 'buy') {\n // For buy orders, stop loss is below the reference price\n calculatedStopPrice = referencePrice * (1 - stopPercentDecimal);\n } else {\n // For sell orders, stop loss is above the reference price\n calculatedStopPrice = referencePrice * (1 + stopPercentDecimal);\n }\n } else {\n calculatedStopPrice = stopPrice;\n }\n }\n\n // Handle take profit validation and calculation\n if (useTakeProfit) {\n if (takeProfitPrice === undefined && takeProfitPercent100 === undefined) {\n this.log('Either takeProfitPrice or takeProfitPercent100 must be provided when useTakeProfit is true', {\n symbol,\n type: 'error',\n });\n throw new Error('Either takeProfitPrice or takeProfitPercent100 must be provided when useTakeProfit is true');\n }\n\n if (takeProfitPercent100 !== undefined) {\n if (referencePrice === undefined) {\n this.log('referencePrice is required when using takeProfitPercent100', {\n symbol,\n type: 'error',\n });\n throw new Error('referencePrice is required when using takeProfitPercent100');\n }\n\n // Calculate take profit price based on percentage and side\n const takeProfitPercentDecimal = takeProfitPercent100 / 100;\n if (side === 'buy') {\n // For buy orders, take profit is above the reference price\n calculatedTakeProfitPrice = referencePrice * (1 + takeProfitPercentDecimal);\n } else {\n // For sell orders, take profit is below the reference price\n calculatedTakeProfitPrice = referencePrice * (1 - takeProfitPercentDecimal);\n }\n } else {\n calculatedTakeProfitPrice = takeProfitPrice;\n }\n }\n\n // Determine order class based on what's enabled\n let orderClass: 'simple' | 'oto' | 'bracket' = 'simple';\n if (useStopLoss && useTakeProfit) {\n orderClass = 'bracket';\n } else if (useStopLoss || useTakeProfit) {\n orderClass = 'oto';\n }\n\n // Build the order request\n const orderData: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n type,\n time_in_force: 'day',\n order_class: orderClass,\n extended_hours: extendedHours,\n position_intent: side === 'buy' ? 'buy_to_open' : 'sell_to_open',\n };\n\n if (clientOrderId) {\n orderData.client_order_id = clientOrderId;\n }\n\n // Add limit price for limit orders\n if (type === 'limit' && limitPrice !== undefined) {\n orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n // Add stop loss if enabled\n if (useStopLoss && calculatedStopPrice !== undefined) {\n orderData.stop_loss = {\n stop_price: this.roundPriceForAlpaca(calculatedStopPrice).toString(),\n };\n }\n\n // Add take profit if enabled\n if (useTakeProfit && calculatedTakeProfitPrice !== undefined) {\n orderData.take_profit = {\n limit_price: this.roundPriceForAlpaca(calculatedTakeProfitPrice).toString(),\n };\n }\n\n const logMessage = `Creating ${orderClass} ${type} ${side} order for ${symbol}: ${qty} shares${\n type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''\n }${useStopLoss ? ` with stop loss at $${calculatedStopPrice?.toFixed(2)}` : ''}${\n useTakeProfit ? ` with take profit at $${calculatedTakeProfitPrice?.toFixed(2)}` : ''\n }${extendedHours ? ' (extended hours)' : ''}`;\n\n this.log(logMessage, {\n symbol,\n });\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', orderData, '', {\n action: 'Create equities trade',\n symbol,\n });\n }\n}\n", "import 'dotenv/config';\nimport { log as baseLog } from './logging';\nimport { LogOptions } from './types/logging-types';\nimport {\n Bar,\n AlpacaQuote,\n TimeFrame,\n AlpacaTrade,\n AlpacaAsset,\n AssetClass,\n GetAssetsParams,\n OptionBar,\n OptionTrade,\n OptionsChainParams,\n OptionsChainResponse,\n LatestOptionsTradesParams,\n LatestOptionsTradesResponse,\n LatestOptionsQuotesParams,\n LatestOptionsQuotesResponse,\n LatestQuotesResponse,\n LatestTradesResponse,\n HistoricalOptionsBarsParams,\n HistoricalOptionsBarsResponse,\n HistoricalOptionsTradesParams,\n HistoricalOptionsTradesResponse,\n OptionsSnapshotsParams,\n OptionsSnapshotsResponse,\n OptionsConditionCodesResponse,\n OptionsExchangeCodesResponse,\n OptionTickType,\n SimpleNews,\n AlpacaNewsArticle,\n DataFeed,\n AlpacaStockStreamMessage,\n AlpacaOptionStreamMessage,\n StockStreamEventName,\n OptionStreamEventName,\n StockStreamEventMap,\n OptionStreamEventMap,\n CryptoTrade,\n CryptoQuote,\n CryptoOrderbook,\n CryptoSnapshot,\n CryptoHistoricalBarsResponse,\n CryptoLatestBarsResponse,\n CryptoHistoricalQuotesResponse,\n CryptoLatestQuotesResponse,\n CryptoHistoricalTradesResponse,\n CryptoLatestTradesResponse,\n CryptoSnapshotsResponse,\n CryptoLatestOrderbooksResponse,\n CryptoHistoricalBarsParams,\n CryptoHistoricalQuotesParams,\n CryptoHistoricalTradesParams,\n} from './types/alpaca-types';\nimport { getLastFullTradingDate } from './market-time';\nimport { EventEmitter } from 'events';\nimport WebSocket from 'ws';\n\nconst DEBUG_LOGGING = process.env['DEBUG'] === 'true' || false;\n\nconst log = (message: string, options: LogOptions = { type: 'info' }) => {\n if (!DEBUG_LOGGING && options.type === 'debug') {\n return;\n }\n baseLog(message, { ...options, source: 'AlpacaMarketDataAPI' });\n};\n\n// Default settings for market data API\nconst DEFAULT_ADJUSTMENT = 'all' as const;\nconst DEFAULT_FEED = 'sip' as DataFeed;\nconst DEFAULT_CURRENCY = 'USD' as const;\n\n/**\n * Parameters for retrieving historical market data bars\n * @see https://data.alpaca.markets/v2/stocks/bars\n */\nexport interface HistoricalBarsParams {\n /** Comma-separated list of stock symbols to query, e.g. 'AAPL,MSFT,TSLA' */\n symbols: string[];\n /**\n * Bar duration/timeframe\n * Format: [1-59]Min/T, [1-23]Hour/H, 1Day/D, 1Week/W, [1,2,3,4,6,12]Month/M\n * Examples: \"1Min\", \"5Min\", \"1Hour\", \"1Day\", \"1Week\", \"1Month\"\n */\n timeframe: TimeFrame;\n /**\n * Start datetime in RFC-3339 format (YYYY-MM-DD)\n * Example: \"2024-02-11T09:00:00Z\"\n */\n start?: string;\n /**\n * End datetime in RFC-3339 format (YYYY-MM-DD)\n * Example: \"2024-02-11T16:00:00Z\"\n */\n end?: string;\n /**\n * Number of bars to return (1-10000)\n * Default: 1000\n */\n limit?: number;\n /** \n\n /** \n * Pagination token for retrieving next page of results\n * Returned in the next_page_token field of the response\n */\n page_token?: string;\n /**\n * Specifies the price adjustments applied to the bars\n * - raw: no adjustments\n * - split: adjust for forward and reverse stock splits\n * - dividend: adjust for cash dividends\n * - spin-off: adjust for spin-offs\n * - all: apply all adjustments (default)\n * Can also be comma-separated combinations, e.g. 'split,spin-off'\n */\n adjustment?: 'raw' | 'split' | 'dividend' | 'spin-off' | 'all' | string;\n /**\n * Sort order of returned bars\n * - asc: Oldest to newest (default)\n * - desc: Newest to oldest\n */\n sort?: 'asc' | 'desc';\n}\n\n/**\n * Response from historical bars endpoint\n * Contains OHLCV (Open, High, Low, Close, Volume) data for requested symbols\n */\nexport interface HistoricalBarsResponse {\n /**\n * Map of symbol to array of bar data\n * Each bar contains OHLCV data for the specified timeframe\n */\n bars: {\n [symbol: string]: Bar[];\n };\n /**\n * Token for retrieving the next page of results\n * null if there are no more results\n */\n next_page_token: string | null;\n /** Currency of the price data in ISO 4217 format */\n currency: string;\n}\n\n/**\n * Response from latest bars endpoint\n * Contains the most recent minute bar for each requested symbol\n */\nexport interface LatestBarsResponse {\n /**\n * Map of symbol to latest bar data\n * Each bar contains OHLCV data for the most recent minute\n */\n bars: {\n [symbol: string]: Bar;\n };\n /** Currency of the price data in ISO 4217 format */\n currency: string;\n}\n\n/**\n * Response from last trade endpoint for a single symbol\n * Contains detailed information about the most recent trade\n */\nexport interface LastTradeResponse {\n /** Status of the request */\n status: string;\n /** The stock symbol that was queried */\n symbol: string;\n /**\n * Details of the last trade\n * @property price - Trade price\n * @property size - Trade size (quantity)\n * @property exchange - Exchange where trade occurred (see Common Exchange Codes in docs)\n * @property cond1-4 - Trade conditions\n * @property timestamp - UNIX epoch timestamp in milliseconds\n */\n last: {\n price: number;\n size: number;\n exchange: number;\n cond1: number;\n cond2: number;\n cond3: number;\n cond4: number;\n timestamp: number;\n };\n}\n\n/**\n * Singleton class for interacting with Alpaca Market Data API\n * Provides methods for fetching historical bars, latest bars, last trades, latest trades, latest quotes, and latest quote for a single symbol\n */\nexport class AlpacaMarketDataAPI extends EventEmitter {\n private static instance: AlpacaMarketDataAPI;\n private headers: Record<string, string>;\n private dataURL: string;\n private apiURL: string;\n private v1beta1url: string;\n private v1beta3url: string;\n private stockStreamUrl: string = 'wss://stream.data.alpaca.markets/v2/sip'; // production values\n private optionStreamUrl: string = 'wss://stream.data.alpaca.markets/v1beta3/options'; // production values\n private stockWs: WebSocket | null = null;\n private optionWs: WebSocket | null = null;\n private stockSubscriptions: Record<string, string[]> = { trades: [], quotes: [], bars: [] };\n private optionSubscriptions: Record<string, string[]> = { trades: [], quotes: [], bars: [] };\n private autoReconnect: boolean = true;\n private stockReconnectAttempts: number = 0;\n private optionReconnectAttempts: number = 0;\n private stockReconnectTimeout: NodeJS.Timeout | null = null;\n private optionReconnectTimeout: NodeJS.Timeout | null = null;\n\n public setMode(mode: 'sandbox' | 'test' | 'production' = 'production'): void {\n if (mode === 'sandbox') {\n // sandbox mode\n this.stockStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v2/sip';\n this.optionStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/options';\n } else if (mode === 'test') {\n // test mode, can only use ticker FAKEPACA\n this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/test';\n this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // there's no test mode for options\n } else {\n // production\n this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip';\n this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options';\n }\n }\n\n public getMode(): 'sandbox' | 'test' | 'production' {\n if (this.stockStreamUrl.includes('sandbox')) {\n return 'sandbox';\n } else if (this.stockStreamUrl.includes('test')) {\n return 'test';\n } else {\n return 'production';\n }\n }\n\n public setAutoReconnect(enabled: boolean): void {\n this.autoReconnect = enabled;\n log(`Auto-reconnect ${enabled ? 'enabled' : 'disabled'}`);\n }\n\n public getAutoReconnect(): boolean {\n return this.autoReconnect;\n }\n\n private constructor() {\n super();\n this.dataURL = 'https://data.alpaca.markets/v2';\n this.apiURL =\n process.env.ALPACA_ACCOUNT_TYPE === 'PAPER'\n ? 'https://paper-api.alpaca.markets/v2'\n : 'https://api.alpaca.markets/v2'; // used by some, e.g. getAssets\n this.v1beta1url = 'https://data.alpaca.markets/v1beta1'; // used for options endpoints\n this.v1beta3url = 'https://data.alpaca.markets/v1beta3'; // used for crypto endpoints\n this.setMode('production'); // sets stockStreamUrl and optionStreamUrl\n this.headers = {\n 'APCA-API-KEY-ID': process.env.ALPACA_API_KEY!,\n 'APCA-API-SECRET-KEY': process.env.ALPACA_SECRET_KEY!,\n 'Content-Type': 'application/json',\n };\n }\n\n public static getInstance(): AlpacaMarketDataAPI {\n if (!AlpacaMarketDataAPI.instance) {\n AlpacaMarketDataAPI.instance = new AlpacaMarketDataAPI();\n }\n return AlpacaMarketDataAPI.instance;\n }\n\n private getReconnectDelay(attempt: number): number {\n // 0: instant (0ms), 1: 5s, 2: 10s, 3: 15s, 4+: 60s\n const delays = [0, 5000, 10000, 15000, 60000];\n return attempt < delays.length ? delays[attempt] : 60000;\n }\n\n private scheduleReconnect(streamType: 'stock' | 'option'): void {\n if (!this.autoReconnect) {\n log(`Auto-reconnect disabled, not reconnecting ${streamType} stream`);\n return;\n }\n\n const attempts = streamType === 'stock' ? this.stockReconnectAttempts : this.optionReconnectAttempts;\n const delay = this.getReconnectDelay(attempts);\n \n log(`Scheduling ${streamType} stream reconnect (attempt ${attempts + 1}) in ${delay}ms`);\n\n const timeout = setTimeout(() => {\n log(`Attempting to reconnect ${streamType} stream (attempt ${attempts + 1})`);\n if (streamType === 'stock') {\n this.stockReconnectAttempts++;\n } else {\n this.optionReconnectAttempts++;\n }\n this.connect(streamType);\n }, delay);\n\n if (streamType === 'stock') {\n this.stockReconnectTimeout = timeout;\n } else {\n this.optionReconnectTimeout = timeout;\n }\n }\n\n // Type-safe event emitter methods\n public on<K extends StockStreamEventName>(event: K, listener: (data: StockStreamEventMap[K]) => void): this;\n public on<K extends OptionStreamEventName>(event: K, listener: (data: OptionStreamEventMap[K]) => void): this;\n public on(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.on(event, listener);\n }\n\n public emit<K extends StockStreamEventName>(event: K, data: StockStreamEventMap[K]): boolean;\n public emit<K extends OptionStreamEventName>(event: K, data: OptionStreamEventMap[K]): boolean;\n public emit(event: string | symbol, ...args: any[]): boolean {\n return super.emit(event, ...args);\n }\n\n private connect(streamType: 'stock' | 'option'): void {\n const url = streamType === 'stock' ? this.stockStreamUrl : this.optionStreamUrl;\n const ws = new WebSocket(url);\n if (streamType === 'stock') {\n this.stockWs = ws;\n } else {\n this.optionWs = ws;\n }\n\n ws.on('open', () => {\n log(`${streamType} stream connected`);\n // Reset reconnect attempts on successful connection\n if (streamType === 'stock') {\n this.stockReconnectAttempts = 0;\n if (this.stockReconnectTimeout) {\n clearTimeout(this.stockReconnectTimeout);\n this.stockReconnectTimeout = null;\n }\n } else {\n this.optionReconnectAttempts = 0;\n if (this.optionReconnectTimeout) {\n clearTimeout(this.optionReconnectTimeout);\n this.optionReconnectTimeout = null;\n }\n }\n const authMessage = {\n action: 'auth',\n key: process.env.ALPACA_API_KEY!,\n secret: process.env.ALPACA_SECRET_KEY!,\n };\n ws.send(JSON.stringify(authMessage));\n });\n\n ws.on('message', (data: WebSocket.Data) => {\n //log(`RAW MESSASGE: ${data.toString()}`);\n const messages = JSON.parse(data.toString());\n for (const message of messages) {\n if (message.T === 'success' && message.msg === 'authenticated') {\n log(`${streamType} stream authenticated`);\n this.sendSubscription(streamType);\n } else if (message.T === 'error') {\n log(`${streamType} stream error: ${message.msg}`, { type: 'error' });\n } else if (message.S) {\n super.emit(`${streamType}-${message.T}`, message);\n super.emit(`${streamType}-data`, message as AlpacaStockStreamMessage | AlpacaOptionStreamMessage);\n }\n }\n });\n\n ws.on('close', (code: number, reason: Buffer) => {\n const reasonStr = reason.toString() || 'No reason provided';\n const codeDesc = this.getCloseCodeDescription(code);\n log(`${streamType} stream disconnected - Code: ${code} (${codeDesc}), Reason: ${reasonStr}`, { type: 'warn' });\n \n if (streamType === 'stock') {\n this.stockWs = null;\n } else {\n this.optionWs = null;\n }\n \n this.scheduleReconnect(streamType);\n });\n\n ws.on('error', (error: Error) => {\n log(`${streamType} stream error: ${error.message}`, { type: 'error' });\n });\n }\n\n private getCloseCodeDescription(code: number): string {\n const codes: Record<number, string> = {\n 1000: 'Normal Closure',\n 1001: 'Going Away',\n 1002: 'Protocol Error',\n 1003: 'Unsupported Data',\n 1005: 'No Status Received',\n 1006: 'Abnormal Closure',\n 1007: 'Invalid Frame Payload Data',\n 1008: 'Policy Violation',\n 1009: 'Message Too Big',\n 1010: 'Mandatory Extension',\n 1011: 'Internal Server Error',\n 1012: 'Service Restart',\n 1013: 'Try Again Later',\n 1014: 'Bad Gateway',\n 1015: 'TLS Handshake',\n };\n return codes[code] || 'Unknown';\n }\n\n private sendSubscription(streamType: 'stock' | 'option'): void {\n const ws = streamType === 'stock' ? this.stockWs : this.optionWs;\n const subscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;\n if (ws && ws.readyState === WebSocket.OPEN) {\n const subMessagePayload: { trades?: string[]; quotes?: string[]; bars?: string[] } = {};\n\n if (subscriptions.trades.length > 0) {\n subMessagePayload.trades = subscriptions.trades;\n }\n if (subscriptions.quotes.length > 0) {\n subMessagePayload.quotes = subscriptions.quotes;\n }\n if (subscriptions.bars.length > 0) {\n subMessagePayload.bars = subscriptions.bars;\n }\n\n if (Object.keys(subMessagePayload).length > 0) {\n const subMessage = {\n action: 'subscribe',\n ...subMessagePayload,\n };\n ws.send(JSON.stringify(subMessage));\n }\n }\n }\n\n public connectStockStream(): void {\n if (!this.stockWs) {\n this.connect('stock');\n }\n }\n\n public connectOptionStream(): void {\n if (!this.optionWs) {\n this.connect('option');\n }\n }\n\n public disconnectStockStream(): void {\n if (this.stockReconnectTimeout) {\n clearTimeout(this.stockReconnectTimeout);\n this.stockReconnectTimeout = null;\n }\n this.stockReconnectAttempts = 0;\n if (this.stockWs) {\n this.stockWs.close();\n }\n }\n\n public disconnectOptionStream(): void {\n if (this.optionReconnectTimeout) {\n clearTimeout(this.optionReconnectTimeout);\n this.optionReconnectTimeout = null;\n }\n this.optionReconnectAttempts = 0;\n if (this.optionWs) {\n this.optionWs.close();\n }\n }\n\n public subscribe(\n streamType: 'stock' | 'option',\n subscriptions: { trades?: string[]; quotes?: string[]; bars?: string[] }\n ): void {\n const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;\n Object.entries(subscriptions).forEach(([key, value]) => {\n if (value) {\n currentSubscriptions[key] = [...new Set([...(currentSubscriptions[key] || []), ...value])];\n }\n });\n\n this.sendSubscription(streamType);\n }\n\n public unsubscribe(\n streamType: 'stock' | 'option',\n subscriptions: { trades?: string[]; quotes?: string[]; bars?: string[] }\n ): void {\n const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;\n Object.entries(subscriptions).forEach(([key, value]) => {\n if (value) {\n currentSubscriptions[key] = (currentSubscriptions[key] || []).filter((s) => !value.includes(s));\n }\n });\n const unsubMessage = {\n action: 'unsubscribe',\n ...subscriptions,\n };\n\n const ws = streamType === 'stock' ? this.stockWs : this.optionWs;\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(unsubMessage));\n }\n }\n\n private async makeRequest(\n endpoint: string,\n method: string = 'GET',\n params?: Record<string, any>,\n baseUrlName: 'data' | 'api' | 'v1beta1' | 'v1beta3' = 'data'\n ): Promise<any> {\n const baseUrl = baseUrlName === 'data' ? this.dataURL : \n baseUrlName === 'api' ? this.apiURL : \n baseUrlName === 'v1beta1' ? this.v1beta1url : this.v1beta3url;\n const url = new URL(`${baseUrl}${endpoint}`);\n\n try {\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n url.searchParams.append(key, value.join(','));\n } else if (value !== undefined) {\n url.searchParams.append(key, value.toString());\n }\n });\n }\n\n const response = await fetch(url.toString(), {\n method,\n headers: this.headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n log(`Market Data API error (${response.status}): ${errorText}`, { type: 'error' });\n throw new Error(`Market Data API error (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n return data;\n } catch (err) {\n const error = err as Error;\n log(`Error in makeRequest: ${error.message}. Endpoint: ${endpoint}. Url: ${url.toString()}`, { type: 'error' });\n if (error instanceof TypeError) {\n log(`Network error details: ${error.stack}`, { type: 'error' });\n }\n throw error;\n }\n }\n\n /**\n * Get historical OHLCV bars for specified symbols, including pre-market and post-market data\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for historical bars request\n * @returns Historical bars data with all pages combined\n */\n async getHistoricalBars(params: HistoricalBarsParams): Promise<HistoricalBarsResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allBars: { [symbol: string]: Bar[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalBarsCount = 0;\n let pageCount = 0;\n let currency = '';\n\n // Initialize bar arrays for each symbol\n symbols.forEach((symbol) => {\n allBars[symbol] = [];\n });\n\n log(\n `Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr }\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n adjustment: params.adjustment ?? DEFAULT_ADJUSTMENT,\n feed: DEFAULT_FEED,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: HistoricalBarsResponse = await this.makeRequest('/stocks/bars', 'GET', requestParams);\n\n if (!response.bars) {\n log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });\n break;\n }\n\n // Track currency from first response\n if (!currency) {\n currency = response.currency;\n }\n\n // Combine bars for each symbol\n let pageBarsCount = 0;\n let earliestTimestamp: Date | null = null;\n let latestTimestamp: Date | null = null;\n\n Object.entries(response.bars).forEach(([symbol, bars]) => {\n if (bars && bars.length > 0) {\n allBars[symbol] = [...allBars[symbol], ...bars];\n pageBarsCount += bars.length;\n\n // Track date range for this page\n bars.forEach((bar) => {\n const barDate = new Date(bar.t);\n if (!earliestTimestamp || barDate < earliestTimestamp) {\n earliestTimestamp = barDate;\n }\n if (!latestTimestamp || barDate > latestTimestamp) {\n latestTimestamp = barDate;\n }\n });\n }\n });\n\n totalBarsCount += pageBarsCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n // Enhanced logging with date range and progress info\n const dateRangeStr =\n earliestTimestamp && latestTimestamp\n ? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(\n latestTimestamp\n ).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`\n : 'unknown range';\n\n log(\n `Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${\n symbols.length\n } symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {symbol: symbolsStr, type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n // Final summary\n const symbolCounts = Object.entries(allBars)\n .map(([symbol, bars]) => `${symbol}: ${bars.length}`)\n .join(', ');\n log(\n `${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length\n } symbols (${symbolCounts})`, { symbol: symbolsStr }\n );\n\n return {\n bars: allBars,\n next_page_token: null, // Always null since we fetch all pages\n currency: currency || DEFAULT_CURRENCY,\n };\n }\n\n /**\n * Get the most recent minute bar for requested symbols\n * @param symbols Array of stock symbols to query\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest bar data for each symbol\n \n */\n async getLatestBars(symbols: string[], currency?: string): Promise<LatestBarsResponse> {\n return this.makeRequest('/stocks/bars/latest', 'GET', {\n symbols,\n feed: DEFAULT_FEED,\n currency: currency || DEFAULT_CURRENCY,\n });\n }\n\n /**\n * Get the last trade for a single symbol\n * @param symbol The stock symbol to query\n * @returns Last trade details including price, size, exchange, and conditions\n */\n async getLastTrade(symbol: string): Promise<LastTradeResponse> {\n return this.makeRequest(`/v1/last/stocks/${symbol}`, 'GET');\n }\n\n /**\n * Get the most recent trades for requested symbols\n * @param symbols Array of stock symbols to query\n * @param feed Optional data source (sip/iex/delayed_sip)\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest trade data for each symbol\n \n */\n async getLatestTrades(symbols: string[], feed?: DataFeed, currency?: string): Promise<LatestTradesResponse> {\n return this.makeRequest('/stocks/trades/latest', 'GET', {\n symbols,\n feed: feed || DEFAULT_FEED,\n currency: currency || DEFAULT_CURRENCY,\n });\n }\n\n /**\n * Get the most recent quotes for requested symbols\n * @param symbols Array of stock symbols to query\n * @param feed Optional data source (sip/iex/delayed_sip)\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest quote data for each symbol\n */\n async getLatestQuotes(symbols: string[], feed?: DataFeed, currency?: string): Promise<LatestQuotesResponse> {\n // Return empty response if symbols array is empty to avoid API error\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getLatestQuotes, returning empty response', { type: 'warn' });\n return {\n quotes: {},\n currency: currency || DEFAULT_CURRENCY,\n };\n }\n\n return this.makeRequest('/stocks/quotes/latest', 'GET', {\n symbols,\n feed: feed || DEFAULT_FEED,\n currency: currency || DEFAULT_CURRENCY,\n });\n }\n\n /**\n * Get the latest quote for a single symbol\n * @param symbol The stock symbol to query\n * @param feed Optional data source (sip/iex/delayed_sip)\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest quote data with symbol and currency information\n */\n async getLatestQuote(\n symbol: string,\n feed?: DataFeed,\n currency?: string\n ): Promise<{ quote: AlpacaQuote; symbol: string; currency: string }> {\n return this.makeRequest(`/stocks/${symbol}/quotes/latest`, 'GET', {\n feed: feed || DEFAULT_FEED,\n currency,\n });\n }\n\n /**\n * Get the previous day's closing price for a symbol\n * @param symbol The stock symbol to query\n * @param referenceDate Optional reference date to get the previous close for\n * @returns Previous day's closing price data\n */\n async getPreviousClose(symbol: string, referenceDate?: Date): Promise<Bar | null> {\n const date = referenceDate || new Date();\n const prevMarketDate = getLastFullTradingDate(date);\n\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '1Day',\n start: prevMarketDate.toISOString(),\n end: prevMarketDate.toISOString(),\n limit: 1,\n });\n\n if (!response.bars[symbol] || response.bars[symbol].length === 0) {\n log(`No previous close data available for ${symbol}`, { type: 'error', symbol });\n return null;\n }\n\n return response.bars[symbol][0];\n }\n\n /**\n * Get hourly price data for a symbol\n * @param symbol The stock symbol to query\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of hourly price bars\n */\n async getHourlyPrices(symbol: string, start: number, end: number): Promise<Bar[]> {\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '1Hour',\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n limit: 96, // Last 96 hours (4 days)\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Get half-hourly price data for a symbol\n * @param symbol The stock symbol to query\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of half-hourly price bars\n */\n async getHalfHourlyPrices(symbol: string, start: number, end: number): Promise<Bar[]> {\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '30Min',\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n limit: 16 * 2 * 4, // last 4 days, 16 hours per day, 2 bars per hour\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Get daily price data for a symbol\n * @param symbol The stock symbol to query\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of daily price bars\n */\n async getDailyPrices(symbol: string, start: number, end: number): Promise<Bar[]> {\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '1Day',\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n limit: 100, // Last 100 days\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Get intraday price data for a symbol\n * @param symbol The stock symbol to query\n * @param minutePeriod Minutes per bar (1, 5, 15, etc.)\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of intraday price bars\n */\n async getIntradayPrices(symbol: string, minutePeriod: number, start: number, end: number): Promise<Bar[]> {\n const timeframe = `${minutePeriod}Min` as TimeFrame;\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe,\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Analyzes an array of price bars and returns a summary string\n * @param bars Array of price bars to analyze\n * @returns A string summarizing the price data\n */\n static analyzeBars(bars: Bar[]): string {\n if (!bars || bars.length === 0) {\n return 'No price data available';\n }\n\n const firstBar = bars[0];\n const lastBar = bars[bars.length - 1];\n const priceChange = lastBar.c - firstBar.o;\n const percentChange = (priceChange / firstBar.o) * 100;\n\n const volumeChange = lastBar.v - firstBar.v;\n const percentVolumeChange = (volumeChange / firstBar.v) * 100;\n\n const high = Math.max(...bars.map((bar) => bar.h));\n const low = Math.min(...bars.map((bar) => bar.l));\n const totalVolume = bars.reduce((sum, bar) => sum + bar.v, 0);\n const avgVolume = totalVolume / bars.length;\n\n return (\n `Price: $${firstBar.o.toFixed(2)} -> $${lastBar.c.toFixed(2)} (${percentChange.toFixed(2)}%), ` +\n `Volume: ${firstBar.v.toLocaleString()} -> ${lastBar.v.toLocaleString()} (${percentVolumeChange.toFixed(2)}%), ` +\n `High: $${high.toFixed(2)}, Low: $${low.toFixed(2)}, ` +\n `Avg Volume: ${avgVolume.toLocaleString()}`\n );\n }\n\n /**\n * Get assets available for trade and data consumption from Alpaca\n * @param params Optional query params\n * - status: 'active' | 'inactive' (default 'active')\n * - asset_class: 'us_equity' | 'us_option' | 'crypto' (default 'us_equity')\n * - shortable: if true (default), filters to assets with shortable=true and easy_to_borrow=true\n * @returns Array of AlpacaAsset objects\n * @see https://docs.alpaca.markets/reference/get-v2-assets-1\n */\n async getAssets(params?: GetAssetsParams): Promise<AlpacaAsset[]> {\n // Endpoint: GET /v2/assets\n const {\n status = 'active',\n asset_class = 'us_equity',\n shortable = true,\n }: { status: 'active' | 'inactive'; asset_class: AssetClass; shortable: boolean } = {\n status: params?.status ?? 'active',\n asset_class: params?.asset_class ?? 'us_equity',\n shortable: params?.shortable ?? true,\n };\n\n const assets: AlpacaAsset[] = await this.makeRequest(\n '/assets',\n 'GET',\n { status, asset_class },\n 'api'\n );\n\n if (!shortable) return assets;\n return assets.filter((a) => a.shortable === true && a.easy_to_borrow === true);\n }\n\n /**\n * Get a single asset by symbol or asset_id\n * @param symbolOrAssetId Symbol or asset_id\n * @returns AlpacaAsset object\n * @see https://docs.alpaca.markets/reference/get-v2-assets-symbol_or_asset_id\n */\n async getAsset(symbolOrAssetId: string): Promise<AlpacaAsset> {\n // Endpoint: GET /v2/assets/{symbol_or_asset_id}\n return this.makeRequest(`/assets/${encodeURIComponent(symbolOrAssetId)}`, 'GET', undefined, 'api');\n }\n\n // ===== OPTIONS MARKET DATA METHODS =====\n\n /**\n * Get options chain for an underlying symbol\n * Provides the latest trade, latest quote, and greeks for each contract symbol of the underlying symbol\n * @param params Options chain request parameters\n * @returns Options chain data with snapshots for each contract\n * @see https://docs.alpaca.markets/reference/optionchain\n */\n async getOptionsChain(params: OptionsChainParams): Promise<OptionsChainResponse> {\n const { underlying_symbol, ...queryParams } = params;\n return this.makeRequest(\n `/options/snapshots/${encodeURIComponent(underlying_symbol)}`,\n 'GET',\n queryParams,\n 'v1beta1'\n );\n }\n\n /**\n * Get the most recent trades for requested option contract symbols\n * @param params Latest options trades request parameters\n * @returns Latest trade data for each option contract symbol\n \n * @see https://docs.alpaca.markets/reference/optionlatesttrades\n */\n async getLatestOptionsTrades(params: LatestOptionsTradesParams): Promise<LatestOptionsTradesResponse> {\n // Remove limit and page_token as they're not supported by this endpoint\n const { limit, page_token, ...requestParams } = params;\n return this.makeRequest('/options/trades/latest', 'GET', requestParams, 'v1beta1');\n }\n\n /**\n * Get the most recent quotes for requested option contract symbols\n * @param params Latest options quotes request parameters\n * @returns Latest quote data for each option contract symbol\n \n * @see https://docs.alpaca.markets/reference/optionlatestquotes\n */\n async getLatestOptionsQuotes(params: LatestOptionsQuotesParams): Promise<LatestOptionsQuotesResponse> {\n // Remove limit and page_token as they're not supported by this endpoint\n const { limit, page_token, ...requestParams } = params;\n return this.makeRequest('/options/quotes/latest', 'GET', requestParams, 'v1beta1');\n }\n\n /**\n * Get historical OHLCV bars for option contract symbols\n * Automatically handles pagination to fetch all available data\n * @param params Historical options bars request parameters\n * @returns Historical bar data for each option contract symbol with all pages combined\n \n * @see https://docs.alpaca.markets/reference/optionbars\n */\n async getHistoricalOptionsBars(params: HistoricalOptionsBarsParams): Promise<HistoricalOptionsBarsResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allBars: { [symbol: string]: OptionBar[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalBarsCount = 0;\n let pageCount = 0;\n\n // Initialize bar arrays for each symbol\n symbols.forEach((symbol) => {\n allBars[symbol] = [];\n });\n\n log(\n `Starting historical options bars fetch for ${symbols.length} symbols (${params.timeframe}, ${\n params.start || 'no start'\n } to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: HistoricalOptionsBarsResponse = await this.makeRequest(\n '/options/bars',\n 'GET',\n requestParams,\n 'v1beta1'\n );\n\n if (!response.bars) {\n log(`No options bars data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine bars for each symbol\n let pageBarsCount = 0;\n let earliestTimestamp: Date | null = null;\n let latestTimestamp: Date | null = null;\n\n Object.entries(response.bars).forEach(([symbol, bars]) => {\n if (bars && bars.length > 0) {\n allBars[symbol] = [...allBars[symbol], ...bars];\n pageBarsCount += bars.length;\n\n // Track date range for this page\n bars.forEach((bar) => {\n const barDate = new Date(bar.t);\n if (!earliestTimestamp || barDate < earliestTimestamp) {\n earliestTimestamp = barDate;\n }\n if (!latestTimestamp || barDate > latestTimestamp) {\n latestTimestamp = barDate;\n }\n });\n }\n });\n\n totalBarsCount += pageBarsCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n // Enhanced logging with date range and progress info\n const dateRangeStr =\n earliestTimestamp && latestTimestamp\n ? `${(earliestTimestamp as Date).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${(\n latestTimestamp as Date\n ).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`\n : 'unknown range';\n\n log(\n `Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} option bars (total: ${totalBarsCount.toLocaleString()}) for ${\n symbols.length\n } symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`,\n {\n type: 'debug',\n }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping options bars pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n // Final summary\n const symbolCounts = Object.entries(allBars)\n .map(([symbol, bars]) => `${symbol}: ${bars.length}`)\n .join(', ');\n log(\n `Options bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages (${symbolCounts})`\n );\n\n return {\n bars: allBars,\n next_page_token: undefined, // Always undefined since we fetch all pages\n };\n }\n\n /**\n * Get historical trades for option contract symbols\n * Automatically handles pagination to fetch all available data\n * @param params Historical options trades request parameters\n * @returns Historical trade data for each option contract symbol with all pages combined\n \n * @see https://docs.alpaca.markets/reference/optiontrades\n */\n async getHistoricalOptionsTrades(params: HistoricalOptionsTradesParams): Promise<HistoricalOptionsTradesResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allTrades: { [symbol: string]: OptionTrade[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalTradesCount = 0;\n let pageCount = 0;\n\n // Initialize trades arrays for each symbol\n symbols.forEach((symbol) => {\n allTrades[symbol] = [];\n });\n\n log(\n `Starting historical options trades fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${\n params.end || 'no end'\n })`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: HistoricalOptionsTradesResponse = await this.makeRequest(\n '/options/trades',\n 'GET',\n requestParams,\n 'v1beta1'\n );\n\n if (!response.trades) {\n log(`No options trades data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine trades for each symbol\n let pageTradesCount = 0;\n let earliestTimestamp: Date | null = null;\n let latestTimestamp: Date | null = null;\n\n Object.entries(response.trades).forEach(([symbol, trades]) => {\n if (trades && trades.length > 0) {\n allTrades[symbol] = [...allTrades[symbol], ...trades];\n pageTradesCount += trades.length;\n\n // Track date range for this page\n trades.forEach((trade) => {\n const tradeDate = new Date(trade.t);\n if (!earliestTimestamp || tradeDate < earliestTimestamp) {\n earliestTimestamp = tradeDate;\n }\n if (!latestTimestamp || tradeDate > latestTimestamp) {\n latestTimestamp = tradeDate;\n }\n });\n }\n });\n\n totalTradesCount += pageTradesCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n // Enhanced logging with date range and progress info\n const dateRangeStr =\n earliestTimestamp && latestTimestamp\n ? `${(earliestTimestamp as Date).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${(\n latestTimestamp as Date\n ).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`\n : 'unknown range';\n\n log(\n `Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} option trades (total: ${totalTradesCount.toLocaleString()}) for ${\n symbols.length\n } symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`,\n {\n type: 'debug',\n }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping options trades pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n // Final summary\n const symbolCounts = Object.entries(allTrades)\n .map(([symbol, trades]) => `${symbol}: ${trades.length}`)\n .join(', ');\n log(\n `Options trades fetch complete: ${totalTradesCount.toLocaleString()} total trades across ${pageCount} pages (${symbolCounts})`\n );\n\n return {\n trades: allTrades,\n next_page_token: undefined, // Always undefined since we fetch all pages\n };\n }\n\n /**\n * Get snapshots for option contract symbols\n * Provides latest trade, latest quote, and greeks for each contract symbol\n * @param params Options snapshots request parameters\n * @returns Snapshot data for each option contract symbol\n \n * @see https://docs.alpaca.markets/reference/optionsnapshots\n */\n async getOptionsSnapshot(params: OptionsSnapshotsParams): Promise<OptionsSnapshotsResponse> {\n // Remove limit and page_token as they may not be supported by this endpoint\n const { limit, page_token, ...requestParams } = params;\n return this.makeRequest('/options/snapshots', 'GET', requestParams, 'v1beta1');\n }\n\n /**\n * Get condition codes for options trades or quotes\n * Returns the mapping between condition codes and their descriptions\n * @param tickType The type of tick data ('trade' or 'quote')\n * @returns Mapping of condition codes to descriptions\n \n * @see https://docs.alpaca.markets/reference/optionmetaconditions\n */\n async getOptionsConditionCodes(tickType: OptionTickType): Promise<OptionsConditionCodesResponse> {\n return this.makeRequest(`/options/meta/conditions/${tickType}`, 'GET', undefined, 'v1beta1');\n }\n\n /**\n * Get exchange codes for options\n * Returns the mapping between option exchange codes and exchange names\n * @returns Mapping of exchange codes to exchange names\n \n * @see https://docs.alpaca.markets/reference/optionmetaexchanges\n */\n async getOptionsExchangeCodes(): Promise<OptionsExchangeCodesResponse> {\n return this.makeRequest('/options/meta/exchanges', 'GET', undefined, 'v1beta1');\n }\n\n /**\n * Analyzes an array of option bars and returns a summary string\n * @param bars Array of option bars to analyze\n * @returns A string summarizing the option price data\n */\n static analyzeOptionBars(bars: OptionBar[]): string {\n if (!bars || bars.length === 0) {\n return 'No option price data available';\n }\n\n const firstBar = bars[0];\n const lastBar = bars[bars.length - 1];\n const priceChange = lastBar.c - firstBar.o;\n const percentChange = (priceChange / firstBar.o) * 100;\n\n const volumeChange = lastBar.v - firstBar.v;\n const percentVolumeChange = firstBar.v > 0 ? (volumeChange / firstBar.v) * 100 : 0;\n\n const high = Math.max(...bars.map((bar) => bar.h));\n const low = Math.min(...bars.map((bar) => bar.l));\n const totalVolume = bars.reduce((sum, bar) => sum + bar.v, 0);\n const avgVolume = totalVolume / bars.length;\n\n return (\n `Option Price: $${firstBar.o.toFixed(2)} -> $${lastBar.c.toFixed(2)} (${percentChange.toFixed(2)}%), ` +\n `Volume: ${firstBar.v.toLocaleString()} -> ${lastBar.v.toLocaleString()} (${percentVolumeChange.toFixed(2)}%), ` +\n `High: $${high.toFixed(2)}, Low: $${low.toFixed(2)}, ` +\n `Avg Volume: ${avgVolume.toLocaleString()}`\n );\n }\n\n /**\n * Formats option greeks for display\n * @param greeks Option greeks object\n * @returns Formatted string with greek values\n */\n static formatOptionGreeks(greeks: any): string {\n if (!greeks) {\n return 'No greeks data available';\n }\n\n const parts: string[] = [];\n if (greeks.delta !== undefined) parts.push(`Delta: ${greeks.delta.toFixed(4)}`);\n if (greeks.gamma !== undefined) parts.push(`Gamma: ${greeks.gamma.toFixed(4)}`);\n if (greeks.theta !== undefined) parts.push(`Theta: ${greeks.theta.toFixed(4)}`);\n if (greeks.vega !== undefined) parts.push(`Vega: ${greeks.vega.toFixed(4)}`);\n if (greeks.rho !== undefined) parts.push(`Rho: ${greeks.rho.toFixed(4)}`);\n\n return parts.length > 0 ? parts.join(', ') : 'No greeks data available';\n }\n\n /**\n * Interprets condition codes using the provided condition codes mapping\n * @param conditionCodes Array of condition codes from trade or quote\n * @param conditionCodesMap Mapping of condition codes to descriptions\n * @returns Formatted string with condition descriptions\n */\n static interpretConditionCodes(conditionCodes: string[], conditionCodesMap: OptionsConditionCodesResponse): string {\n if (!conditionCodes || conditionCodes.length === 0) {\n return 'No conditions';\n }\n\n const descriptions = conditionCodes\n .map((code) => conditionCodesMap[code] || `Unknown (${code})`)\n .filter((desc) => desc !== undefined);\n\n return descriptions.length > 0 ? descriptions.join(', ') : 'No condition descriptions available';\n }\n\n /**\n * Gets the exchange name from exchange code using the provided exchange codes mapping\n * @param exchangeCode Exchange code from trade or quote\n * @param exchangeCodesMap Mapping of exchange codes to names\n * @returns Exchange name or formatted unknown exchange\n */\n static getExchangeName(exchangeCode: string, exchangeCodesMap: OptionsExchangeCodesResponse): string {\n return exchangeCodesMap[exchangeCode] || `Unknown Exchange (${exchangeCode})`;\n }\n\n /**\n * Fetches news articles from Alpaca API for a symbol, paginating through all results.\n * @param symbol The symbol to fetch news for (e.g., 'AAPL')\n * @param params Optional parameters: start, end, limit, sort, include_content\n * @returns Array of SimpleNews articles\n */\n async fetchNews(\n symbol: string,\n params?: {\n start?: Date | string;\n end?: Date | string;\n limit?: number;\n sort?: 'asc' | 'desc';\n include_content?: boolean;\n }\n ): Promise<SimpleNews[]> {\n const defaultParams = {\n start: new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: new Date(),\n limit: 10,\n sort: 'desc' as const,\n include_content: true,\n };\n const mergedParams = { ...defaultParams, ...params };\n let newsArticles: SimpleNews[] = [];\n let pageToken: string | null = null;\n let hasMorePages = true;\n let fetchedCount = 0;\n const maxLimit = mergedParams.limit;\n\n // Utility to clean content\n function cleanContent(content: string | undefined): string | undefined {\n if (!content) return undefined;\n // Remove excessive whitespace, newlines, and trim\n return content.replace(/\\s+/g, ' ').trim();\n }\n\n while (hasMorePages) {\n const queryParams: URLSearchParams = new URLSearchParams({\n ...(mergedParams.start && { start: new Date(mergedParams.start).toISOString() }),\n ...(mergedParams.end && { end: new Date(mergedParams.end).toISOString() }),\n ...(symbol && { symbols: symbol }),\n ...(mergedParams.limit && { limit: Math.min(50, maxLimit - fetchedCount).toString() }),\n ...(mergedParams.sort && { sort: mergedParams.sort }),\n ...(mergedParams.include_content !== undefined\n ? { include_content: mergedParams.include_content.toString() }\n : {}),\n ...(pageToken && { page_token: pageToken }),\n });\n const url: string = `${this.v1beta1url}/news?${queryParams}`;\n log(`Fetching news from: ${url}`, { type: 'debug', symbol });\n const response: Response = await fetch(url, {\n method: 'GET',\n headers: this.headers,\n });\n if (!response.ok) {\n const errorText = await response.text();\n log(`Alpaca news API error (${response.status}): ${errorText}`, { type: 'error', symbol });\n throw new Error(`Alpaca news API error (${response.status}): ${errorText}`);\n }\n const data: { news: AlpacaNewsArticle[]; next_page_token: string | null } = await response.json();\n if (!data.news || !Array.isArray(data.news)) {\n log(`No news data found in Alpaca response for ${symbol}`, { type: 'warn', symbol });\n break;\n }\n const transformedNews: SimpleNews[] = data.news.map((article: AlpacaNewsArticle) => ({\n symbols: article.symbols,\n title: article.headline,\n summary: cleanContent(article.summary) ?? '',\n content: article.content ? cleanContent(article.content) : undefined,\n url: article.url,\n source: article.source,\n author: article.author,\n date: article.updated_at || article.created_at,\n updatedDate: article.updated_at || article.created_at,\n sentiment: 0,\n }));\n newsArticles = newsArticles.concat(transformedNews);\n fetchedCount = newsArticles.length;\n pageToken = data.next_page_token || null;\n hasMorePages = !!pageToken && (!maxLimit || fetchedCount < maxLimit);\n log(\n `Fetched ${transformedNews.length} news articles (total: ${fetchedCount}) for ${symbol}. More pages: ${hasMorePages}`,\n { type: 'debug', symbol }\n );\n if (maxLimit && fetchedCount >= maxLimit) {\n newsArticles = newsArticles.slice(0, maxLimit);\n break;\n }\n }\n return newsArticles;\n }\n\n // ===== CRYPTO MARKET DATA METHODS =====\n\n /**\n * Get historical OHLCV bars for crypto symbols\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for crypto historical bars request\n * @returns Historical bars data with all pages combined\n */\n async getCryptoHistoricalBars(params: CryptoHistoricalBarsParams): Promise<CryptoHistoricalBarsResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allBars: { [symbol: string]: Bar[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalBarsCount = 0;\n let pageCount = 0;\n\n // Initialize bar arrays for each symbol\n symbols.forEach((symbol) => {\n allBars[symbol] = [];\n });\n\n log(\n `Starting crypto historical bars fetch for ${symbols.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n symbols: symbolsStr,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: CryptoHistoricalBarsResponse = await this.makeRequest(\n '/crypto/us/bars',\n 'GET',\n requestParams,\n 'v1beta3'\n );\n\n if (!response.bars) {\n log(`No crypto bars data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine bars for each symbol\n let pageBarsCount = 0;\n Object.entries(response.bars).forEach(([symbol, bars]) => {\n if (bars && bars.length > 0) {\n allBars[symbol] = [...allBars[symbol], ...bars];\n pageBarsCount += bars.length;\n }\n });\n\n totalBarsCount += pageBarsCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n log(\n `Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} crypto bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping crypto bars pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n log(\n `Crypto historical bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages`\n );\n\n return {\n bars: allBars,\n next_page_token: null, // Always null since we fetch all pages\n };\n }\n\n /**\n * Get the most recent minute bar for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest bar data for each symbol\n */\n async getCryptoLatestBars(symbols: string[]): Promise<CryptoLatestBarsResponse> {\n return this.makeRequest('/crypto/us/latest/bars', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get historical quotes for crypto symbols\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for crypto historical quotes request\n * @returns Historical quotes data with all pages combined\n */\n async getCryptoHistoricalQuotes(params: CryptoHistoricalQuotesParams): Promise<CryptoHistoricalQuotesResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allQuotes: { [symbol: string]: CryptoQuote[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalQuotesCount = 0;\n let pageCount = 0;\n\n // Initialize quotes arrays for each symbol\n symbols.forEach((symbol) => {\n allQuotes[symbol] = [];\n });\n\n log(\n `Starting crypto historical quotes fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n symbols: symbolsStr,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: CryptoHistoricalQuotesResponse = await this.makeRequest(\n '/crypto/us/quotes',\n 'GET',\n requestParams,\n 'v1beta3'\n );\n\n if (!response.quotes) {\n log(`No crypto quotes data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine quotes for each symbol\n let pageQuotesCount = 0;\n Object.entries(response.quotes).forEach(([symbol, quotes]) => {\n if (quotes && quotes.length > 0) {\n allQuotes[symbol] = [...allQuotes[symbol], ...quotes];\n pageQuotesCount += quotes.length;\n }\n });\n\n totalQuotesCount += pageQuotesCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n log(\n `Page ${pageCount}: Fetched ${pageQuotesCount.toLocaleString()} crypto quotes (total: ${totalQuotesCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping crypto quotes pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n log(\n `Crypto historical quotes fetch complete: ${totalQuotesCount.toLocaleString()} total quotes across ${pageCount} pages`\n );\n\n return {\n quotes: allQuotes,\n next_page_token: null, // Always null since we fetch all pages\n };\n }\n\n /**\n * Get the most recent quotes for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest quote data for each symbol\n */\n async getCryptoLatestQuotes(symbols: string[]): Promise<CryptoLatestQuotesResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoLatestQuotes, returning empty response', { type: 'warn' });\n return { quotes: {} };\n }\n\n return this.makeRequest('/crypto/us/latest/quotes', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get historical trades for crypto symbols\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for crypto historical trades request\n * @returns Historical trades data with all pages combined\n */\n async getCryptoHistoricalTrades(params: CryptoHistoricalTradesParams): Promise<CryptoHistoricalTradesResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allTrades: { [symbol: string]: CryptoTrade[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalTradesCount = 0;\n let pageCount = 0;\n\n // Initialize trades arrays for each symbol\n symbols.forEach((symbol) => {\n allTrades[symbol] = [];\n });\n\n log(\n `Starting crypto historical trades fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n symbols: symbolsStr,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: CryptoHistoricalTradesResponse = await this.makeRequest(\n '/crypto/us/trades',\n 'GET',\n requestParams,\n 'v1beta3'\n );\n\n if (!response.trades) {\n log(`No crypto trades data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine trades for each symbol\n let pageTradesCount = 0;\n Object.entries(response.trades).forEach(([symbol, trades]) => {\n if (trades && trades.length > 0) {\n allTrades[symbol] = [...allTrades[symbol], ...trades];\n pageTradesCount += trades.length;\n }\n });\n\n totalTradesCount += pageTradesCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n log(\n `Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} crypto trades (total: ${totalTradesCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping crypto trades pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n log(\n `Crypto historical trades fetch complete: ${totalTradesCount.toLocaleString()} total trades across ${pageCount} pages`\n );\n\n return {\n trades: allTrades,\n next_page_token: null, // Always null since we fetch all pages\n };\n }\n\n /**\n * Get the most recent trades for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest trade data for each symbol\n */\n async getCryptoLatestTrades(symbols: string[]): Promise<CryptoLatestTradesResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoLatestTrades, returning empty response', { type: 'warn' });\n return { trades: {} };\n }\n\n return this.makeRequest('/crypto/us/latest/trades', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get snapshots for crypto symbols\n * Returns the latest trade, latest quote, latest minute bar, latest daily bar, and previous daily bar data\n * @param symbols Array of crypto symbols to query\n * @returns Snapshot data for each symbol\n */\n async getCryptoSnapshots(symbols: string[]): Promise<CryptoSnapshotsResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoSnapshots, returning empty response', { type: 'warn' });\n return { snapshots: {} };\n }\n\n return this.makeRequest('/crypto/us/snapshots', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get the latest orderbook for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest orderbook data for each symbol\n */\n async getCryptoLatestOrderbooks(symbols: string[]): Promise<CryptoLatestOrderbooksResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoLatestOrderbooks, returning empty response', { type: 'warn' });\n return { orderbooks: {} };\n }\n\n return this.makeRequest('/crypto/us/latest/orderbooks', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Analyzes an array of crypto bars and returns a summary string\n * @param bars Array of crypto bars to analyze\n * @returns A string summarizing the crypto price data\n */\n static analyzeCryptoBars(bars: Bar[]): string {\n if (!bars || bars.length === 0) {\n return 'No crypto price data available';\n }\n\n const firstBar = bars[0];\n const lastBar = bars[bars.length - 1];\n const priceChange = lastBar.c - firstBar.o;\n const percentChange = (priceChange / firstBar.o) * 100;\n\n const volumeChange = lastBar.v - firstBar.v;\n const percentVolumeChange = firstBar.v > 0 ? (volumeChange / firstBar.v) * 100 : 0;\n\n const high = Math.max(...bars.map((bar) => bar.h));\n const low = Math.min(...bars.map((bar) => bar.l));\n const totalVolume = bars.reduce((sum, bar) => sum + bar.v, 0);\n const avgVolume = totalVolume / bars.length;\n\n return (\n `Crypto Price: $${firstBar.o.toFixed(6)} -> $${lastBar.c.toFixed(6)} (${percentChange.toFixed(2)}%), ` +\n `Volume: ${firstBar.v.toLocaleString()} -> ${lastBar.v.toLocaleString()} (${percentVolumeChange.toFixed(2)}%), ` +\n `High: $${high.toFixed(6)}, Low: $${low.toFixed(6)}, ` +\n `Avg Volume: ${avgVolume.toLocaleString()}`\n );\n }\n}\n\n// Export the singleton instance\nexport const marketDataAPI = AlpacaMarketDataAPI.getInstance();\n"],
|
|
5
|
-
"mappings": "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",
|
|
3
|
+
"sources": ["../src/index.ts", "../src/logging.ts", "../src/market-hours.ts", "../src/market-time.ts", "../src/format-tools.ts", "../src/types/index.ts", "../src/types/llm-types.ts", "../src/misc-utils.ts", "../src/llm-openai.ts", "../src/llm-config.ts", "../src/json-tools.ts", "../src/llm-utils.ts", "../src/llm-images.ts", "../src/llm-deepseek.ts", "../src/llm-openrouter.ts", "../src/performance-timer.ts", "../src/disco-mail.ts", "../src/alpaca-trading-api.ts", "../src/alpaca-market-data-api.ts"],
|
|
4
|
+
"sourcesContent": ["import * as mt from './market-time';\nimport * as ft from './format-tools';\nimport * as Types from './types';\nimport * as misc from './misc-utils';\nimport * as llm from './llm-openai';\nimport * as llmImages from './llm-images';\nimport * as deepseek from './llm-deepseek';\nimport * as openrouter from './llm-openrouter';\nimport { PerformanceTimer } from './performance-timer';\nimport { DiscoMailAPI } from './disco-mail';\n\nimport { AlpacaTradingAPI } from './alpaca-trading-api';\nimport { AlpacaMarketDataAPI } from './alpaca-market-data-api';\nimport { getPackedSettings } from 'http2';\n\n// Re-export all types\nexport * from './types';\n\n// Export key classes directly for easier access\nexport { AlpacaTradingAPI } from './alpaca-trading-api';\nexport { AlpacaMarketDataAPI } from './alpaca-market-data-api';\nexport { DiscoMailAPI, DiscoMailApiError } from './disco-mail';\nexport { supportsTemperature, uploadVisionFile } from './llm-openai';\nexport { OPENAI_IMAGE_MODELS, OPENAI_MODELS, OPENROUTER_MODELS } from './types/llm-types';\n\nexport const disco = {\n types: Types,\n alpaca: {\n TradingAPI: AlpacaTradingAPI,\n MarketDataAPI: AlpacaMarketDataAPI,\n },\n format: {\n capFirstLetter: ft.capFirstLetter,\n currency: ft.formatCurrency,\n number: ft.formatNumber,\n pct: ft.formatPercentage,\n dateTimeForGS: ft.dateTimeForGS,\n },\n llm: {\n call: llm.makeLLMCall,\n uploadVisionFile: llm.uploadVisionFile,\n seek: deepseek.makeDeepseekCall,\n images: llmImages.makeImagesCall,\n open: openrouter.makeOpenRouterCall,\n },\n mail: new DiscoMailAPI(),\n time: {\n convertDateToMarketTimeZone: mt.convertDateToMarketTimeZone,\n getStartAndEndDates: mt.getStartAndEndDates,\n getMarketOpenClose: mt.getMarketOpenClose,\n getOpenCloseForTradingDay: mt.getOpenCloseForTradingDay,\n getLastFullTradingDate: mt.getLastFullTradingDate,\n getNextMarketDay: mt.getNextMarketDay,\n getPreviousMarketDay: mt.getPreviousMarketDay,\n getMarketTimePeriod: mt.getMarketTimePeriod,\n getMarketStatus: mt.getMarketStatus,\n getNYTimeZone: mt.getNYTimeZone,\n getTradingDate: mt.getTradingDate,\n getTradingStartAndEndDates: mt.getTradingStartAndEndDates,\n getTradingDaysBack: mt.getTradingDaysBack,\n isMarketDay: mt.isMarketDay,\n isWithinMarketHours: mt.isWithinMarketHours,\n countTradingDays: mt.countTradingDays,\n MARKET_TIMES: mt.MARKET_TIMES,\n },\n utils: {\n logIfDebug: misc.logIfDebug,\n fetchWithRetry: misc.fetchWithRetry,\n Timer: PerformanceTimer,\n },\n};\n", "import { LogOptions } from './types/logging-types';\n\n/**\n * Logs a message to the console.\n * @param message The message to log.\n * @param options Optional options.\n * @param options.source The source of the message.\n * @param options.type The type of message to log.\n * @param options.symbol The trading symbol associated with this log.\n * @param options.account The account associated with this log.\n */\nexport function log(message: string, options: LogOptions = { source: 'App', type: 'info' }): void {\n // Format the timestamp\n const date = new Date();\n const timestamp = date.toLocaleString('en-US', { timeZone: 'America/New_York' });\n const account = options?.account;\n const symbol = options?.symbol;\n\n // Build the log message\n const logMessage = `[${timestamp}]${options?.source ? ` [${options.source}] ` : ''}${\n account ? ` [${account}] ` : ''\n }${symbol ? ` [${symbol}] ` : ''}${message}`;\n\n // Use appropriate console method based on type\n if (options?.type === 'error') {\n console.error(logMessage);\n } else if (options?.type === 'warn') {\n console.warn(logMessage);\n } else {\n console.log(logMessage);\n }\n}\n", "// market-hours.ts\n\nexport interface HolidayDetails {\n date: string;\n}\n\nexport interface MarketHolidaysForYear {\n [holidayName: string]: HolidayDetails;\n}\n\nexport interface MarketHolidays {\n [year: number]: MarketHolidaysForYear;\n}\n\nexport interface EarlyCloseDetails {\n date: string;\n time: string;\n optionsTime: string;\n notes: string;\n}\n\nexport interface EarlyClosesForYear {\n [date: string]: EarlyCloseDetails;\n}\n\nexport interface MarketEarlyCloses {\n [year: number]: EarlyClosesForYear;\n}\n\nexport const marketHolidays: MarketHolidays = {\n 2024: {\n \"New Year's Day\": { date: '2024-01-01' },\n 'Martin Luther King, Jr. Day': { date: '2024-01-15' },\n \"Washington's Birthday\": { date: '2024-02-19' },\n 'Good Friday': { date: '2024-03-29' },\n 'Memorial Day': { date: '2024-05-27' },\n 'Juneteenth National Independence Day': { date: '2024-06-19' },\n 'Independence Day': { date: '2024-07-04' },\n 'Labor Day': { date: '2024-09-02' },\n 'Thanksgiving Day': { date: '2024-11-28' },\n 'Christmas Day': { date: '2024-12-25' },\n },\n 2025: {\n \"New Year's Day\": { date: '2025-01-01' },\n 'Jimmy Carter Memorial Day': { date: '2025-01-09' },\n 'Martin Luther King, Jr. Day': { date: '2025-01-20' },\n \"Washington's Birthday\": { date: '2025-02-17' },\n 'Good Friday': { date: '2025-04-18' },\n 'Memorial Day': { date: '2025-05-26' },\n 'Juneteenth National Independence Day': { date: '2025-06-19' },\n 'Independence Day': { date: '2025-07-04' },\n 'Labor Day': { date: '2025-09-01' },\n 'Thanksgiving Day': { date: '2025-11-27' },\n 'Christmas Day': { date: '2025-12-25' },\n },\n 2026: {\n \"New Year's Day\": { date: '2026-01-01' },\n 'Martin Luther King, Jr. Day': { date: '2026-01-19' },\n \"Washington's Birthday\": { date: '2026-02-16' },\n 'Good Friday': { date: '2026-04-03' },\n 'Memorial Day': { date: '2026-05-25' },\n 'Juneteenth National Independence Day': { date: '2026-06-19' },\n 'Independence Day': { date: '2026-07-03' },\n 'Labor Day': { date: '2026-09-07' },\n 'Thanksgiving Day': { date: '2026-11-26' },\n 'Christmas Day': { date: '2026-12-25' },\n },\n};\n\nexport const marketEarlyCloses: MarketEarlyCloses = {\n 2024: {\n '2024-07-03': {\n date: '2024-07-03',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Wednesday, July 3, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2024-11-29': {\n date: '2024-11-29',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Friday, November 29, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2024-12-24': {\n date: '2024-12-24',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Tuesday, December 24, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n },\n 2025: {\n '2025-07-03': {\n date: '2025-07-03',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Thursday, July 3, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2025-11-28': {\n date: '2025-11-28',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Friday, November 28, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2025-12-24': {\n date: '2025-12-24',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Wednesday, December 24, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n },\n 2026: {\n '2026-07-02': {\n date: '2026-07-02',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Independence Day observed, market closes early at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2026-11-27': {\n date: '2026-11-27',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Friday, November 27, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n '2026-12-24': {\n date: '2026-12-24',\n time: '13:00',\n optionsTime: '13:15',\n notes:\n 'Market closes early on Thursday, December 24, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.',\n },\n },\n};\n", "import { log as baseLog } from './logging';\nimport { LogOptions } from './types/logging-types';\nimport {\n Period,\n IntradayReporting,\n PeriodDates,\n MarketTimeParams,\n OutputFormat,\n MarketOpenCloseResult,\n MarketStatus,\n MarketTimesConfig,\n TradingDaysBackOptions,\n} from './types/market-time-types';\nimport { marketHolidays, marketEarlyCloses } from './market-hours';\n\n// Constants for NY market times (Eastern Time)\nexport const MARKET_CONFIG = {\n TIMEZONE: 'America/New_York',\n UTC_OFFSET_STANDARD: -5, // EST\n UTC_OFFSET_DST: -4, // EDT\n TIMES: {\n EXTENDED_START: { hour: 4, minute: 0 },\n MARKET_OPEN: { hour: 9, minute: 30 },\n EARLY_MARKET_END: { hour: 10, minute: 0 },\n MARKET_CLOSE: { hour: 16, minute: 0 },\n EARLY_CLOSE: { hour: 13, minute: 0 },\n EXTENDED_END: { hour: 20, minute: 0 },\n EARLY_EXTENDED_END: { hour: 17, minute: 0 },\n },\n} as const;\n\nconst log = (message: string, options: LogOptions = { type: 'info' }) => {\n baseLog(message, { ...options, source: 'MarketTime' });\n};\n\n// Helper: Get NY offset for a given UTC date (DST rules for US)\n/**\n * Returns the NY timezone offset (in hours) for a given UTC date, accounting for US DST rules.\n * @param date - UTC date\n * @returns offset in hours (-5 for EST, -4 for EDT)\n */\nfunction getNYOffset(date: Date): number {\n // US DST starts 2nd Sunday in March, ends 1st Sunday in November\n const year = date.getUTCFullYear();\n const dstStart = getNthWeekdayOfMonth(year, 3, 0, 2); // March, Sunday, 2nd\n const dstEnd = getNthWeekdayOfMonth(year, 11, 0, 1); // November, Sunday, 1st\n const utcTime = date.getTime();\n\n if (utcTime >= dstStart.getTime() && utcTime < dstEnd.getTime()) {\n return MARKET_CONFIG.UTC_OFFSET_DST;\n }\n return MARKET_CONFIG.UTC_OFFSET_STANDARD;\n}\n\n// Helper: Get nth weekday of month in UTC\n/**\n * Returns the nth weekday of a given month in UTC.\n * @param year - Year\n * @param month - 1-based month (e.g. March = 3)\n * @param weekday - 0=Sunday, 1=Monday, ...\n * @param n - nth occurrence\n * @returns Date object for the nth weekday\n */\nfunction getNthWeekdayOfMonth(year: number, month: number, weekday: number, n: number): Date {\n // month: 1-based (March = 3), weekday: 0=Sunday\n const firstDay = new Date(Date.UTC(year, month - 1, 1));\n let count = 0;\n for (let d = 1; d <= 31; d++) {\n const date = new Date(Date.UTC(year, month - 1, d));\n if (date.getUTCMonth() !== month - 1) break;\n if (date.getUTCDay() === weekday) {\n count++;\n if (count === n) return date;\n }\n }\n // fallback: last day of month\n return new Date(Date.UTC(year, month - 1, 28));\n}\n\n// Helper: Convert UTC date to NY time (returns new Date object)\n/**\n * Converts a UTC date to NY time (returns a new Date object).\n * @param date - UTC date\n * @returns Date object in NY time\n */\nfunction toNYTime(date: Date): Date {\n const offset = getNYOffset(date);\n // NY offset in hours\n const utcMillis = date.getTime();\n const nyMillis = utcMillis + offset * 60 * 60 * 1000;\n return new Date(nyMillis);\n}\n\n// Helper: Convert NY time to UTC (returns new Date object)\n/**\n * Converts a NY time date to UTC (returns a new Date object).\n * @param date - NY time date\n * @returns Date object in UTC\n */\nfunction fromNYTime(date: Date): Date {\n const offset = getNYOffset(date);\n const nyMillis = date.getTime();\n const utcMillis = nyMillis - offset * 60 * 60 * 1000;\n return new Date(utcMillis);\n}\n\n// Helper: Format date in ISO, unix, etc.\n/**\n * Formats a date in ISO, unix-seconds, or unix-ms format.\n * @param date - Date object\n * @param outputFormat - Output format ('iso', 'unix-seconds', 'unix-ms')\n * @returns Formatted date string or number\n */\nfunction formatDate(date: Date, outputFormat: OutputFormat = 'iso'): string | number {\n switch (outputFormat) {\n case 'unix-seconds':\n return Math.floor(date.getTime() / 1000);\n case 'unix-ms':\n return date.getTime();\n case 'iso':\n default:\n return date.toISOString();\n }\n}\n\n// Helper: Format date in NY locale string\n/**\n * Formats a date in NY locale string.\n * @param date - Date object\n * @returns NY locale string\n */\nfunction formatNYLocale(date: Date): string {\n return date.toLocaleString('en-US', { timeZone: 'America/New_York' });\n}\n\n// Market calendar logic\n/**\n * Market calendar logic for holidays, weekends, and market days.\n */\nclass MarketCalendar {\n /**\n * Checks if a date is a weekend in NY time.\n * @param date - Date object\n * @returns true if weekend, false otherwise\n */\n isWeekend(date: Date): boolean {\n const day = toNYTime(date).getUTCDay();\n return day === 0 || day === 6;\n }\n\n /**\n * Checks if a date is a market holiday in NY time.\n * @param date - Date object\n * @returns true if holiday, false otherwise\n */\n isHoliday(date: Date): boolean {\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth() + 1;\n const day = nyDate.getUTCDate();\n const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n const yearHolidays = marketHolidays[year];\n if (!yearHolidays) return false;\n return Object.values(yearHolidays).some((holiday) => holiday.date === formattedDate);\n }\n\n /**\n * Checks if a date is an early close day in NY time.\n * @param date - Date object\n * @returns true if early close, false otherwise\n */\n isEarlyCloseDay(date: Date): boolean {\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth() + 1;\n const day = nyDate.getUTCDate();\n const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n const yearEarlyCloses = marketEarlyCloses[year];\n return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;\n }\n\n /**\n * Gets the early close time (in minutes from midnight) for a given date.\n * @param date - Date object\n * @returns minutes from midnight or null\n */\n getEarlyCloseTime(date: Date): number | null {\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth() + 1;\n const day = nyDate.getUTCDate();\n const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n const yearEarlyCloses = marketEarlyCloses[year];\n if (yearEarlyCloses && yearEarlyCloses[formattedDate]) {\n const [hours, minutes] = yearEarlyCloses[formattedDate].time.split(':').map(Number);\n return hours * 60 + minutes;\n }\n return null;\n }\n\n /**\n * Checks if a date is a market day (not weekend or holiday).\n * @param date - Date object\n * @returns true if market day, false otherwise\n */\n isMarketDay(date: Date): boolean {\n return !this.isWeekend(date) && !this.isHoliday(date);\n }\n\n /**\n * Gets the next market day after the given date.\n * @param date - Date object\n * @returns Date object for next market day\n */\n getNextMarketDay(date: Date): Date {\n let nextDay = new Date(date.getTime() + 24 * 60 * 60 * 1000);\n while (!this.isMarketDay(nextDay)) {\n nextDay = new Date(nextDay.getTime() + 24 * 60 * 60 * 1000);\n }\n return nextDay;\n }\n\n /**\n * Gets the previous market day before the given date.\n * @param date - Date object\n * @returns Date object for previous market day\n */\n getPreviousMarketDay(date: Date): Date {\n let prevDay = new Date(date.getTime() - 24 * 60 * 60 * 1000);\n while (!this.isMarketDay(prevDay)) {\n prevDay = new Date(prevDay.getTime() - 24 * 60 * 60 * 1000);\n }\n return prevDay;\n }\n}\n\n// Market open/close times\n/**\n * Returns market open/close times for a given date, including extended and early closes.\n * @param date - Date object\n * @returns MarketOpenCloseResult\n */\nfunction getMarketTimes(date: Date): MarketOpenCloseResult {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(date);\n if (!calendar.isMarketDay(date)) {\n return {\n marketOpen: false,\n open: null,\n close: null,\n openExt: null,\n closeExt: null,\n };\n }\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth();\n const day = nyDate.getUTCDate();\n\n // Helper to build NY time for a given hour/minute\n function buildNYTime(hour: number, minute: number): Date {\n const d = new Date(Date.UTC(year, month, day, hour, minute, 0, 0));\n return fromNYTime(d);\n }\n\n let open = buildNYTime(MARKET_CONFIG.TIMES.MARKET_OPEN.hour, MARKET_CONFIG.TIMES.MARKET_OPEN.minute);\n let close = buildNYTime(MARKET_CONFIG.TIMES.MARKET_CLOSE.hour, MARKET_CONFIG.TIMES.MARKET_CLOSE.minute);\n let openExt = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_START.hour, MARKET_CONFIG.TIMES.EXTENDED_START.minute);\n let closeExt = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_END.hour, MARKET_CONFIG.TIMES.EXTENDED_END.minute);\n\n if (calendar.isEarlyCloseDay(date)) {\n close = buildNYTime(MARKET_CONFIG.TIMES.EARLY_CLOSE.hour, MARKET_CONFIG.TIMES.EARLY_CLOSE.minute);\n closeExt = buildNYTime(MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour, MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute);\n }\n\n return {\n marketOpen: true,\n open,\n close,\n openExt,\n closeExt,\n };\n}\n\n// Is within market hours\n/**\n * Checks if a date/time is within market hours, extended hours, or continuous.\n * @param date - Date object\n * @param intradayReporting - 'market_hours', 'extended_hours', or 'continuous'\n * @returns true if within hours, false otherwise\n */\nexport function isWithinMarketHours(date: Date, intradayReporting: IntradayReporting = 'market_hours'): boolean {\n const calendar = new MarketCalendar();\n if (!calendar.isMarketDay(date)) return false;\n const nyDate = toNYTime(date);\n const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();\n\n switch (intradayReporting) {\n case 'extended_hours': {\n let endMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;\n if (calendar.isEarlyCloseDay(date)) {\n endMinutes = MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;\n }\n const startMinutes = MARKET_CONFIG.TIMES.EXTENDED_START.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_START.minute;\n return minutes >= startMinutes && minutes <= endMinutes;\n }\n case 'continuous':\n return true;\n default: {\n let endMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n if (calendar.isEarlyCloseDay(date)) {\n endMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n }\n const startMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n return minutes >= startMinutes && minutes <= endMinutes;\n }\n }\n}\n\n// Get last full trading date\n/**\n * Returns the last full trading date (market close) for a given date.\n * @param currentDate - Date object (default: now)\n * @returns Date object for last full trading date\n */\nfunction getLastFullTradingDateImpl(currentDate: Date = new Date()): Date {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(currentDate);\n const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();\n const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n let marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n if (calendar.isEarlyCloseDay(currentDate)) {\n marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n }\n\n // If not a market day, or before open, or during market hours, return previous market day's close\n if (\n !calendar.isMarketDay(currentDate) ||\n minutes < marketOpenMinutes ||\n (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)\n ) {\n const prevMarketDay = calendar.getPreviousMarketDay(currentDate);\n let prevCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n if (calendar.isEarlyCloseDay(prevMarketDay)) {\n prevCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n }\n const prevNYDate = toNYTime(prevMarketDay);\n const year = prevNYDate.getUTCFullYear();\n const month = prevNYDate.getUTCMonth();\n const day = prevNYDate.getUTCDate();\n const closeHour = Math.floor(prevCloseMinutes / 60);\n const closeMinute = prevCloseMinutes % 60;\n return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));\n }\n\n // After market close or after extended hours, return today's close\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth();\n const day = nyDate.getUTCDate();\n const closeHour = Math.floor(marketCloseMinutes / 60);\n const closeMinute = marketCloseMinutes % 60;\n return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));\n}\n\n// Get day boundaries\n/**\n * Returns the start and end boundaries for a market day, extended hours, or continuous.\n * @param date - Date object\n * @param intradayReporting - 'market_hours', 'extended_hours', or 'continuous'\n * @returns Object with start and end Date\n */\nfunction getDayBoundaries(\n date: Date,\n intradayReporting: IntradayReporting = 'market_hours'\n): { start: Date; end: Date } {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(date);\n const year = nyDate.getUTCFullYear();\n const month = nyDate.getUTCMonth();\n const day = nyDate.getUTCDate();\n\n function buildNYTime(hour: number, minute: number, sec = 0, ms = 0): Date {\n const d = new Date(Date.UTC(year, month, day, hour, minute, sec, ms));\n return fromNYTime(d);\n }\n\n let start: Date;\n let end: Date;\n\n switch (intradayReporting) {\n case 'extended_hours':\n start = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_START.hour, MARKET_CONFIG.TIMES.EXTENDED_START.minute, 0, 0);\n end = buildNYTime(MARKET_CONFIG.TIMES.EXTENDED_END.hour, MARKET_CONFIG.TIMES.EXTENDED_END.minute, 59, 999);\n if (calendar.isEarlyCloseDay(date)) {\n end = buildNYTime(\n MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour,\n MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute,\n 59,\n 999\n );\n }\n break;\n case 'continuous':\n start = new Date(Date.UTC(year, month, day, 0, 0, 0, 0));\n end = new Date(Date.UTC(year, month, day, 23, 59, 59, 999));\n break;\n default:\n start = buildNYTime(MARKET_CONFIG.TIMES.MARKET_OPEN.hour, MARKET_CONFIG.TIMES.MARKET_OPEN.minute, 0, 0);\n end = buildNYTime(MARKET_CONFIG.TIMES.MARKET_CLOSE.hour, MARKET_CONFIG.TIMES.MARKET_CLOSE.minute, 59, 999);\n if (calendar.isEarlyCloseDay(date)) {\n end = buildNYTime(MARKET_CONFIG.TIMES.EARLY_CLOSE.hour, MARKET_CONFIG.TIMES.EARLY_CLOSE.minute, 59, 999);\n }\n break;\n }\n return { start, end };\n}\n\n// Period calculator\n/**\n * Calculates the start date for a given period ending at endDate.\n * @param endDate - Date object\n * @param period - Period string\n * @returns Date object for period start\n */\nfunction calculatePeriodStartDate(endDate: Date, period: Period): Date {\n const calendar = new MarketCalendar();\n let startDate: Date;\n switch (period) {\n case 'YTD':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), 0, 1));\n break;\n case '1D':\n startDate = calendar.getPreviousMarketDay(endDate);\n break;\n case '3D':\n startDate = new Date(endDate.getTime() - 3 * 24 * 60 * 60 * 1000);\n break;\n case '1W':\n startDate = new Date(endDate.getTime() - 7 * 24 * 60 * 60 * 1000);\n break;\n case '2W':\n startDate = new Date(endDate.getTime() - 14 * 24 * 60 * 60 * 1000);\n break;\n case '1M':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), endDate.getUTCMonth() - 1, endDate.getUTCDate()));\n break;\n case '3M':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), endDate.getUTCMonth() - 3, endDate.getUTCDate()));\n break;\n case '6M':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear(), endDate.getUTCMonth() - 6, endDate.getUTCDate()));\n break;\n case '1Y':\n startDate = new Date(Date.UTC(endDate.getUTCFullYear() - 1, endDate.getUTCMonth(), endDate.getUTCDate()));\n break;\n default:\n throw new Error(`Invalid period: ${period}`);\n }\n // Ensure start date is a market day\n while (!calendar.isMarketDay(startDate)) {\n startDate = calendar.getNextMarketDay(startDate);\n }\n return startDate;\n}\n\n// Get market time period\n/**\n * Returns the start and end dates for a market time period.\n * @param params - MarketTimeParams\n * @returns PeriodDates object\n */\nexport function getMarketTimePeriod(params: MarketTimeParams): PeriodDates {\n const { period, end = new Date(), intraday_reporting = 'market_hours', outputFormat = 'iso' } = params;\n\n if (!period) throw new Error('Period is required');\n const calendar = new MarketCalendar();\n\n const nyEndDate = toNYTime(end);\n let endDate: Date;\n const isCurrentMarketDay = calendar.isMarketDay(end);\n const isWithinHours = isWithinMarketHours(end, intraday_reporting);\n const minutes = nyEndDate.getUTCHours() * 60 + nyEndDate.getUTCMinutes();\n const marketStartMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n\n if (isCurrentMarketDay) {\n if (minutes < marketStartMinutes) {\n // Before market open - use previous day's close\n const lastMarketDay = calendar.getPreviousMarketDay(end);\n const { end: dayEnd } = getDayBoundaries(lastMarketDay, intraday_reporting);\n endDate = dayEnd;\n } else if (isWithinHours) {\n // During market hours - use current time\n endDate = end;\n } else {\n // After market close - use today's close\n const { end: dayEnd } = getDayBoundaries(end, intraday_reporting);\n endDate = dayEnd;\n }\n } else {\n // Not a market day - use previous market day's close\n const lastMarketDay = calendar.getPreviousMarketDay(end);\n const { end: dayEnd } = getDayBoundaries(lastMarketDay, intraday_reporting);\n endDate = dayEnd;\n }\n\n // Calculate start date\n const periodStartDate = calculatePeriodStartDate(endDate, period);\n const { start: dayStart } = getDayBoundaries(periodStartDate, intraday_reporting);\n\n if (endDate.getTime() < dayStart.getTime()) {\n throw new Error('Start date cannot be after end date');\n }\n\n return {\n start: formatDate(dayStart, outputFormat),\n end: formatDate(endDate, outputFormat),\n };\n}\n\n// Market status\n/**\n * Returns the current market status for a given date.\n * @param date - Date object (default: now)\n * @returns MarketStatus object\n */\nfunction getMarketStatusImpl(date: Date = new Date()): MarketStatus {\n const calendar = new MarketCalendar();\n const nyDate = toNYTime(date);\n const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();\n const isMarketDay = calendar.isMarketDay(date);\n const isEarlyCloseDay = calendar.isEarlyCloseDay(date);\n\n const extendedStartMinutes = MARKET_CONFIG.TIMES.EXTENDED_START.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_START.minute;\n const marketStartMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n const earlyMarketEndMinutes =\n MARKET_CONFIG.TIMES.EARLY_MARKET_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_MARKET_END.minute;\n\n let marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n let extendedEndMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;\n if (isEarlyCloseDay) {\n marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;\n extendedEndMinutes =\n MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;\n }\n\n let status: MarketStatus['status'];\n let nextStatus: MarketStatus['nextStatus'];\n let nextStatusTime: Date;\n let marketPeriod: MarketStatus['marketPeriod'];\n\n if (!isMarketDay) {\n status = 'closed';\n nextStatus = 'extended hours';\n marketPeriod = 'closed';\n const nextMarketDay = calendar.getNextMarketDay(date);\n nextStatusTime = getDayBoundaries(nextMarketDay, 'extended_hours').start;\n } else if (minutes < extendedStartMinutes) {\n status = 'closed';\n nextStatus = 'extended hours';\n marketPeriod = 'closed';\n nextStatusTime = getDayBoundaries(date, 'extended_hours').start;\n } else if (minutes < marketStartMinutes) {\n status = 'extended hours';\n nextStatus = 'open';\n marketPeriod = 'preMarket';\n nextStatusTime = getDayBoundaries(date, 'market_hours').start;\n } else if (minutes < marketCloseMinutes) {\n status = 'open';\n nextStatus = 'extended hours';\n marketPeriod = minutes < earlyMarketEndMinutes ? 'earlyMarket' : 'regularMarket';\n nextStatusTime = getDayBoundaries(date, 'market_hours').end;\n } else if (minutes < extendedEndMinutes) {\n status = 'extended hours';\n nextStatus = 'closed';\n marketPeriod = 'afterMarket';\n nextStatusTime = getDayBoundaries(date, 'extended_hours').end;\n } else {\n status = 'closed';\n nextStatus = 'extended hours';\n marketPeriod = 'closed';\n const nextMarketDay = calendar.getNextMarketDay(date);\n nextStatusTime = getDayBoundaries(nextMarketDay, 'extended_hours').start;\n }\n\n // I think using nyDate here may be wrong - should use current time? i.e. date.getTime()\n const nextStatusTimeDifference = nextStatusTime.getTime() - date.getTime();\n\n return {\n time: date,\n timeString: formatNYLocale(nyDate),\n status,\n nextStatus,\n marketPeriod,\n nextStatusTime,\n nextStatusTimeDifference,\n nextStatusTimeString: formatNYLocale(nextStatusTime),\n };\n}\n\n// API exports\n/**\n * Returns market open/close times for a given date.\n * @param options - { date?: Date }\n * @returns MarketOpenCloseResult\n */\nexport function getMarketOpenClose(options: { date?: Date } = {}): MarketOpenCloseResult {\n const { date = new Date() } = options;\n return getMarketTimes(date);\n}\n\n/**\n * Returns the start and end dates for a market time period as Date objects.\n * @param params - MarketTimeParams\n * @returns Object with start and end Date\n */\nexport function getStartAndEndDates(params: MarketTimeParams = {}): { start: Date; end: Date } {\n const { start, end } = getMarketTimePeriod(params);\n return {\n start: typeof start === 'string' || typeof start === 'number' ? new Date(start) : start,\n end: typeof end === 'string' || typeof end === 'number' ? new Date(end) : end,\n };\n}\n\n/**\n * Returns the last full trading date as a Date object.\n */\n/**\n * Returns the last full trading date as a Date object.\n * @param currentDate - Date object (default: now)\n * @returns Date object for last full trading date\n */\nexport function getLastFullTradingDate(currentDate: Date = new Date()): Date {\n return getLastFullTradingDateImpl(currentDate);\n}\n\n/**\n * Returns the last full trading date and formatted YYYYMMDD string.\n */\n/**\n * Returns the last full trading date and formatted YYYY-MM-DD string.\n * @param currentDate - Date object (default: now)\n * @returns Object with date and YYYYMMDD string\n */\nexport function getLastFullTradingDateInfo(currentDate: Date = new Date()): { date: Date; YYYYMMDD: string } {\n const date = getLastFullTradingDateImpl(currentDate);\n return {\n date,\n YYYYMMDD: `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(\n date.getUTCDate()\n ).padStart(2, '0')}`,\n };\n}\n\n/**\n * Returns the next market day after the reference date.\n * @param referenceDate - Date object (default: now)\n * @returns Object with date, yyyymmdd string, and ISO string\n */\nexport function getNextMarketDay({ referenceDate }: { referenceDate?: Date } = {}): {\n date: Date;\n yyyymmdd: string;\n dateISOString: string;\n} {\n const calendar = new MarketCalendar();\n const startDate = referenceDate ?? new Date();\n\n // Find the next trading day (UTC Date object)\n const nextDate = calendar.getNextMarketDay(startDate);\n\n // Convert to NY time before extracting Y-M-D parts\n const nyNext = toNYTime(nextDate);\n const yyyymmdd = `${nyNext.getUTCFullYear()}-${String(nyNext.getUTCMonth() + 1).padStart(2, '0')}-${String(\n nyNext.getUTCDate()\n ).padStart(2, '0')}`;\n\n return {\n date: nextDate, // raw Date, unchanged\n yyyymmdd, // correct trading date string\n dateISOString: nextDate.toISOString(),\n };\n}\n\n/**\n * Returns the previous market day before the reference date.\n * @param referenceDate - Date object (default: now)\n * @returns Object with date, yyyymmdd string, and ISO string\n */\nexport function getPreviousMarketDay({ referenceDate }: { referenceDate?: Date } = {}) {\n const calendar = new MarketCalendar();\n const startDate = referenceDate || new Date();\n const prevDate = calendar.getPreviousMarketDay(startDate);\n\n // convert to NY time first\n const nyPrev = toNYTime(prevDate); // \u2190 already in this file\n const yyyymmdd = `${nyPrev.getUTCFullYear()}-${String(nyPrev.getUTCMonth() + 1).padStart(2, '0')}-${String(\n nyPrev.getUTCDate()\n ).padStart(2, '0')}`;\n\n return {\n date: prevDate,\n yyyymmdd,\n dateISOString: prevDate.toISOString(),\n };\n}\n\n/**\n * Returns the trading date for a given time. Note: Just trims the date string; does not validate if the date is a market day.\n * @param time - a string, number (unix timestamp), or Date object representing the time\n * @returns the trading date as a string in YYYY-MM-DD format\n */\n/**\n * Returns the trading date for a given time in YYYY-MM-DD format (NY time).\n * @param time - string, number, or Date\n * @returns trading date string\n */\nexport function getTradingDate(time: string | number | Date): string {\n const date = typeof time === 'number' ? new Date(time) : typeof time === 'string' ? new Date(time) : time;\n const nyDate = toNYTime(date);\n return `${nyDate.getUTCFullYear()}-${String(nyDate.getUTCMonth() + 1).padStart(2, '0')}-${String(\n nyDate.getUTCDate()\n ).padStart(2, '0')}`;\n}\n\n/**\n * Returns the NY timezone offset string for a given date.\n * @param date - Date object (default: now)\n * @returns '-04:00' for EDT, '-05:00' for EST\n */\nexport function getNYTimeZone(date?: Date): '-04:00' | '-05:00' {\n const offset = getNYOffset(date || new Date());\n return offset === -4 ? '-04:00' : '-05:00';\n}\n\n/**\n * Returns the regular market open and close Date objects for a given trading day string in the\n * America/New_York timezone (NYSE/NASDAQ calendar).\n *\n * This helper is convenient when you have a calendar date like '2025-10-03' and want the precise\n * open and close Date values for that day. It internally:\n * - Determines the NY offset for the day using `getNYTimeZone()`.\n * - Anchors a noon-time Date on that day in NY time to avoid DST edge cases.\n * - Verifies the day is a market day via `isMarketDay()`.\n * - Fetches the open/close times via `getMarketOpenClose()`.\n *\n * Throws if the provided day is not a market day or if open/close times are unavailable.\n *\n * See also:\n * - `getNYTimeZone(date?: Date)`\n * - `isMarketDay(date: Date)`\n * - `getMarketOpenClose(options?: { date?: Date })`\n *\n * @param dateStr - Trading day string in 'YYYY-MM-DD' format (Eastern Time date)\n * @returns An object containing `{ open: Date; close: Date }`\n * @example\n * ```ts\n * const { open, close } = disco.time.getOpenCloseForTradingDay('2025-10-03');\n * ```\n */\nexport function getOpenCloseForTradingDay(dateStr: string): { open: Date; close: Date } {\n // Build a UTC midnight anchor for the date, then derive the NY offset for that day.\n const utcAnchor = new Date(`${dateStr}T00:00:00Z`);\n const nyOffset = getNYTimeZone(utcAnchor); // '-04:00' | '-05:00'\n\n // Create a NY-local noon date to avoid DST midnight transitions.\n const nyNoon = new Date(`${dateStr}T12:00:00${nyOffset}`);\n\n if (!isMarketDay(nyNoon)) {\n throw new Error(`Not a market day in ET: ${dateStr}`);\n }\n\n const { open, close } = getMarketOpenClose({ date: nyNoon });\n if (!open || !close) {\n throw new Error(`No market times available for ${dateStr}`);\n }\n\n return { open, close };\n}\n\n/**\n * Converts any date to the market time zone (America/New_York, Eastern Time).\n * Returns a new Date object representing the same moment in time but adjusted to NY/Eastern timezone.\n * Automatically handles daylight saving time transitions (EST/EDT).\n * \n * @param date - Date object to convert to market time zone\n * @returns Date object in NY/Eastern time zone\n * @example\n * ```typescript\n * const utcDate = new Date('2024-01-15T15:30:00Z'); // 3:30 PM UTC\n * const nyDate = convertDateToMarketTimeZone(utcDate); // 10:30 AM EST (winter) or 11:30 AM EDT (summer)\n * ```\n */\nexport function convertDateToMarketTimeZone(date: Date): Date {\n return toNYTime(date);\n}\n\n/**\n * Returns the current market status for a given date.\n * @param options - { date?: Date }\n * @returns MarketStatus object\n */\nexport function getMarketStatus(options: { date?: Date } = {}): MarketStatus {\n const { date = new Date() } = options;\n return getMarketStatusImpl(date);\n}\n\n/**\n * Checks if a date is a market day.\n * @param date - Date object\n * @returns true if market day, false otherwise\n */\nexport function isMarketDay(date: Date): boolean {\n const calendar = new MarketCalendar();\n return calendar.isMarketDay(date);\n}\n\n/**\n * Returns full trading days from market open to market close.\n * endDate is always the most recent market close (previous day's close if before open, today's close if after open).\n * days: 1 or not specified = that day's open; 2 = previous market day's open, etc.\n */\n/**\n * Returns full trading days from market open to market close.\n * @param options - { endDate?: Date, days?: number }\n * @returns Object with startDate and endDate\n */\nexport function getTradingStartAndEndDates(\n options: {\n endDate?: Date;\n days?: number;\n } = {}\n): { startDate: Date; endDate: Date } {\n const { endDate = new Date(), days = 1 } = options;\n const calendar = new MarketCalendar();\n\n // Find the most recent market close\n let endMarketDay = endDate;\n const nyEnd = toNYTime(endDate);\n const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;\n const marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;\n const minutes = nyEnd.getUTCHours() * 60 + nyEnd.getUTCMinutes();\n\n if (\n !calendar.isMarketDay(endDate) ||\n minutes < marketOpenMinutes ||\n (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)\n ) {\n // Before market open, not a market day, or during market hours: use previous market day\n endMarketDay = calendar.getPreviousMarketDay(endDate);\n } else {\n // After market close: use today\n endMarketDay = endDate;\n }\n\n // Get market close for endMarketDay\n const endClose = getMarketOpenClose({ date: endMarketDay }).close!;\n\n // Find start market day by iterating back over market days\n let startMarketDay = endMarketDay;\n let count = Math.max(1, days);\n for (let i = 1; i < count; i++) {\n startMarketDay = calendar.getPreviousMarketDay(startMarketDay);\n }\n // If days > 1, we need to go back (days-1) market days from endMarketDay\n if (days > 1) {\n startMarketDay = endMarketDay;\n for (let i = 1; i < days; i++) {\n startMarketDay = calendar.getPreviousMarketDay(startMarketDay);\n }\n }\n const startOpen = getMarketOpenClose({ date: startMarketDay }).open!;\n\n return { startDate: startOpen, endDate: endClose };\n}\n\n/**\n * Counts trading time between two dates (passed as standard Date objects), excluding weekends and holidays, and closed market hours, using other functions in this library.\n *\n * This function calculates the actual trading time between two dates by:\n * 1. Iterating through each calendar day between startDate and endDate (inclusive)\n * 2. For each day that is a market day (not weekend/holiday), getting market open/close times\n * 3. Calculating the overlap between the time range and market hours for that day\n * 4. Summing up all the trading minutes across all days\n *\n * The function automatically handles:\n * - Weekends (Saturday/Sunday) - skipped entirely\n * - Market holidays - skipped entirely\n * - Early close days (e.g. day before holidays) - uses early close time\n * - Times outside market hours - only counts time within 9:30am-4pm ET (or early close)\n *\n * Examples:\n * - 12pm to 3:30pm same day = 3.5 hours = 210 minutes = 0.54 days\n * - 9:30am to 4pm same day = 6.5 hours = 390 minutes = 1 day\n * - Friday 2pm to Monday 2pm = 6.5 hours (Friday 2pm-4pm + Monday 9:30am-2pm)\n *\n * @param startDate - Start date/time\n * @param endDate - End date/time (default: now)\n * @returns Object containing:\n * - days: Trading time as fraction of full trading days (6.5 hours = 1 day)\n * - hours: Trading time in hours\n * - minutes: Trading time in minutes\n */\nexport function countTradingDays(\n startDate: Date,\n endDate: Date = new Date()\n): {\n days: number;\n hours: number;\n minutes: number;\n} {\n const calendar = new MarketCalendar();\n\n // Ensure start is before end\n if (startDate.getTime() > endDate.getTime()) {\n throw new Error('Start date must be before end date');\n }\n\n let totalMinutes = 0;\n\n // Get the NY dates for iteration\n const startNY = toNYTime(startDate);\n const endNY = toNYTime(endDate);\n\n // Create date at start of first day (in NY time)\n const currentNY = new Date(\n Date.UTC(startNY.getUTCFullYear(), startNY.getUTCMonth(), startNY.getUTCDate(), 0, 0, 0, 0)\n );\n\n // Iterate through each calendar day\n while (currentNY.getTime() <= endNY.getTime()) {\n const currentUTC = fromNYTime(currentNY);\n\n // Check if this is a market day\n if (calendar.isMarketDay(currentUTC)) {\n // Get market hours for this day\n const marketTimes = getMarketTimes(currentUTC);\n\n if (marketTimes.marketOpen && marketTimes.open && marketTimes.close) {\n // Calculate the overlap between our time range and market hours\n const dayStart = Math.max(startDate.getTime(), marketTimes.open.getTime());\n const dayEnd = Math.min(endDate.getTime(), marketTimes.close.getTime());\n\n // Only count if there's actual overlap\n if (dayStart < dayEnd) {\n totalMinutes += (dayEnd - dayStart) / (1000 * 60);\n }\n }\n }\n\n // Move to next day\n currentNY.setUTCDate(currentNY.getUTCDate() + 1);\n }\n\n // Convert to days, hours, minutes\n const MINUTES_PER_TRADING_DAY = 390; // 6.5 hours\n const days = totalMinutes / MINUTES_PER_TRADING_DAY;\n const hours = totalMinutes / 60;\n const minutes = totalMinutes;\n\n return {\n days: Math.round(days * 1000) / 1000, // Round to 3 decimal places\n hours: Math.round(hours * 100) / 100, // Round to 2 decimal places\n minutes: Math.round(minutes),\n };\n}\n\n/**\n * Returns the trading day N days back from a reference date, along with its market open time.\n * Trading days are counted as full or half trading days (days that end count as 1 full trading day).\n * By default, the most recent completed trading day counts as day 1.\n * Set includeMostRecentFullDay to false to count strictly before that day.\n * \n * @param options - Object with:\n * - referenceDate: Date to count back from (default: now)\n * - days: Number of trading days to go back (must be an integer >= 1)\n * - includeMostRecentFullDay: Whether to include the most recent completed trading day (default: true)\n * @returns Object containing:\n * - date: Trading date in YYYY-MM-DD format\n * - marketOpenISO: Market open time as ISO string (e.g., \"2025-11-15T13:30:00.000Z\")\n * - unixTimestamp: Market open time as Unix timestamp in seconds\n * @example\n * ```typescript\n * // Get the trading day 1 day back (most recent full trading day)\n * const result = getTradingDaysBack({ days: 1 });\n * console.log(result.date); // \"2025-11-01\"\n * console.log(result.marketOpenISO); // \"2025-11-01T13:30:00.000Z\"\n * console.log(result.unixTimestamp); // 1730466600\n * \n * // Get the trading day 5 days back from a specific date\n * const result2 = getTradingDaysBack({ \n * referenceDate: new Date('2025-11-15T12:00:00-05:00'), \n * days: 5 \n * });\n * ```\n */\nexport function getTradingDaysBack(options: TradingDaysBackOptions): {\n date: string;\n marketOpenISO: string;\n unixTimestamp: number;\n} {\n const calendar = new MarketCalendar();\n const { referenceDate, days, includeMostRecentFullDay = true } = options;\n const refDate = referenceDate || new Date();\n const daysBack = days;\n\n if (!Number.isInteger(daysBack) || daysBack < 1) {\n throw new Error('days must be an integer >= 1');\n }\n\n // Start from the last full trading date relative to reference\n let targetDate = getLastFullTradingDateImpl(refDate);\n\n if (!includeMostRecentFullDay) {\n targetDate = calendar.getPreviousMarketDay(targetDate);\n }\n\n // Go back the specified number of days (we're already at day 1, so go back days-1 more)\n for (let i = 1; i < daysBack; i++) {\n targetDate = calendar.getPreviousMarketDay(targetDate);\n }\n\n // Get market open time for this date\n const marketTimes = getMarketTimes(targetDate);\n if (!marketTimes.open) {\n throw new Error(`No market open time for target date`);\n }\n\n // Format the date string (YYYY-MM-DD) in NY time\n const nyDate = toNYTime(marketTimes.open);\n const dateStr = `${nyDate.getUTCFullYear()}-${String(nyDate.getUTCMonth() + 1).padStart(2, '0')}-${String(nyDate.getUTCDate()).padStart(2, '0')}`;\n\n const marketOpenISO = marketTimes.open.toISOString();\n const unixTimestamp = Math.floor(marketTimes.open.getTime() / 1000);\n\n return {\n date: dateStr,\n marketOpenISO,\n unixTimestamp,\n };\n}\n\n// Export MARKET_TIMES for compatibility\nexport const MARKET_TIMES: MarketTimesConfig = {\n TIMEZONE: MARKET_CONFIG.TIMEZONE,\n PRE: {\n START: { HOUR: 4, MINUTE: 0, MINUTES: 240 },\n END: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n },\n EARLY_MORNING: {\n START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n END: { HOUR: 10, MINUTE: 0, MINUTES: 600 },\n },\n EARLY_CLOSE_BEFORE_HOLIDAY: {\n START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n END: { HOUR: 13, MINUTE: 0, MINUTES: 780 },\n },\n EARLY_EXTENDED_BEFORE_HOLIDAY: {\n START: { HOUR: 13, MINUTE: 0, MINUTES: 780 },\n END: { HOUR: 17, MINUTE: 0, MINUTES: 1020 },\n },\n REGULAR: {\n START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },\n END: { HOUR: 16, MINUTE: 0, MINUTES: 960 },\n },\n EXTENDED: {\n START: { HOUR: 4, MINUTE: 0, MINUTES: 240 },\n END: { HOUR: 20, MINUTE: 0, MINUTES: 1200 },\n },\n};\n", "// format-tools.ts\n\n/**\n * Capitalizes the first letter of a string\n * @param {string} str - The string to capitalize\n * @returns {string} The capitalized string, or original value if not a string\n * @example\n * capitalize('hello') // 'Hello'\n * capitalize(123) // 123\n */\nexport function capFirstLetter(str: string): string {\n if (!str || typeof str !== 'string') return str;\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Formats a number as US currency\n * @param {number} value - The number to format\n * @returns {string} The formatted currency string (e.g. '$1,234.56')\n * @example\n * formatCurrency(1234.56) // '$1,234.56'\n * formatCurrency(NaN) // '$0.00'\n */\nexport function formatCurrency(value: number): string {\n if (isNaN(value)) {\n return '$0.00';\n }\n\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n }).format(value);\n}\n\n/**\n * Formats a number with commas\n * @param {number} value - The number to format\n * @returns {string} The formatted number string (e.g. '1,234.56')\n * @example\n * formatNumber(1234.56) // '1,234.56'\n * formatNumber(NaN) // '0'\n */\nexport function formatNumber(value: number): string {\n if (isNaN(value)) {\n return '0';\n }\n\n return new Intl.NumberFormat('en-US').format(value);\n}\n\n/**\n * Formats a number as a percentage\n * @param {number} value - The number to format (e.g. 0.75 for 75%)\n * @param {number} [decimalPlaces=2] - Number of decimal places to show\n * @returns {string} The formatted percentage string (e.g. '75.00%')\n * @example\n * formatPercentage(0.75) // '75.00%'\n * formatPercentage(0.753, 1) // '75.3%'\n */\nexport function formatPercentage(value: number, decimalPlaces: number = 2): string {\n if (isNaN(value)) {\n return '0%';\n }\n return new Intl.NumberFormat('en-US', {\n style: 'percent',\n minimumFractionDigits: decimalPlaces,\n }).format(value);\n}\n\n/**\n * Formats a Date object to Australian datetime format for Google Sheets\n * @param {Date} date - The date to format\n * @returns {string} The formatted datetime string in 'DD/MM/YYYY HH:MM:SS' format\n * @example\n * dateTimeForGS(new Date('2025-01-01T12:34:56')) // '01/01/2025 12:34:56'\n */\nexport function dateTimeForGS(date: Date): string {\n return date\n .toLocaleString('en-AU', {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n })\n .replace(/\\./g, '/');\n}\n", "export * from './alpaca-types';\nexport * from './market-time-types';\nexport * from './ta-types';\nexport * from './llm-types';\nexport * from './logging-types';\nexport * from './disco-mail-types';\n", "// openai-types.ts\nimport type {\n ChatCompletionMessageParam,\n ChatCompletionTool,\n ChatCompletionMessageToolCall,\n} from 'openai/resources/chat/completions';\nimport type { ImageGenerateParams, ImageModel } from 'openai/resources/images';\nimport type { ResponseFormatTextJSONSchemaConfig, ResponseInputImage } from 'openai/resources/responses/responses';\nimport type { ZodType } from 'zod';\n\n/**\n * Represents OpenAI models\n */\nexport const OPENAI_MODELS = [\n 'gpt-5.6',\n 'gpt-5.6-sol',\n 'gpt-5.6-terra',\n 'gpt-5.6-luna',\n 'gpt-5',\n 'gpt-5-mini',\n 'gpt-5.4-mini',\n 'gpt-5.4-nano',\n 'gpt-5-nano',\n 'gpt-5.1',\n 'gpt-5.4',\n 'gpt-5.5',\n 'gpt-5.5-pro',\n 'gpt-5.2',\n 'gpt-5.2-pro',\n 'gpt-5.1-codex',\n 'gpt-5.1-codex-max',\n] as const;\n\nexport type OpenAIModel = (typeof OPENAI_MODELS)[number];\n\n/**\n * Type guard to check if a model is a supported direct OpenAI model.\n */\nexport function isOpenAIModel(model: string): model is OpenAIModel {\n return OPENAI_MODELS.includes(model as OpenAIModel);\n}\n\n/**\n * Represents OpenAI image models.\n */\nexport const OPENAI_IMAGE_MODELS = [\n 'gpt-image-2',\n 'gpt-image-2-2026-04-21',\n 'gpt-image-1.5',\n 'gpt-image-1',\n 'gpt-image-1-mini',\n 'chatgpt-image-latest',\n 'dall-e-2',\n 'dall-e-3',\n] as const satisfies readonly ImageModel[];\n\nexport type OpenAIImageModel = (typeof OPENAI_IMAGE_MODELS)[number];\n\n/**\n * Type guard to check if a model is a supported OpenAI image model.\n */\nexport function isOpenAIImageModel(model: string): model is OpenAIImageModel {\n return OPENAI_IMAGE_MODELS.includes(model as OpenAIImageModel);\n}\n\n/**\n * Represents Deepseek models\n */\nexport type DeepseekModel = 'deepseek-chat' | 'deepseek-reasoner';\n\n/**\n * Represents OpenRouter models\n */\nexport const OPENROUTER_MODELS = [\n 'openai/gpt-5',\n 'openai/gpt-5-mini',\n 'openai/gpt-5.4-mini',\n 'openai/gpt-5.4-nano',\n 'openai/gpt-5-nano',\n 'openai/gpt-5.1',\n 'openai/gpt-5.4',\n 'openai/gpt-5.4-pro',\n 'openai/gpt-5.5',\n 'openai/gpt-5.5-pro',\n 'openai/gpt-5.2',\n 'openai/gpt-5.2-pro',\n 'openai/gpt-5.1-codex',\n 'openai/gpt-5.1-codex-max',\n 'openai/gpt-oss-120b',\n 'z.ai/glm-4.5',\n 'z.ai/glm-4.5-air',\n 'google/gemini-2.5-flash',\n 'google/gemini-2.5-flash-lite',\n 'deepseek/deepseek-r1-0528',\n 'deepseek/deepseek-chat-v3-0324',\n] as const;\n\nexport type OpenRouterModel = (typeof OPENROUTER_MODELS)[number];\n\n/**\n * Represents pricing information for OpenRouter models\n */\nexport interface OpenRouterPricing {\n input: number; // Cost per 1M input tokens\n output: number; // Cost per 1M output tokens\n context?: number; // Max context tokens\n}\n\n/**\n * Represents all supported LLM models\n */\nexport type LLMModel = OpenAIModel | DeepseekModel | OpenRouterModel;\n\n/**\n * Type guard to check if a model is an OpenRouter model\n */\nexport function isOpenRouterModel(model: string): model is OpenRouterModel {\n return OPENROUTER_MODELS.includes(model as OpenRouterModel);\n}\n\n/**\n * Represents the usage of the LLM.\n */\nexport interface LLMUsage {\n prompt_tokens: number;\n completion_tokens: number;\n reasoning_tokens?: number;\n provider: string;\n model: LLMModel;\n cache_hit_tokens?: number;\n cache_write_tokens?: number;\n cost: number;\n}\n\n/**\n * Represents the options for the LLM.\n */\nexport interface LLMOptions {\n model?: LLMModel;\n temperature?: number;\n top_p?: number;\n frequency_penalty?: number;\n presence_penalty?: number;\n max_completion_tokens?: number;\n tools?: ChatCompletionTool[];\n developerPrompt?: string;\n context?: ChatCompletionMessageParam[];\n store?: boolean;\n reasoning_effort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n reasoning_mode?: 'standard' | 'pro';\n reasoning_context?: 'auto' | 'current_turn' | 'all_turns';\n metadata?: Record<string, string>;\n parallel_tool_calls?: boolean;\n service_tier?: 'auto' | 'default' | 'flex' | 'priority';\n apiKey?: string;\n}\n\n/**\n * Represents the response from the LLM.\n */\nexport interface LLMResponse<T> {\n response: T;\n usage: LLMUsage;\n tool_calls?: ChatCompletionMessageToolCall[];\n}\n\n/**\n * Represents the format of the OpenAI response.\n */\nexport type OpenAIResponseFormat = 'text' | 'json' | ResponseFormatTextJSONSchemaConfig;\n\n/**\n * Represents schema input for structured outputs in OpenAI calls.\n * Can be either a JSON Schema object or a Zod schema.\n */\nexport type OpenAISchemaInput = ResponseFormatTextJSONSchemaConfig['schema'] | ZodType;\n\n/**\n * Supported image detail levels for OpenAI Responses vision inputs.\n */\nexport type OpenAIImageDetail = ResponseInputImage['detail'];\n\n/**\n * A remote image URL to analyze.\n */\nexport interface OpenAIImageURLInput {\n url: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * A base64-encoded image to analyze.\n * If `base64` is a raw base64 string, `mimeType` is used to create a data URL.\n */\nexport interface OpenAIImageBase64Input {\n base64: string;\n mimeType?: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * A fully formed data URL to analyze.\n */\nexport interface OpenAIImageDataURLInput {\n dataUrl: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * An already-uploaded OpenAI file ID to analyze.\n */\nexport interface OpenAIImageFileIDInput {\n fileId: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * A local file path to upload for vision analysis in Node.js environments.\n */\nexport interface OpenAIImageFilePathInput {\n filePath: string;\n filename?: string;\n mimeType?: string;\n detail?: OpenAIImageDetail;\n}\n\n/**\n * Vision image input accepted by the OpenAI Responses helper.\n */\nexport type OpenAIImageInput =\n | OpenAIImageURLInput\n | OpenAIImageBase64Input\n | OpenAIImageDataURLInput\n | OpenAIImageFileIDInput\n | OpenAIImageFilePathInput;\n\n/**\n * Represents the options for the OpenAI Images API.\n * Extends the official ImageGenerateParams but with more user-friendly option names.\n */\nexport interface ImageGenerationOptions {\n model?: DiscoImageModel;\n size?: ImageGenerateParams['size'];\n outputFormat?: 'jpeg' | 'png' | 'webp';\n compression?: number;\n quality?: ImageGenerateParams['quality'];\n count?: number | null;\n apiKey?: string;\n background?: ImageGenerateParams['background'];\n moderation?: ImageGenerateParams['moderation'];\n /**\n * Optional multimodal LLM to pair with image outputs (e.g., gpt-5.4).\n */\n visionModel?: LLMModel;\n}\n\nexport type DiscoImageModel = OpenAIImageModel;\n\n/**\n * Context message for conversation history\n */\nexport interface ContextMessage {\n role: 'user' | 'assistant' | 'system' | 'developer';\n content: string;\n}\n\n\n// Re-export OpenAI types for convenience\nexport type { ImageModel, ImageGenerateParams } from 'openai/resources/images';\nexport type { ImagesResponse, Image } from 'openai/resources/images';\nexport type { Tool } from 'openai/resources/responses/responses';\n", "// Utility function for debug logging\n\n// Define the possible log types as a const array for better type inference\nconst LOG_TYPES = ['info', 'warn', 'error', 'debug', 'trace'] as const;\n// Create a union type from the array\ntype LogType = (typeof LOG_TYPES)[number];\n\n/**\n * Debug logging utility that respects environment debug flags.\n * Logs messages to the console based on the specified log level.\n *\n * @param message - The message to log.\n * @param data - Optional data to log alongside the message. This can be any type of data.\n * @param type - Log level. One of: 'info' | 'warn' | 'error' | 'debug' | 'trace'. Defaults to 'info'.\n *\n * @example\n * logIfDebug(\"User login failed\", { userId: 123 }, \"error\");\n * logIfDebug(\"Cache miss\", undefined, \"warn\");\n * logIfDebug(\"Processing request\", { requestId: \"abc\" }, \"debug\");\n */\nexport const logIfDebug = (message: string, data?: unknown, type: LogType = 'info') => {\n const prefix = `[DEBUG][${type.toUpperCase()}]`;\n const formattedData = data !== undefined ? JSON.stringify(data, null, 2) : '';\n\n switch (type) {\n case 'error':\n console.error(prefix, message, formattedData);\n break;\n case 'warn':\n console.warn(prefix, message, formattedData);\n break;\n case 'debug':\n console.debug(prefix, message, formattedData);\n break;\n case 'trace':\n console.trace(prefix, message, formattedData);\n break;\n case 'info':\n default:\n console.info(prefix, message, formattedData);\n }\n};\n\n/**\n * Masks the middle part of an API key, returning only the first 2 and last 2 characters.\n * If the API key is very short (<= 4 characters), it will be returned as is.\n *\n * @param keyValue - The API key to mask.\n * @returns The masked API key.\n *\n * @example\n * maskApiKey(\"12341239856677\"); // Returns \"12****77\"\n */\nfunction maskApiKey(keyValue: string): string {\n if (keyValue.length <= 4) {\n return keyValue;\n }\n const firstTwo = keyValue.slice(0, 2);\n const lastTwo = keyValue.slice(-2);\n return `${firstTwo}****${lastTwo}`;\n}\n\n/**\n * Hides (masks) the value of any query parameter that is \"apiKey\" (case-insensitive),\n * replacing the middle part with **** and keeping only the first 2 and last 2 characters.\n *\n * @param url - The URL containing the query parameters.\n * @returns The URL with the masked API key.\n *\n * @example\n * hideApiKeyFromurl(\"https://xxx.com/s/23/fdsa/?apiKey=12341239856677\");\n * // Returns \"https://xxx.com/s/23/fdsa/?apiKey=12****77\"\n */\nexport function hideApiKeyFromurl(url: string): string {\n try {\n const parsedUrl = new URL(url);\n\n // We iterate over all search params and look for one named 'apikey' (case-insensitive)\n for (const [key, value] of parsedUrl.searchParams.entries()) {\n if (key.toLowerCase() === 'apikey') {\n const masked = maskApiKey(value);\n parsedUrl.searchParams.set(key, masked);\n }\n }\n\n return parsedUrl.toString();\n } catch {\n // If we can't parse it as a valid URL, just return the original string\n return url;\n }\n}\n\ninterface ErrorDetails {\n type: string;\n reason: string;\n status: number | null;\n retryAfter?: number;\n}\n\n/**\n * Extracts meaningful error information from various error types.\n * @param error - The error to analyze.\n * @param response - Optional response object for HTTP errors.\n * @returns Structured error details.\n */\nfunction extractErrorDetails(error: unknown, response?: Response): ErrorDetails {\n const errMsg = error instanceof Error ? error.message : String(error);\n const errName = error instanceof Error ? error.name : 'Error';\n if (errName === 'TypeError' && errMsg.includes('fetch')) {\n return { type: 'NETWORK_ERROR', reason: 'Network connectivity issue', status: null };\n }\n if (errMsg.includes('HTTP error: 429')) {\n const match = errMsg.match(/RATE_LIMIT: 429:(\\d+)/);\n const retryAfter = match ? parseInt(match[1]) : undefined;\n return { type: 'RATE_LIMIT', reason: 'Rate limit exceeded', status: 429, retryAfter };\n }\n if (errMsg.includes('HTTP error: 401') || errMsg.includes('AUTH_ERROR: 401')) {\n return { type: 'AUTH_ERROR', reason: 'Authentication failed - invalid API key', status: 401 };\n }\n if (errMsg.includes('HTTP error: 403') || errMsg.includes('AUTH_ERROR: 403')) {\n return { type: 'AUTH_ERROR', reason: 'Access forbidden - insufficient permissions', status: 403 };\n }\n if (errMsg.includes('SERVER_ERROR:')) {\n const status = parseInt(errMsg.split('SERVER_ERROR: ')[1]) || 500;\n return { type: 'SERVER_ERROR', reason: `Server error (${status})`, status };\n }\n if (errMsg.includes('CLIENT_ERROR:')) {\n const status = parseInt(errMsg.split('CLIENT_ERROR: ')[1]) || 400;\n return { type: 'CLIENT_ERROR', reason: `Client error (${status})`, status };\n }\n return { type: 'UNKNOWN', reason: errMsg || 'Unknown error', status: null };\n}\n\n/**\n * Fetches a resource with intelligent retry logic for handling transient errors.\n * Features enhanced error logging, rate limit detection, and adaptive backoff.\n *\n * @param url - The URL to fetch.\n * @param options - Optional fetch options.\n * @param retries - The number of retry attempts. Defaults to 3.\n * @param initialBackoff - The initial backoff time in milliseconds. Defaults to 1000.\n * @returns A promise that resolves to the response.\n *\n * @throws Will throw an error if the fetch fails after the specified number of retries.\n */\nexport async function fetchWithRetry(\n url: string,\n options: RequestInit = {},\n retries: number = 3,\n initialBackoff: number = 1000,\n): Promise<Response> {\n let backoff = initialBackoff;\n\n for (let attempt = 1; attempt <= retries; attempt++) {\n try {\n const response = await fetch(url, options);\n if (!response.ok) {\n // Enhanced HTTP error handling with specific error types\n if (response.status === 429) {\n // Check for Retry-After header\n const retryAfter = response.headers.get('Retry-After');\n const retryDelay = retryAfter ? parseInt(retryAfter) * 1000 : null;\n\n throw new Error(`RATE_LIMIT: ${response.status}${retryDelay ? `:${retryDelay}` : ''}`);\n }\n if ([500, 502, 503, 504].includes(response.status)) {\n throw new Error(`SERVER_ERROR: ${response.status}`);\n }\n if ([401, 403].includes(response.status)) {\n throw new Error(`AUTH_ERROR: ${response.status}`);\n }\n if (response.status >= 400 && response.status < 500) {\n // Don't retry most 4xx client errors\n throw new Error(`CLIENT_ERROR: ${response.status}`);\n }\n throw new Error(`HTTP_ERROR: ${response.status}`);\n }\n return response;\n } catch (error) {\n if (attempt === retries) {\n throw error;\n }\n\n // Extract meaningful error information\n const errorDetails = extractErrorDetails(error);\n let adaptiveBackoff = backoff;\n\n // Adaptive backoff based on error type\n if (errorDetails.type === 'RATE_LIMIT') {\n // Use Retry-After header if available, otherwise use minimum 5s for rate limits\n if (errorDetails.retryAfter) {\n adaptiveBackoff = errorDetails.retryAfter;\n } else {\n adaptiveBackoff = Math.max(backoff, 5000);\n }\n } else if (errorDetails.type === 'AUTH_ERROR') {\n // Don't retry auth errors - fail fast\n console.error(`Authentication error for ${hideApiKeyFromurl(url)}: ${errorDetails.reason}`, {\n attemptNumber: attempt,\n errorType: errorDetails.type,\n httpStatus: errorDetails.status,\n url: hideApiKeyFromurl(url),\n source: 'fetchWithRetry',\n timestamp: new Date().toISOString(),\n });\n throw error;\n } else if (errorDetails.type === 'CLIENT_ERROR') {\n // Don't retry client errors (except 429 which is handled above)\n console.error(`Client error for ${hideApiKeyFromurl(url)}: ${errorDetails.reason}`, {\n attemptNumber: attempt,\n errorType: errorDetails.type,\n httpStatus: errorDetails.status,\n url: hideApiKeyFromurl(url),\n source: 'fetchWithRetry',\n timestamp: new Date().toISOString(),\n });\n throw error;\n }\n\n // Enhanced error logging with structured data\n console.warn(\n `Fetch attempt ${attempt} of ${retries} for ${hideApiKeyFromurl(url)} failed: ${\n errorDetails.reason\n }. Retrying in ${adaptiveBackoff}ms...`,\n {\n attemptNumber: attempt,\n totalRetries: retries,\n errorType: errorDetails.type,\n httpStatus: errorDetails.status,\n retryDelay: adaptiveBackoff,\n url: hideApiKeyFromurl(url),\n source: 'fetchWithRetry',\n timestamp: new Date().toISOString(),\n },\n );\n\n await new Promise((resolve) => setTimeout(resolve, adaptiveBackoff));\n backoff = Math.min(backoff * 2, 30000); // Cap at 30 seconds\n }\n }\n throw new Error('Failed to fetch after multiple attempts');\n}\n", "// llm-openai.ts\n\nimport OpenAI from 'openai';\nimport { zodTextFormat } from 'openai/helpers/zod';\nimport type { ZodType } from 'zod';\n\nimport type {\n Tool,\n ResponseInput,\n EasyInputMessage,\n ResponseInputImage,\n ResponseInputText,\n} from 'openai/resources/responses/responses';\n\nimport { calculateCost, DEFAULT_MODEL } from './llm-config';\nimport { parseResponse, normalizeModelName } from './llm-utils';\nimport { isOpenAIModel } from './types';\nimport type {\n LLMResponse,\n LLMOptions,\n LLMModel,\n OpenAIResponseFormat,\n ContextMessage,\n OpenAISchemaInput,\n OpenAIImageInput,\n OpenAIImageDetail,\n} from './types';\nimport type {\n ResponseCreateParamsNonStreaming,\n ResponseOutputItem,\n ResponseFunctionToolCall,\n ResponseCodeInterpreterToolCall,\n ResponseOutputMessage,\n ResponseOutputText,\n ResponseFormatTextJSONSchemaConfig,\n} from 'openai/resources/responses/responses';\n\nexport const DEFAULT_OPTIONS: LLMOptions = {\n model: DEFAULT_MODEL,\n parallel_tool_calls: false,\n};\n\nconst DEFAULT_IMAGE_MIME_TYPE = 'image/webp';\n\n/**\n * Checks if the given direct OpenAI model supports the temperature parameter.\n * @param model The model to check.\n * @returns True if the model supports the temperature parameter, false otherwise.\n */\nexport function supportsTemperature(_model: string): boolean {\n return false;\n}\n\nfunction isZodSchema(schema: OpenAISchemaInput): schema is ZodType {\n return typeof schema === 'object' && schema !== null && 'safeParse' in schema;\n}\n\nfunction buildJsonSchemaFormat(\n schema: OpenAISchemaInput,\n schemaName: string,\n schemaDescription?: string,\n schemaStrict?: boolean\n): ResponseFormatTextJSONSchemaConfig {\n if (isZodSchema(schema)) {\n const zodFormat = zodTextFormat(\n schema,\n schemaName,\n schemaDescription\n ? {\n description: schemaDescription,\n }\n : undefined\n );\n\n return {\n type: 'json_schema',\n name: zodFormat.name,\n schema: zodFormat.schema,\n ...(zodFormat.description ? { description: zodFormat.description } : {}),\n ...(schemaStrict !== undefined ? { strict: schemaStrict } : { strict: zodFormat.strict }),\n };\n }\n\n return {\n type: 'json_schema',\n name: schemaName,\n schema,\n ...(schemaDescription ? { description: schemaDescription } : {}),\n ...(schemaStrict !== undefined ? { strict: schemaStrict } : {}),\n };\n}\n\nfunction resolveOpenAIApiKey(apiKey?: string): string {\n const resolvedApiKey = apiKey || process.env.OPENAI_API_KEY;\n\n if (!resolvedApiKey) {\n throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');\n }\n\n return resolvedApiKey;\n}\n\nfunction createOpenAIClient(apiKey: string): OpenAI {\n return new OpenAI({\n apiKey,\n });\n}\n\nfunction normalizeImageDataUrl(imageData: string, mimeType = DEFAULT_IMAGE_MIME_TYPE): string {\n return imageData.startsWith('data:') ? imageData : `data:${mimeType};base64,${imageData}`;\n}\n\nfunction getFilenameFromPath(filePath: string): string {\n const normalizedPath = filePath.replace(/\\\\/g, '/');\n const pathSegments = normalizedPath.split('/');\n const filename = pathSegments[pathSegments.length - 1];\n\n if (!filename) {\n throw new Error(`Could not determine a filename from file path: ${filePath}`);\n }\n\n return filename;\n}\n\nfunction inferImageMimeType(filePath: string): string | undefined {\n const normalizedPath = filePath.toLowerCase();\n\n if (normalizedPath.endsWith('.png')) {\n return 'image/png';\n }\n\n if (normalizedPath.endsWith('.jpg') || normalizedPath.endsWith('.jpeg')) {\n return 'image/jpeg';\n }\n\n if (normalizedPath.endsWith('.webp')) {\n return 'image/webp';\n }\n\n if (normalizedPath.endsWith('.gif')) {\n return 'image/gif';\n }\n\n return undefined;\n}\n\nasync function readLocalFileBytes(filePath: string): Promise<Uint8Array> {\n try {\n const dynamicImport = new Function('specifier', 'return import(specifier);') as (\n specifier: string\n ) => Promise<{ readFile: (path: string) => Promise<Uint8Array> }>;\n const { readFile } = await dynamicImport('node:fs/promises');\n\n return await readFile(filePath);\n } catch {\n throw new Error('Local image file uploads require a Node.js runtime with access to node:fs/promises');\n }\n}\n\nasync function uploadVisionFileFromPath(\n openai: OpenAI,\n filePath: string,\n filename?: string,\n mimeType?: string\n): Promise<string> {\n const fileBytes = await readLocalFileBytes(filePath);\n const resolvedFilename = filename || getFilenameFromPath(filePath);\n const resolvedMimeType = mimeType || inferImageMimeType(filePath);\n const uploadableFile = await OpenAI.toFile(\n fileBytes,\n resolvedFilename,\n resolvedMimeType ? { type: resolvedMimeType } : undefined\n );\n\n const uploadedFile = await openai.files.create({\n file: uploadableFile,\n purpose: 'vision',\n });\n\n return uploadedFile.id;\n}\n\nfunction collectImageInputs(\n image: OpenAIImageInput | undefined,\n images: OpenAIImageInput[] | undefined,\n imageBase64: string | undefined\n): OpenAIImageInput[] {\n const collectedImages: OpenAIImageInput[] = [];\n\n if (image) {\n collectedImages.push(image);\n }\n\n if (images && images.length > 0) {\n collectedImages.push(...images);\n }\n\n if (imageBase64) {\n collectedImages.push({ base64: imageBase64 });\n }\n\n return collectedImages;\n}\n\nfunction hasLocalFileImage(images: OpenAIImageInput[]): boolean {\n return images.some((image) => 'filePath' in image);\n}\n\nasync function buildImageContentPart(\n image: OpenAIImageInput,\n defaultDetail: OpenAIImageDetail,\n openai?: OpenAI\n): Promise<ResponseInputImage> {\n const detail = image.detail ?? defaultDetail;\n\n if ('url' in image) {\n return {\n type: 'input_image',\n detail,\n image_url: image.url,\n };\n }\n\n if ('dataUrl' in image) {\n return {\n type: 'input_image',\n detail,\n image_url: image.dataUrl,\n };\n }\n\n if ('base64' in image) {\n return {\n type: 'input_image',\n detail,\n image_url: normalizeImageDataUrl(image.base64, image.mimeType),\n };\n }\n\n if ('fileId' in image) {\n return {\n type: 'input_image',\n detail,\n file_id: image.fileId,\n };\n }\n\n if (!openai) {\n throw new Error('A local image file path was provided, but no OpenAI client is available to upload it');\n }\n\n const fileId = await uploadVisionFileFromPath(openai, image.filePath, image.filename, image.mimeType);\n return {\n type: 'input_image',\n detail,\n file_id: fileId,\n };\n}\n\nasync function buildPromptContent(\n input: string,\n imageInputs: OpenAIImageInput[],\n imageDetail: OpenAIImageDetail,\n openai?: OpenAI\n): Promise<string | Array<ResponseInputText | ResponseInputImage>> {\n if (imageInputs.length === 0) {\n return input;\n }\n\n const imageContent = await Promise.all(imageInputs.map((image) => buildImageContentPart(image, imageDetail, openai)));\n\n return [{ type: 'input_text', text: input }, ...imageContent];\n}\n\nexport async function uploadVisionFile(\n filePath: string,\n options: {\n apiKey?: string;\n filename?: string;\n mimeType?: string;\n } = {}\n): Promise<string> {\n const resolvedApiKey = resolveOpenAIApiKey(options.apiKey);\n const openai = createOpenAIClient(resolvedApiKey);\n\n return await uploadVisionFileFromPath(openai, filePath, options.filename, options.mimeType);\n}\n\n/**\n * Makes a call to OpenAI's Responses API for more advanced use cases with built-in tools.\n *\n * This function provides access to the Responses API which supports:\n * - Built-in tools (web search, file search, computer use, code interpreter, image generation)\n * - Background processing\n * - Conversation state management\n * - GPT-5 reasoning controls\n *\n * @example\n * // Basic text response\n * const response = await makeResponsesAPICall('What is the weather like?');\n *\n * @example\n * // With web search tool\n * const response = await makeResponsesAPICall('Latest news about AI', {\n * tools: [{ type: 'web_search_preview' }]\n * });\n *\n * @param input - The input content. Can be:\n * - A string for simple text prompts\n * - An array of input items for complex/multi-modal content\n * @param options - Configuration options for the Responses API\n * @returns Promise<LLMResponse<T>> - The response in the same format as makeLLMCall\n * @throws Error if the API call fails\n */\nexport const makeResponsesAPICall = async <T = string>(\n input: string | ResponseCreateParamsNonStreaming['input'],\n options: Omit<ResponseCreateParamsNonStreaming, 'input' | 'model'> & {\n apiKey?: string;\n model?: string;\n } = {}\n): Promise<LLMResponse<T>> => {\n const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);\n if (!isOpenAIModel(normalizedModel)) {\n throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);\n }\n\n const apiKey = resolveOpenAIApiKey(options.apiKey);\n const openai = createOpenAIClient(apiKey);\n\n // Remove apiKey from options before creating request body\n const { apiKey: _, model: __, ...cleanOptions } = options;\n\n const requestBody: ResponseCreateParamsNonStreaming = {\n model: normalizedModel,\n input,\n ...cleanOptions,\n };\n\n // Make the API call to the Responses endpoint\n const response = await openai.responses.create(requestBody);\n const cacheHitTokens = response.usage?.input_tokens_details?.cached_tokens || 0;\n const cacheWriteTokens = response.usage?.input_tokens_details?.cache_write_tokens || 0;\n\n // Extract tool calls from the output\n const toolCalls = response.output\n ?.filter((item: ResponseOutputItem): item is ResponseFunctionToolCall => item.type === 'function_call')\n .map((toolCall: ResponseFunctionToolCall) => ({\n id: toolCall.call_id,\n type: 'function' as const,\n function: {\n name: toolCall.name,\n arguments: toolCall.arguments,\n },\n }));\n\n // Extract code interpreter outputs if present\n const codeInterpreterCalls = response.output?.filter(\n (item: ResponseOutputItem): item is ResponseCodeInterpreterToolCall => item.type === 'code_interpreter_call'\n );\n let codeInterpreterOutputs: ResponseCodeInterpreterToolCall['outputs'] | undefined = undefined;\n if (codeInterpreterCalls && codeInterpreterCalls.length > 0) {\n // Each code_interpreter_call has an 'outputs' array property\n codeInterpreterOutputs = codeInterpreterCalls.flatMap((ci) => {\n // Return outputs if present, otherwise empty array\n if (ci.outputs) return ci.outputs;\n return [];\n });\n }\n\n // Handle tool calls differently\n if (toolCalls && toolCalls.length > 0) {\n return {\n response: {\n tool_calls: toolCalls.map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments),\n })),\n } as T,\n usage: {\n prompt_tokens: response.usage?.input_tokens || 0,\n completion_tokens: response.usage?.output_tokens || 0,\n reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,\n provider: 'openai',\n model: normalizedModel,\n cache_hit_tokens: cacheHitTokens,\n cache_write_tokens: cacheWriteTokens,\n cost: calculateCost(\n 'openai',\n normalizedModel,\n response.usage?.input_tokens || 0,\n response.usage?.output_tokens || 0,\n response.usage?.output_tokens_details?.reasoning_tokens || 0,\n cacheHitTokens,\n cacheWriteTokens\n ),\n },\n tool_calls: toolCalls,\n ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),\n };\n }\n\n // Extract text content from the response output\n const textContent =\n response.output\n ?.filter((item: ResponseOutputItem): item is ResponseOutputMessage => item.type === 'message')\n .map((item: ResponseOutputMessage) =>\n item.content\n .filter((content): content is ResponseOutputText => content.type === 'output_text')\n .map((content) => content.text)\n .join('')\n )\n .join('') || '';\n\n // Determine the format for parsing the response\n let parsingFormat: OpenAIResponseFormat = 'text';\n const requestedFormat = requestBody.text?.format;\n if (requestedFormat?.type === 'json_object') {\n parsingFormat = 'json';\n } else if (requestedFormat?.type === 'json_schema') {\n parsingFormat = requestedFormat;\n }\n\n // Handle regular responses\n const parsedResponse = await parseResponse<T>(textContent, parsingFormat);\n if (parsedResponse === null) {\n throw new Error('Failed to parse response from Responses API');\n }\n\n return {\n response: parsedResponse,\n usage: {\n prompt_tokens: response.usage?.input_tokens || 0,\n completion_tokens: response.usage?.output_tokens || 0,\n reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,\n provider: 'openai',\n model: normalizedModel,\n cache_hit_tokens: cacheHitTokens,\n cache_write_tokens: cacheWriteTokens,\n cost: calculateCost(\n 'openai',\n normalizedModel,\n response.usage?.input_tokens || 0,\n response.usage?.output_tokens || 0,\n response.usage?.output_tokens_details?.reasoning_tokens || 0,\n cacheHitTokens,\n cacheWriteTokens\n ),\n },\n tool_calls: toolCalls,\n ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),\n };\n};\n\n/**\n * Makes a call to the OpenAI Responses API for advanced use cases with built-in tools.\n *\n * @param input The text prompt to send to the model (e.g., \"What's in this image?\")\n * @param options The options for the Responses API call, including optional image data and context.\n * @return A promise that resolves to the response from the Responses API.\n *\n * @example\n * // With conversation context\n * const response = await makeLLMCall(\"What did I ask about earlier?\", {\n * context: [\n * { role: 'user', content: 'What is the capital of France?' },\n * { role: 'assistant', content: 'The capital of France is Paris.' }\n * ]\n * });\n */\nexport async function makeLLMCall<T = string>(\n input: string,\n options: {\n apiKey?: string;\n model?: LLMModel;\n responseFormat?: OpenAIResponseFormat;\n schema?: OpenAISchemaInput;\n schemaName?: string;\n schemaDescription?: string;\n schemaStrict?: boolean;\n tools?: Tool[];\n useCodeInterpreter?: boolean;\n useWebSearch?: boolean;\n image?: OpenAIImageInput;\n images?: OpenAIImageInput[];\n imageBase64?: string;\n imageDetail?: OpenAIImageDetail;\n context?: ContextMessage[];\n reasoningEffort?: LLMOptions['reasoning_effort'];\n reasoningMode?: LLMOptions['reasoning_mode'];\n reasoningContext?: LLMOptions['reasoning_context'];\n } = {}\n): Promise<LLMResponse<T>> {\n const {\n apiKey,\n model = DEFAULT_MODEL,\n responseFormat = 'text',\n schema,\n schemaName = 'response',\n schemaDescription,\n schemaStrict,\n tools,\n useCodeInterpreter = false,\n useWebSearch = false,\n image,\n images,\n imageBase64,\n imageDetail = 'high',\n context,\n reasoningEffort,\n reasoningMode,\n reasoningContext,\n } = options;\n\n // Validate model\n const normalizedModel = normalizeModelName(model);\n if (!isOpenAIModel(normalizedModel)) {\n throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);\n }\n\n const resolvedApiKey = resolveOpenAIApiKey(apiKey);\n const imageInputs = collectImageInputs(image, images, imageBase64);\n const openai = hasLocalFileImage(imageInputs) ? createOpenAIClient(resolvedApiKey) : undefined;\n const promptContent = await buildPromptContent(input, imageInputs, imageDetail, openai);\n\n // Process input for conversation context and image analysis\n let processedInput: string | ResponseInput;\n\n if (context && context.length > 0) {\n // Build conversation array with context\n const conversationMessages: EasyInputMessage[] = [];\n\n // Add context messages\n for (const contextMsg of context) {\n conversationMessages.push({\n role: contextMsg.role,\n content: contextMsg.content,\n type: 'message',\n });\n }\n\n // Add current input message\n if (imageInputs.length > 0) {\n // Current message includes text and one or more images\n conversationMessages.push({\n role: 'user',\n content: promptContent,\n type: 'message',\n });\n } else {\n // Current message is just text\n conversationMessages.push({\n role: 'user',\n content: input,\n type: 'message',\n });\n }\n\n processedInput = conversationMessages;\n } else if (imageInputs.length > 0) {\n // No context, but has image(s)\n processedInput = [\n {\n role: 'user',\n content: promptContent,\n type: 'message',\n },\n ];\n } else {\n // No context, no image - simple string input\n processedInput = input;\n }\n\n // Build the options object for makeResponsesAPICall\n let responsesOptions: Parameters<typeof makeResponsesAPICall>[1] = {\n apiKey: resolvedApiKey,\n model: normalizedModel,\n parallel_tool_calls: false,\n tools,\n };\n\n // Only include temperature if the model supports it\n if (supportsTemperature(normalizedModel)) {\n responsesOptions.temperature = 0.2;\n }\n\n if (reasoningEffort || reasoningMode || reasoningContext) {\n responsesOptions.reasoning = {\n ...(reasoningEffort ? { effort: reasoningEffort } : {}),\n ...(reasoningMode ? { mode: reasoningMode } : {}),\n ...(reasoningContext ? { context: reasoningContext } : {}),\n };\n }\n\n // Configure response format\n if (schema) {\n responsesOptions.text = {\n format: buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStrict),\n };\n } else if (responseFormat === 'json') {\n responsesOptions.text = { format: { type: 'json_object' } };\n } else if (typeof responseFormat === 'object' && responseFormat.type === 'json_schema') {\n responsesOptions.text = { format: responseFormat };\n }\n\n // Configure built-in tools\n if (useCodeInterpreter) {\n responsesOptions.tools = [{ type: 'code_interpreter', container: { type: 'auto' } }];\n responsesOptions.include = ['code_interpreter_call.outputs'];\n }\n\n if (useWebSearch) {\n responsesOptions.tools = [{ type: 'web_search_preview' }];\n }\n\n return await makeResponsesAPICall<T>(processedInput, responsesOptions);\n}\n", "// llm-openai-config.ts\nimport type { ImageGenerateParams } from 'openai/resources/images';\nimport type { OpenAIImageModel, OpenAIModel } from './types/llm-types';\n\nexport const DEFAULT_MODEL: OpenAIModel = 'gpt-5.6-luna';\n\nexport const DEFAULT_DEVELOPER_PROMPT = `\n You are a highly experienced coding, business analyst, and financial analyst associate.\n Help with coding, business process design and analysis, data generation and refinement, content creation, financial analysis, and more.\n When presented with a coding problem, logic problem, or other problem benefiting from systematic thinking, think through it step by step before giving your final answer.\n Present complete, high-confidence, final answers only. Do not rephrase to be more brief or omit parts of answers.\n Respond only with final content (e.g. code, a json or yaml object, a formatted string, or a markdown document) and nothing else. Do not reply with a preamble, introduction, or conclusion.\n`;\n\ninterface AIModelCosts {\n [modelName: string]: {\n inputCost: number;\n outputCost: number;\n cacheHitCost?: number;\n cacheWriteCost?: number;\n };\n}\n\nconst GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS = 272_000;\nconst GPT_5_HIGH_CONTEXT_INPUT_MULTIPLIER = 2;\nconst GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER = 1.5;\n\n/** Token costs in USD per 1M tokens. Last updated July 2026 from the OpenAI API pricing page. */\nexport const openAiModelCosts: AIModelCosts = {\n 'gpt-5.6': {\n inputCost: 5 / 1_000_000,\n cacheHitCost: 0.5 / 1_000_000,\n cacheWriteCost: 6.25 / 1_000_000,\n outputCost: 30 / 1_000_000,\n },\n 'gpt-5.6-sol': {\n inputCost: 5 / 1_000_000,\n cacheHitCost: 0.5 / 1_000_000,\n cacheWriteCost: 6.25 / 1_000_000,\n outputCost: 30 / 1_000_000,\n },\n 'gpt-5.6-terra': {\n inputCost: 2.5 / 1_000_000,\n cacheHitCost: 0.25 / 1_000_000,\n cacheWriteCost: 3.125 / 1_000_000,\n outputCost: 15 / 1_000_000,\n },\n 'gpt-5.6-luna': {\n inputCost: 1 / 1_000_000,\n cacheHitCost: 0.1 / 1_000_000,\n cacheWriteCost: 1.25 / 1_000_000,\n outputCost: 6 / 1_000_000,\n },\n 'gpt-5': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n 'gpt-5-mini': {\n inputCost: 0.25 / 1_000_000,\n cacheHitCost: 0.025 / 1_000_000,\n outputCost: 2 / 1_000_000,\n },\n 'gpt-5.4-mini': {\n inputCost: 0.75 / 1_000_000,\n cacheHitCost: 0.075 / 1_000_000,\n outputCost: 4.5 / 1_000_000,\n },\n 'gpt-5.4-nano': {\n inputCost: 0.2 / 1_000_000,\n cacheHitCost: 0.02 / 1_000_000,\n outputCost: 1.25 / 1_000_000,\n },\n 'gpt-5-nano': {\n inputCost: 0.05 / 1_000_000,\n cacheHitCost: 0.005 / 1_000_000,\n outputCost: 0.4 / 1_000_000,\n },\n 'gpt-5.1': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n 'gpt-5.4': {\n inputCost: 2.5 / 1_000_000,\n cacheHitCost: 0.25 / 1_000_000,\n outputCost: 15 / 1_000_000,\n },\n 'gpt-5.5': {\n inputCost: 5 / 1_000_000,\n cacheHitCost: 0.5 / 1_000_000,\n outputCost: 30 / 1_000_000,\n },\n 'gpt-5.5-pro': {\n inputCost: 30 / 1_000_000,\n outputCost: 180 / 1_000_000,\n },\n 'gpt-5.2': {\n inputCost: 1.75 / 1_000_000,\n cacheHitCost: 0.175 / 1_000_000,\n outputCost: 14 / 1_000_000,\n },\n 'gpt-5.2-pro': {\n inputCost: 21 / 1_000_000,\n outputCost: 168 / 1_000_000,\n },\n 'gpt-5.1-codex': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n 'gpt-5.1-codex-max': {\n inputCost: 1.25 / 1_000_000,\n cacheHitCost: 0.125 / 1_000_000,\n outputCost: 10 / 1_000_000,\n },\n};\n\nexport const deepseekModelCosts: AIModelCosts = {\n 'deepseek-chat': {\n inputCost: 0.27 / 1_000_000, // $0.27 per 1M tokens (Cache miss price)\n cacheHitCost: 0.07 / 1_000_000, // $0.07 per 1M tokens (Cache hit price)\n outputCost: 1.1 / 1_000_000, // $1.10 per 1M tokens\n },\n 'deepseek-reasoner': {\n inputCost: 0.55 / 1_000_000, // $0.55 per 1M tokens (Cache miss price)\n cacheHitCost: 0.14 / 1_000_000, // $0.14 per 1M tokens (Cache hit price)\n outputCost: 2.19 / 1_000_000, // $2.19 per 1M tokens\n },\n};\n\nfunction shouldUseGPT5HighContextPricing(model: string, inputTokens: number): boolean {\n return (\n (model === 'gpt-5.4' || model === 'gpt-5.5' || model === 'gpt-5.6' || model === 'gpt-5.6-sol' || model === 'gpt-5.6-terra' || model === 'gpt-5.6-luna') &&\n inputTokens > GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS\n );\n}\n\nexport type PricedOpenAIImageModel =\n | 'gpt-image-2'\n | 'gpt-image-2-2026-04-21'\n | 'gpt-image-1.5'\n | 'gpt-image-1'\n | 'gpt-image-1-mini';\nexport type OpenAIImagePricingQuality = 'low' | 'medium' | 'high';\nexport type OpenAIImagePricingSize = '1024x1024' | '1024x1536' | '1536x1024';\n\nexport const DEFAULT_IMAGE_PRICING_QUALITY: OpenAIImagePricingQuality = 'high';\nexport const DEFAULT_IMAGE_PRICING_SIZE: OpenAIImagePricingSize = '1024x1024';\n\nconst PRICED_OPENAI_IMAGE_MODELS: readonly PricedOpenAIImageModel[] = [\n 'gpt-image-2',\n 'gpt-image-2-2026-04-21',\n 'gpt-image-1.5',\n 'gpt-image-1',\n 'gpt-image-1-mini',\n];\nconst OPENAI_IMAGE_PRICING_SIZES: readonly OpenAIImagePricingSize[] = ['1024x1024', '1024x1536', '1536x1024'];\n\n/**\n * Estimated image output costs in USD per image for common GPT Image sizes.\n * Last updated May 2026 from the OpenAI image generation guide. Text and image\n * input token costs for prompts and edit inputs are not included.\n */\nexport const openAiImageCostByQualityAndSize: Record<\n PricedOpenAIImageModel,\n Record<OpenAIImagePricingQuality, Record<OpenAIImagePricingSize, number>>\n> = {\n 'gpt-image-2': {\n low: {\n '1024x1024': 0.006,\n '1024x1536': 0.005,\n '1536x1024': 0.005,\n },\n medium: {\n '1024x1024': 0.053,\n '1024x1536': 0.041,\n '1536x1024': 0.041,\n },\n high: {\n '1024x1024': 0.211,\n '1024x1536': 0.165,\n '1536x1024': 0.165,\n },\n },\n 'gpt-image-2-2026-04-21': {\n low: {\n '1024x1024': 0.006,\n '1024x1536': 0.005,\n '1536x1024': 0.005,\n },\n medium: {\n '1024x1024': 0.053,\n '1024x1536': 0.041,\n '1536x1024': 0.041,\n },\n high: {\n '1024x1024': 0.211,\n '1024x1536': 0.165,\n '1536x1024': 0.165,\n },\n },\n 'gpt-image-1.5': {\n low: {\n '1024x1024': 0.009,\n '1024x1536': 0.013,\n '1536x1024': 0.013,\n },\n medium: {\n '1024x1024': 0.034,\n '1024x1536': 0.05,\n '1536x1024': 0.05,\n },\n high: {\n '1024x1024': 0.133,\n '1024x1536': 0.2,\n '1536x1024': 0.2,\n },\n },\n 'gpt-image-1': {\n low: {\n '1024x1024': 0.011,\n '1024x1536': 0.016,\n '1536x1024': 0.016,\n },\n medium: {\n '1024x1024': 0.042,\n '1024x1536': 0.063,\n '1536x1024': 0.063,\n },\n high: {\n '1024x1024': 0.167,\n '1024x1536': 0.25,\n '1536x1024': 0.25,\n },\n },\n 'gpt-image-1-mini': {\n low: {\n '1024x1024': 0.005,\n '1024x1536': 0.006,\n '1536x1024': 0.006,\n },\n medium: {\n '1024x1024': 0.011,\n '1024x1536': 0.015,\n '1536x1024': 0.015,\n },\n high: {\n '1024x1024': 0.036,\n '1024x1536': 0.052,\n '1536x1024': 0.052,\n },\n },\n};\n\n/** Default image output costs in USD per image for legacy callers. */\nexport const openAiImageCosts: Record<PricedOpenAIImageModel, number> = {\n 'gpt-image-2':\n openAiImageCostByQualityAndSize['gpt-image-2'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n 'gpt-image-2-2026-04-21':\n openAiImageCostByQualityAndSize['gpt-image-2-2026-04-21'][DEFAULT_IMAGE_PRICING_QUALITY][\n DEFAULT_IMAGE_PRICING_SIZE\n ],\n 'gpt-image-1.5':\n openAiImageCostByQualityAndSize['gpt-image-1.5'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n 'gpt-image-1':\n openAiImageCostByQualityAndSize['gpt-image-1'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n 'gpt-image-1-mini':\n openAiImageCostByQualityAndSize['gpt-image-1-mini'][DEFAULT_IMAGE_PRICING_QUALITY][DEFAULT_IMAGE_PRICING_SIZE],\n};\n\nfunction isPricedOpenAIImageModel(model: string): model is PricedOpenAIImageModel {\n return PRICED_OPENAI_IMAGE_MODELS.includes(model as PricedOpenAIImageModel);\n}\n\nfunction isOpenAIImagePricingSize(size: string): size is OpenAIImagePricingSize {\n return OPENAI_IMAGE_PRICING_SIZES.includes(size as OpenAIImagePricingSize);\n}\n\nfunction resolveImagePricingQuality(quality?: ImageGenerateParams['quality']): OpenAIImagePricingQuality {\n if (quality === 'low' || quality === 'medium' || quality === 'high') {\n return quality;\n }\n\n return DEFAULT_IMAGE_PRICING_QUALITY;\n}\n\nfunction resolveImagePricingSize(size?: ImageGenerateParams['size']): OpenAIImagePricingSize {\n if (typeof size === 'string' && isOpenAIImagePricingSize(size)) {\n return size;\n }\n\n return DEFAULT_IMAGE_PRICING_SIZE;\n}\n\n/**\n * Calculates the cost of generating images using OpenAI's Images API.\n *\n * @param model The image generation model name.\n * @param imageCount The number of images generated.\n * @param quality The requested image quality.\n * @param size The requested image size.\n * @returns The cost of generating the images in USD.\n */\nexport function calculateImageCost(\n model: OpenAIImageModel | string,\n imageCount: number,\n quality?: ImageGenerateParams['quality'],\n size?: ImageGenerateParams['size']\n): number {\n if (typeof model !== 'string' || typeof imageCount !== 'number' || imageCount <= 0) {\n return 0;\n }\n\n if (!isPricedOpenAIImageModel(model)) return 0;\n\n const pricingQuality = resolveImagePricingQuality(quality);\n const pricingSize = resolveImagePricingSize(size);\n const costPerImage = openAiImageCostByQualityAndSize[model][pricingQuality][pricingSize];\n\n return imageCount * costPerImage;\n}\n\n/**\n * Calculates the cost of calling a language model in USD based on the provider and model, tokens, and given costs per 1M tokens.\n *\n * @param provider The provider of the language model. Supported providers are 'openai' and 'deepseek'.\n * @param model The name of the language model. Supported models are listed in the `openAiModelCosts` and `deepseekModelCosts` objects.\n * @param inputTokens The number of input tokens passed to the language model.\n * @param outputTokens The number of output tokens generated by the language model.\n * @param reasoningTokens The number of output tokens generated by the language model for reasoning.\n * @param cacheHitTokens The number of input tokens billed at cached-input rates.\n * @param cacheWriteTokens The number of input tokens billed at cache-write rates.\n * @returns The cost of calling the language model in USD.\n */\nexport function calculateCost(\n provider: string,\n model: string,\n inputTokens: number,\n outputTokens: number,\n reasoningTokens?: number,\n cacheHitTokens?: number,\n cacheWriteTokens?: number\n): number {\n if (\n typeof provider !== 'string' ||\n typeof model !== 'string' ||\n typeof inputTokens !== 'number' ||\n typeof outputTokens !== 'number' ||\n (reasoningTokens !== undefined && typeof reasoningTokens !== 'number') ||\n (cacheHitTokens !== undefined && typeof cacheHitTokens !== 'number') ||\n (cacheWriteTokens !== undefined && typeof cacheWriteTokens !== 'number')\n ) {\n return 0;\n }\n\n const modelCosts = provider === 'deepseek' ? deepseekModelCosts[model] : openAiModelCosts[model];\n\n if (!modelCosts) return 0;\n\n const boundedCacheHitTokens = Math.min(Math.max(cacheHitTokens || 0, 0), inputTokens);\n const boundedCacheWriteTokens = Math.min(Math.max(cacheWriteTokens || 0, 0), inputTokens - boundedCacheHitTokens);\n const uncachedInputTokens = inputTokens - boundedCacheHitTokens - boundedCacheWriteTokens;\n const inputCost =\n uncachedInputTokens * modelCosts.inputCost +\n boundedCacheHitTokens * (modelCosts.cacheHitCost || modelCosts.inputCost) +\n boundedCacheWriteTokens * (modelCosts.cacheWriteCost || modelCosts.inputCost);\n\n let outputCost = outputTokens * modelCosts.outputCost;\n let reasoningCost = (reasoningTokens || 0) * modelCosts.outputCost;\n\n if (provider === 'openai' && shouldUseGPT5HighContextPricing(model, inputTokens)) {\n return (\n inputCost * GPT_5_HIGH_CONTEXT_INPUT_MULTIPLIER +\n outputCost * GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER +\n reasoningCost * GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER\n );\n }\n\n return inputCost + outputCost + reasoningCost;\n}\n", "import OpenAI from 'openai';\nimport { DEFAULT_MODEL } from './llm-config';\n/**\n * Fix a broken JSON string by attempting to extract and parse valid JSON content. This function is very lenient and will attempt to fix many types of JSON errors, including unbalanced brackets, missing or extra commas, improperly escaped $ signs, unquoted strings, trailing commas, missing closing brackets or braces, etc.\n * @param {string} jsonStr - The broken JSON string to fix\n * @returns {JsonValue} - The parsed JSON value\n */\nexport function fixBrokenJson(jsonStr: string): JsonValue {\n // Pre-process: Fix improperly escaped $ signs\n jsonStr = jsonStr.replace(/\\\\\\$/g, '$');\n\n let index = 0;\n\n function parse(): JsonValue {\n const results: JsonValue[] = [];\n while (index < jsonStr.length) {\n skipWhitespace();\n const value = parseValue();\n if (value !== undefined) {\n results.push(value);\n } else {\n index++; // Skip invalid character\n }\n }\n return results.length === 1 ? results[0] : results;\n }\n\n function parseValue(): JsonValue | undefined {\n skipWhitespace();\n const char = getChar();\n if (!char) return undefined;\n if (char === '{') return parseObject();\n if (char === '[') return parseArray();\n if (char === '\"' || char === \"'\") return parseString();\n if (char === 't' && jsonStr.slice(index, index + 4).toLowerCase() === 'true') {\n index += 4;\n return true;\n }\n if (char === 'f' && jsonStr.slice(index, index + 5).toLowerCase() === 'false') {\n index += 5;\n return false;\n }\n if (char === 'n' && jsonStr.slice(index, index + 4).toLowerCase() === 'null') {\n index += 4;\n return null;\n }\n if (/[a-zA-Z]/.test(char)) return parseString(); // Unquoted string\n if (char === '-' || char === '.' || /\\d/.test(char)) return parseNumber();\n return undefined; // Unknown character\n }\n\n function parseObject(): JsonObject {\n const obj: JsonObject = {};\n index++; // Skip opening brace\n skipWhitespace();\n while (index < jsonStr.length && getChar() !== '}') {\n skipWhitespace();\n const key = parseString();\n if (key === undefined) {\n console.warn(`Expected key at position ${index}`);\n index++;\n continue;\n }\n skipWhitespace();\n if (getChar() === ':') {\n index++; // Skip colon\n } else {\n console.warn(`Missing colon after key \"${key}\" at position ${index}`);\n }\n skipWhitespace();\n const value = parseValue();\n if (value === undefined) {\n console.warn(`Expected value for key \"${key}\" at position ${index}`);\n index++;\n continue;\n }\n obj[key] = value;\n skipWhitespace();\n if (getChar() === ',') {\n index++; // Skip comma\n } else {\n break;\n }\n skipWhitespace();\n }\n if (getChar() === '}') {\n index++; // Skip closing brace\n } else {\n // Add a closing brace if it's missing\n jsonStr += '}';\n }\n return obj;\n }\n\n function parseArray(): JsonArray {\n const arr: JsonArray = [];\n index++; // Skip opening bracket\n skipWhitespace();\n while (index < jsonStr.length && getChar() !== ']') {\n const value = parseValue();\n if (value === undefined) {\n console.warn(`Expected value at position ${index}`);\n index++;\n } else {\n arr.push(value);\n }\n skipWhitespace();\n if (getChar() === ',') {\n index++; // Skip comma\n } else {\n break;\n }\n skipWhitespace();\n }\n if (getChar() === ']') {\n index++; // Skip closing bracket\n } else {\n console.warn(`Missing closing bracket for array at position ${index}`);\n }\n return arr;\n }\n\n function parseString(): string {\n const startChar = getChar();\n let result = '';\n let isQuoted = false;\n let delimiter = '';\n\n if (startChar === '\"' || startChar === \"'\") {\n isQuoted = true;\n delimiter = startChar;\n index++; // Skip opening quote\n }\n\n while (index < jsonStr.length) {\n const char = getChar();\n if (isQuoted) {\n if (char === delimiter) {\n index++; // Skip closing quote\n return result;\n } else if (char === '\\\\') {\n index++;\n const escapeChar = getChar();\n const escapeSequences: { [key: string]: string } = {\n n: '\\n',\n r: '\\r',\n t: '\\t',\n b: '\\b',\n f: '\\f',\n '\\\\': '\\\\',\n '/': '/',\n '\"': '\"',\n \"'\": \"'\",\n $: '$',\n };\n result += escapeSequences[escapeChar] || escapeChar;\n } else {\n result += char;\n }\n index++;\n } else {\n if (/\\s|,|}|]|\\:/.test(char)) {\n return result;\n } else {\n result += char;\n index++;\n }\n }\n }\n if (isQuoted) {\n console.warn(`Missing closing quote for string starting at position ${index}`);\n }\n return result;\n }\n\n function parseNumber(): number | undefined {\n const numberRegex = /^-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?/;\n const match = numberRegex.exec(jsonStr.slice(index));\n if (match) {\n index += match[0].length;\n return parseFloat(match[0]);\n } else {\n console.warn(`Invalid number at position ${index}`);\n index++;\n return undefined;\n }\n }\n\n function getChar(): string {\n return jsonStr[index];\n }\n\n function skipWhitespace(): void {\n while (/\\s/.test(getChar())) index++;\n }\n\n try {\n return parse();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`Error parsing JSON at position ${index}: ${msg}`);\n return null;\n }\n}\n\n/**\n * Returns true if the given JSON string is valid, false otherwise.\n *\n * This function simply attempts to parse the given string as JSON and returns true if successful, or false if an error is thrown.\n *\n * @param {string} jsonString The JSON string to validate.\n * @returns {boolean} True if the JSON string is valid, false otherwise.\n */\nexport function isValidJson(jsonString: string): boolean {\n try {\n JSON.parse(jsonString);\n return true;\n } catch {\n return false;\n }\n}\n\n// Types just for fixing JSON with AI\ninterface JsonObject {\n [key: string]: JsonValue;\n}\ntype JsonArray = JsonValue[];\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\n\nlet openai: OpenAI;\n\n/**\n * Initializes an instance of the OpenAI client, using the provided API key or the value of the OPENAI_API_KEY environment variable if no key is provided.\n * @param apiKey - the API key to use, or undefined to use the value of the OPENAI_API_KEY environment variable\n * @returns an instance of the OpenAI client\n * @throws an error if the API key is not provided and the OPENAI_API_KEY environment variable is not set\n */\nfunction initializeOpenAI(apiKey?: string): OpenAI {\n const key = apiKey || process.env.OPENAI_API_KEY;\n if (!key) {\n throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');\n }\n return new OpenAI({\n apiKey: key,\n defaultHeaders: { 'User-Agent': 'My Server-side Application (compatible; OpenAI API Client)' },\n });\n}\n\n/**\n * Fixes broken JSON by sending it to OpenAI to fix it.\n * If the model fails to return valid JSON, an error is thrown.\n * @param jsonStr - the broken JSON to fix\n * @param apiKey - the OpenAI API key to use, or undefined to use the value of the OPENAI_API_KEY environment variable\n * @returns the fixed JSON\n * @throws an error if the model fails to return valid JSON\n */\nexport async function fixJsonWithAI(jsonStr: string, apiKey?: string): Promise<JsonValue> {\n try {\n if (!openai) {\n openai = initializeOpenAI();\n }\n\n const completion = await openai.chat.completions.create({\n model: DEFAULT_MODEL,\n messages: [\n {\n role: 'system',\n content: 'You are a JSON fixer. Return only valid JSON without any additional text or explanation.',\n },\n {\n role: 'user',\n content: `Fix this broken JSON:\\n${jsonStr}`,\n },\n ],\n response_format: { type: 'json_object' },\n });\n\n const fixedJson = completion.choices[0]?.message?.content;\n\n if (fixedJson && isValidJson(fixedJson)) {\n return JSON.parse(fixedJson);\n }\n throw new Error('Failed to fix JSON with AI');\n } catch (err: unknown) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n throw new Error(`Error fixing JSON with AI: ${errorMessage}`);\n }\n}\n", "// llm-utils.ts\n\nimport { LLMModel, OpenAIModel, OpenAIResponseFormat } from './types';\nimport { fixBrokenJson, fixJsonWithAI } from './json-tools';\n\nexport function normalizeModelName(model: string): LLMModel {\n return model.replace(/_/g, '-').toLowerCase() as LLMModel;\n}\n\nexport const CODE_BLOCK_TYPES = ['javascript', 'js', 'graphql', 'json', 'typescript', 'python', 'markdown', 'yaml'];\n\n /**\n * Tries to parse JSON from the given content string according to the specified\n * response format. If the response format is 'json' or a JSON schema object, it\n * will attempt to parse the content using multiple strategies. If any of the\n * strategies succeed, it will return the parsed JSON object. If all of them fail,\n * it will throw an error.\n *\n * @param content The content string to parse\n * @param responseFormat The desired format of the response\n * @returns The parsed JSON object or null if it fails\n */\nexport async function parseResponse<T>(content: string, responseFormat: OpenAIResponseFormat): Promise<T | null> {\n if (!content) return null;\n\n if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat?.type === 'json_schema')) {\n let cleanedContent = content.trim();\n let detectedType: string | null = null;\n\n // Remove code block markers if present\n const startsWithCodeBlock = CODE_BLOCK_TYPES.some((type) => {\n if (cleanedContent.startsWith(`\\`\\`\\`${type}`)) {\n detectedType = type;\n return true;\n }\n return false;\n });\n\n if (startsWithCodeBlock && cleanedContent.endsWith('```')) {\n const firstLineEndIndex = cleanedContent.indexOf('\\n');\n if (firstLineEndIndex !== -1) {\n cleanedContent = cleanedContent.slice(firstLineEndIndex + 1, -3).trim();\n console.log(`Code block for type ${detectedType} detected and removed. Cleaned content: ${cleanedContent}`);\n }\n }\n\n // Multiple JSON parsing strategies\n const jsonParsingStrategies = [\n // Strategy 1: Direct parsing\n () => {\n try {\n return JSON.parse(cleanedContent);\n } catch {\n return null;\n }\n },\n // Strategy 2: Extract JSON from between first {} or []\n () => {\n const jsonMatch = cleanedContent.match(/[\\{\\[].*[\\}\\]]/s);\n if (jsonMatch) {\n try {\n return JSON.parse(jsonMatch[0]);\n } catch {\n return null;\n }\n }\n return null;\n },\n // Strategy 3: Remove leading/trailing text and try parsing\n () => {\n const jsonMatch = cleanedContent.replace(/^[^{[]*|[^}\\]]*$/g, '');\n try {\n return JSON.parse(jsonMatch);\n } catch {\n return null;\n }\n },\n // Strategy 4: Use fixJsonWithAI\n () => {\n return fixJsonWithAI(cleanedContent);\n },\n // Strategy 5: Use fixBrokenJson\n () => {\n return fixBrokenJson(cleanedContent);\n },\n ];\n\n // Try each parsing strategy\n for (const strategy of jsonParsingStrategies) {\n const result = await strategy();\n if (result !== null) {\n return result as T;\n }\n }\n\n // If all strategies fail, throw an error\n console.error(`Failed to parse JSON from content: ${cleanedContent}. Original JSON: ${content}`);\n throw new Error('Unable to parse JSON response');\n } else {\n return content as T;\n }\n}\n", "import OpenAI from 'openai';\nimport { ImageGenerationOptions, LLMModel, DiscoImageModel, OPENAI_MODELS } from './types';\nimport { calculateImageCost } from './llm-config';\nimport { ImageGenerateParams, ImagesResponse } from 'openai/resources/images';\n\n/**\n * Enhanced ImagesResponse that includes cost calculation\n */\nexport interface ImageResponseWithUsage extends ImagesResponse {\n usage?: ImagesResponse['usage'] & {\n provider: string;\n model: DiscoImageModel;\n cost: number;\n visionModel?: LLMModel;\n };\n}\n\nexport const DEFAULT_IMAGE_MODEL: DiscoImageModel = 'gpt-image-2';\n\nexport const resolveImageModel = (model?: DiscoImageModel): DiscoImageModel => model ?? DEFAULT_IMAGE_MODEL;\n\nconst MULTIMODAL_VISION_MODELS: ReadonlySet<LLMModel> = new Set(OPENAI_MODELS);\n\n/**\n * Makes a call to the OpenAI Images API to generate images based on a text prompt.\n *\n * This function provides access to OpenAI's image generation capabilities with support for:\n * - Different output formats (JPEG, PNG, WebP)\n * - Various image sizes and quality settings\n * - Multiple image generation in a single call\n * - Base64 encoded image data return\n *\n * @example\n * // Basic image generation\n * const response = await makeImagesCall('A beautiful sunset over mountains');\n *\n * @example\n * // Custom options\n * const response = await makeImagesCall('A birthday cake', {\n * size: '1024x1024',\n * outputFormat: 'png',\n * quality: 'high',\n * count: 2\n * });\n *\n * @param prompt - The text prompt describing the image to generate\n * @param options - Configuration options for image generation. Includes:\n * - size: Image dimensions (uses OpenAI's size options)\n * - outputFormat: Image format ('jpeg', 'png', 'webp') - defaults to 'webp'\n * - compression: Compression level (number) - defaults to 50\n * - quality: Quality setting (uses OpenAI's quality options) - defaults to 'high'\n * - count: Number of images to generate - defaults to 1\n * - background: Background setting for transparency support\n * - moderation: Content moderation level\n * - apiKey: OpenAI API key (optional, falls back to environment variable)\n * @returns Promise<ImageResponseWithUsage> - The image generation response with cost information\n * @throws Error if the API call fails or invalid parameters are provided\n */\nexport async function makeImagesCall(\n prompt: string,\n options: ImageGenerationOptions = {}\n): Promise<ImageResponseWithUsage> {\n const {\n model,\n size = 'auto',\n outputFormat = 'webp',\n compression = 50,\n quality = 'high',\n count = 1,\n background = 'auto',\n moderation = 'auto',\n apiKey,\n visionModel,\n } = options;\n const imageModel = resolveImageModel(model);\n const supportedVisionModel = visionModel && MULTIMODAL_VISION_MODELS.has(visionModel) ? visionModel : undefined;\n if (visionModel && !supportedVisionModel) {\n console.warn(\n `Vision model ${visionModel} is not recognized as a multimodal OpenAI model. Ignoring for image usage metadata.`\n );\n }\n\n // Get API key\n const effectiveApiKey = apiKey || process.env.OPENAI_API_KEY;\n if (!effectiveApiKey) {\n throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');\n }\n\n // Validate inputs\n if (!prompt || typeof prompt !== 'string') {\n throw new Error('Prompt must be a non-empty string');\n }\n\n if (count && (count < 1 || count > 10)) {\n throw new Error('Count must be between 1 and 10');\n }\n\n if (compression && (compression < 0 || compression > 100)) {\n throw new Error('Compression must be between 0 and 100');\n }\n\n const openai = new OpenAI({\n apiKey: effectiveApiKey,\n });\n\n // Build the request parameters using OpenAI's type\n const requestParams: ImageGenerateParams = {\n model: imageModel,\n prompt,\n n: count || 1,\n size: size || 'auto',\n quality: quality || 'auto',\n background: background || 'auto',\n moderation: moderation || 'auto',\n };\n\n // Add output format if specified\n if (outputFormat) {\n requestParams.output_format = outputFormat;\n }\n\n // Add compression if specified\n if (compression !== undefined) {\n requestParams.output_compression = compression;\n }\n\n try {\n // Make the API call\n const response = await openai.images.generate(requestParams);\n\n // Validate response\n if (!response.data || response.data.length === 0) {\n throw new Error('No images returned from OpenAI Images API');\n }\n\n // Calculate cost\n const cost = calculateImageCost(imageModel, count || 1, quality, size);\n\n // Return the response with enhanced usage information\n const enhancedResponse: ImageResponseWithUsage = {\n ...response,\n usage: {\n // OpenAI Images response may not include usage details per image; preserve if present\n ...(response.usage ?? {\n input_tokens: 0,\n input_tokens_details: { image_tokens: 0, text_tokens: 0 },\n output_tokens: 0,\n total_tokens: 0,\n }),\n provider: 'openai',\n model: imageModel,\n cost,\n ...(supportedVisionModel ? { visionModel: supportedVisionModel } : {}),\n },\n };\n\n return enhancedResponse;\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n throw new Error(`OpenAI Images API call failed: ${message}`);\n }\n} \n", "import OpenAI from 'openai';\nimport {\n ChatCompletionContentPart,\n ChatCompletionMessageParam,\n ChatCompletionCreateParams,\n} from 'openai/resources/chat';\n\nimport { calculateCost } from './llm-config';\nimport { parseResponse, normalizeModelName } from './llm-utils';\nimport { LLMResponse, LLMOptions, OpenAIModel, OpenAIResponseFormat, DeepseekModel, LLMModel } from './types';\n\n/**\n * Default options for Deepseek API calls\n */\nconst DEFAULT_DEEPSEEK_OPTIONS = {\n defaultModel: 'deepseek-chat' as DeepseekModel,\n};\n\n/**\n * Checks if the given model is a supported Deepseek model\n * @param model The model to check\n * @returns True if the model is supported, false otherwise\n */\nconst isSupportedDeepseekModel = (model: string): model is DeepseekModel => {\n return ['deepseek-chat', 'deepseek-reasoner'].includes(model);\n};\n\n/**\n * Checks if the given Deepseek model supports JSON output format\n * @param model The model to check\n * @returns True if JSON output is supported, false otherwise\n */\nconst supportsJsonOutput = (model: string): boolean => {\n return model === 'deepseek-chat';\n};\n\n/**\n * Checks if the given Deepseek model supports tool calling\n * @param model The model to check\n * @returns True if tool calling is supported, false otherwise\n */\nconst supportsToolCalling = (model: string): boolean => {\n return model === 'deepseek-chat';\n};\n\n/**\n * Gets the appropriate response format option for Deepseek API\n * \n * @param responseFormat The desired response format\n * @param model The model being used\n * @returns Object representing the Deepseek response format option\n */\nfunction getDeepseekResponseFormatOption(responseFormat: OpenAIResponseFormat, model: string): { type: 'text' } | { type: 'json_object' } {\n // Check if the model supports JSON output\n if (responseFormat !== 'text' && !supportsJsonOutput(model)) {\n console.warn(`Model ${model} does not support JSON output. Using text format instead.`);\n return { type: 'text' };\n }\n\n if (responseFormat === 'text') {\n return { type: 'text' };\n }\n if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) {\n return { type: 'json_object' };\n }\n return { type: 'text' };\n}\n\n/**\n * Creates a completion using the Deepseek API\n * \n * @param content The content to pass to the API\n * @param responseFormat The desired format of the response\n * @param options Additional options for the API call\n * @returns Promise resolving to the API response\n */\nasync function createDeepseekCompletion(\n content: string | ChatCompletionContentPart[],\n responseFormat: OpenAIResponseFormat,\n options: LLMOptions = {}\n) {\n // Extract the model or use default\n const modelOption = options.model || DEFAULT_DEEPSEEK_OPTIONS.defaultModel;\n const normalizedModel = normalizeModelName(modelOption);\n \n // Validate model\n if (!isSupportedDeepseekModel(normalizedModel)) {\n throw new Error(`Unsupported Deepseek model: ${normalizedModel}. Please use 'deepseek-chat' or 'deepseek-reasoner'.`);\n }\n\n // Check if tools are requested with a model that doesn't support them\n if (options.tools && options.tools.length > 0 && !supportsToolCalling(normalizedModel)) {\n throw new Error(`Model ${normalizedModel} does not support tool calling.`);\n }\n\n const apiKey = options.apiKey || process.env.DEEPSEEK_API_KEY;\n if (!apiKey) {\n throw new Error('Deepseek API key is not provided and DEEPSEEK_API_KEY environment variable is not set');\n }\n\n // Initialize OpenAI client with Deepseek API URL\n const openai = new OpenAI({\n apiKey,\n baseURL: 'https://api.deepseek.com',\n });\n\n const messages: ChatCompletionMessageParam[] = [];\n\n // Add system message with developer prompt if present\n if (options.developerPrompt) {\n messages.push({\n role: 'system',\n content: options.developerPrompt,\n });\n }\n\n // Add context if present\n if (options.context) {\n messages.push(...options.context);\n }\n\n // Add user content\n if (typeof content === 'string') {\n messages.push({\n role: 'user',\n content,\n });\n } else {\n messages.push({\n role: 'user',\n content,\n });\n }\n\n // If JSON response format, include a hint in the system prompt\n if ((responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) \n && supportsJsonOutput(normalizedModel)) {\n // If there's no system message yet, add one\n if (!messages.some(m => m.role === 'system')) {\n messages.unshift({\n role: 'system',\n content: 'Please respond in valid JSON format.',\n });\n } else {\n // Append to existing system message\n const systemMsgIndex = messages.findIndex(m => m.role === 'system');\n const systemMsg = messages[systemMsgIndex];\n if (typeof systemMsg.content === 'string') {\n messages[systemMsgIndex] = {\n ...systemMsg,\n content: `${systemMsg.content} Please respond in valid JSON format.`,\n };\n }\n }\n }\n\n const queryOptions: ChatCompletionCreateParams = {\n model: normalizedModel,\n messages,\n response_format: getDeepseekResponseFormatOption(responseFormat, normalizedModel),\n temperature: options.temperature,\n top_p: options.top_p,\n frequency_penalty: options.frequency_penalty,\n presence_penalty: options.presence_penalty,\n max_tokens: options.max_completion_tokens,\n };\n\n // Only add tools if the model supports them\n if (options.tools && supportsToolCalling(normalizedModel)) {\n queryOptions.tools = options.tools;\n }\n\n try {\n const completion = await openai.chat.completions.create(queryOptions);\n\n return {\n id: completion.id,\n content: completion.choices[0]?.message?.content || '',\n tool_calls: completion.choices[0]?.message?.tool_calls,\n usage: completion.usage || {\n prompt_tokens: 0,\n completion_tokens: 0,\n total_tokens: 0,\n },\n system_fingerprint: completion.system_fingerprint,\n provider: 'deepseek',\n model: normalizedModel as DeepseekModel,\n };\n } catch (error) {\n console.error('Error calling Deepseek API:', error);\n throw error;\n }\n}\n\n/**\n * Makes a call to the Deepseek AI API.\n *\n * @param content The content to pass to the LLM. Can be a string or an array of content parts.\n * @param responseFormat The format of the response. Defaults to 'json'.\n * @param options Configuration options including model ('deepseek-chat' or 'deepseek-reasoner'), tools, and apiKey.\n * @return A promise that resolves to the response from the Deepseek API.\n */\nexport const makeDeepseekCall = async <T = string>(\n content: string | ChatCompletionContentPart[],\n responseFormat: OpenAIResponseFormat = 'json',\n options: LLMOptions = {}\n): Promise<LLMResponse<T>> => {\n // Set default model if not provided\n const mergedOptions = {\n ...options,\n };\n\n if (!mergedOptions.model) {\n mergedOptions.model = DEFAULT_DEEPSEEK_OPTIONS.defaultModel;\n }\n\n const modelName = normalizeModelName(mergedOptions.model as string);\n \n // Check if the requested response format is compatible with the model\n if (responseFormat !== 'text' && !supportsJsonOutput(modelName)) {\n console.warn(`Model ${modelName} does not support JSON output. Will return error in the response.`);\n return {\n response: {\n error: `Model ${modelName} does not support JSON output format.`\n } as unknown as T,\n usage: {\n prompt_tokens: 0,\n completion_tokens: 0,\n reasoning_tokens: 0,\n provider: 'deepseek',\n model: modelName as DeepseekModel,\n cache_hit_tokens: 0,\n cost: 0,\n },\n tool_calls: undefined,\n };\n }\n\n // Check if tools are requested with a model that doesn't support them\n if (mergedOptions.tools && mergedOptions.tools.length > 0 && !supportsToolCalling(modelName)) {\n console.warn(`Model ${modelName} does not support tool calling. Will return error in the response.`);\n return {\n response: {\n error: `Model ${modelName} does not support tool calling.`\n } as unknown as T,\n usage: {\n prompt_tokens: 0,\n completion_tokens: 0,\n reasoning_tokens: 0,\n provider: 'deepseek',\n model: modelName as DeepseekModel,\n cache_hit_tokens: 0,\n cost: 0,\n },\n tool_calls: undefined,\n };\n }\n\n try {\n const completion = await createDeepseekCompletion(content, responseFormat, mergedOptions);\n\n // Handle tool calls similarly to OpenAI\n if (completion.tool_calls && completion.tool_calls.length > 0) {\n const fnCalls = completion.tool_calls\n .filter((tc) => tc.type === 'function')\n .map((tc) => ({\n id: tc.id,\n name: (tc as Extract<typeof tc, { type: 'function' }>).function.name,\n arguments: JSON.parse((tc as Extract<typeof tc, { type: 'function' }>).function.arguments),\n }));\n return {\n response: { tool_calls: fnCalls } as T,\n usage: {\n prompt_tokens: completion.usage.prompt_tokens,\n completion_tokens: completion.usage.completion_tokens,\n reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately\n provider: 'deepseek',\n model: completion.model,\n cache_hit_tokens: 0, // Not provided directly in API response\n cost: calculateCost(\n 'deepseek',\n completion.model,\n completion.usage.prompt_tokens,\n completion.usage.completion_tokens,\n 0,\n 0 // Cache hit tokens (not provided in the response)\n ),\n },\n tool_calls: completion.tool_calls,\n };\n }\n\n // Handle regular responses\n const parsedResponse = await parseResponse<T>(completion.content, responseFormat);\n if (parsedResponse === null) {\n throw new Error('Failed to parse Deepseek response');\n }\n\n return {\n response: parsedResponse,\n usage: {\n prompt_tokens: completion.usage.prompt_tokens,\n completion_tokens: completion.usage.completion_tokens,\n reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately\n provider: 'deepseek',\n model: completion.model,\n cache_hit_tokens: 0, // Not provided directly in API response\n cost: calculateCost(\n 'deepseek',\n completion.model,\n completion.usage.prompt_tokens,\n completion.usage.completion_tokens,\n 0,\n 0 // Cache hit tokens (not provided in the response)\n ),\n },\n tool_calls: completion.tool_calls,\n };\n } catch (error) {\n // If there's an error due to incompatible features, return a structured error\n console.error('Error in Deepseek API call:', error);\n return {\n response: {\n error: error instanceof Error ? error.message : 'Unknown error'\n } as unknown as T,\n usage: {\n prompt_tokens: 0,\n completion_tokens: 0,\n reasoning_tokens: 0,\n provider: 'deepseek',\n model: modelName as DeepseekModel,\n cache_hit_tokens: 0,\n cost: 0,\n },\n tool_calls: undefined,\n };\n }\n};\n", "// llm-openrouter.ts\n\nimport OpenAI from 'openai';\nimport type {\n ChatCompletionMessageParam,\n ChatCompletionMessageToolCall,\n ChatCompletionTool,\n ChatCompletionToolChoiceOption,\n} from 'openai/resources/chat/completions';\n\nimport { calculateCost, DEFAULT_MODEL } from './llm-config';\nimport { parseResponse, normalizeModelName } from './llm-utils';\nimport type {\n LLMResponse,\n ContextMessage,\n OpenAIResponseFormat,\n LLMModel,\n OpenAIModel,\n DeepseekModel,\n OpenRouterModel,\n} from './types/llm-types';\nimport { isOpenRouterModel } from './types/llm-types';\n\n// Use the SDK's tool choice type, compatible with OpenRouter\ntype ToolChoice = ChatCompletionToolChoiceOption;\n\n// Map our ContextMessage to OpenAI chat message\nfunction mapContextToMessages(context: ContextMessage[]): ChatCompletionMessageParam[] {\n return context.map((msg) => {\n const role = msg.role === 'developer' ? 'system' : msg.role;\n return { role, content: msg.content } as ChatCompletionMessageParam;\n });\n}\n\nfunction toOpenRouterModel(model?: string): string {\n if (model && model.includes('/')) return model;\n const base = normalizeModelName(model || DEFAULT_MODEL);\n return `openai/${base}`;\n}\n\n// Normalize model name for pricing\nfunction normalizeModelForPricing(model: string | undefined): { provider: 'openai' | 'deepseek'; coreModel: string } {\n if (!model) return { provider: 'openai', coreModel: normalizeModelName(DEFAULT_MODEL) };\n const [maybeProvider, maybeModel] = model.includes('/') ? model.split('/') : ['openai', model];\n const provider = (maybeProvider === 'deepseek' ? 'deepseek' : 'openai') as 'openai' | 'deepseek';\n const coreModel = normalizeModelName(maybeModel || model);\n return { provider, coreModel };\n}\n\nexport interface OpenRouterCallOptions {\n apiKey?: string;\n model?: OpenRouterModel | string; // OpenRouter model id (e.g., \"openai/gpt-5-mini\") or plain (\"gpt-5-mini\")\n responseFormat?: 'text' | 'json' | OpenAIResponseFormat;\n tools?: ChatCompletionTool[];\n toolChoice?: ToolChoice;\n context?: ContextMessage[];\n developerPrompt?: string;\n temperature?: number;\n max_tokens?: number;\n top_p?: number;\n frequency_penalty?: number;\n presence_penalty?: number;\n stop?: string | string[];\n seed?: number;\n // Optional headers for OpenRouter ranking\n referer?: string;\n title?: string;\n}\n\n/**\n * Make a call through OpenRouter using the OpenAI Chat Completions-compatible API.\n * Supports: JSON mode, model selection, message history, and tools.\n */\nexport async function makeOpenRouterCall<T = string>(\n input: string,\n options: OpenRouterCallOptions = {}\n): Promise<LLMResponse<T>> {\n const {\n apiKey = process.env.OPENROUTER_API_KEY,\n model,\n responseFormat = 'text',\n tools,\n toolChoice,\n context,\n developerPrompt,\n temperature = 0.2,\n max_tokens,\n top_p,\n frequency_penalty,\n presence_penalty,\n stop,\n seed,\n referer = process.env.OPENROUTER_SITE_URL,\n title = process.env.OPENROUTER_SITE_NAME,\n } = options;\n\n if (!apiKey) {\n throw new Error('OpenRouter API key is not provided and OPENROUTER_API_KEY is not set');\n }\n\n const client = new OpenAI({\n apiKey,\n baseURL: 'https://openrouter.ai/api/v1',\n defaultHeaders: {\n ...(referer ? { 'HTTP-Referer': referer } : {}),\n ...(title ? { 'X-Title': title } : {}),\n },\n });\n\n const messages: ChatCompletionMessageParam[] = [];\n if (developerPrompt && developerPrompt.trim()) {\n messages.push({ role: 'system', content: developerPrompt });\n }\n if (context && context.length > 0) {\n messages.push(...mapContextToMessages(context));\n }\n messages.push({ role: 'user', content: input });\n\n // Configure response_format\n let response_format: { type: 'json_object' } | undefined;\n let parsingFormat: OpenAIResponseFormat = 'text';\n if (responseFormat === 'json') {\n response_format = { type: 'json_object' };\n parsingFormat = 'json';\n } else if (typeof responseFormat === 'object') {\n response_format = { type: 'json_object' };\n parsingFormat = responseFormat;\n }\n\n const modelId = toOpenRouterModel(model);\n\n const completion = await client.chat.completions.create({\n model: modelId,\n messages,\n response_format,\n tools,\n tool_choice: toolChoice,\n temperature,\n max_tokens,\n top_p,\n frequency_penalty,\n presence_penalty,\n stop,\n seed,\n });\n\n const choice = completion.choices && completion.choices.length > 0 ? completion.choices[0] : undefined;\n const message = (choice && 'message' in choice ? choice.message : undefined) as\n | { content: string | null; role: string; tool_calls?: ChatCompletionMessageToolCall[] }\n | undefined;\n\n const { provider: pricingProvider, coreModel } = normalizeModelForPricing(modelId);\n const promptTokens = completion.usage?.prompt_tokens ?? 0;\n const completionTokens = completion.usage?.completion_tokens ?? 0;\n const cost = calculateCost(pricingProvider, coreModel, promptTokens, completionTokens);\n\n // Tool calls branch: return empty string response and expose tool_calls on LLMResponse\n const hasToolCalls = Array.isArray(message?.tool_calls) && message!.tool_calls!.length > 0;\n if (hasToolCalls) {\n const usageModel: LLMModel = isOpenRouterModel(modelId) ? modelId : (DEFAULT_MODEL as LLMModel);\n return {\n response: '' as T,\n usage: {\n prompt_tokens: promptTokens,\n completion_tokens: completionTokens,\n provider: 'openrouter',\n model: usageModel,\n cost,\n },\n tool_calls: message!.tool_calls as ChatCompletionMessageToolCall[],\n };\n }\n\n const rawText = typeof message?.content === 'string' ? message.content : '';\n const parsed = await parseResponse<T>(rawText, parsingFormat);\n if (parsed === null) {\n throw new Error('Failed to parse OpenRouter response');\n }\n\n // Ensure the model value conforms to LLMModel; otherwise fall back to DEFAULT_MODEL\n const usageModel: LLMModel = isOpenRouterModel(modelId) ? modelId : (DEFAULT_MODEL as LLMModel);\n\n return {\n response: parsed,\n usage: {\n prompt_tokens: promptTokens,\n completion_tokens: completionTokens,\n provider: 'openrouter',\n model: usageModel,\n cost,\n },\n ...(hasToolCalls ? { tool_calls: message!.tool_calls as ChatCompletionMessageToolCall[] } : {}),\n };\n}\n\nexport default makeOpenRouterCall;\n", "/**\n * A class to measure performance of code execution.\n *\n * This utility records elapsed time during execution and provides a detailed \n * breakdown of elapsed time between checkpoints.\n *\n * Usage example:\n * const timer = new PerformanceTimer();\n * timer.checkpoint('Start Processing');\n * // ... code for processing\n * timer.checkpoint('After Task 1');\n * // ... additional processing code\n * timer.stop();\n * console.log(timer.generateReport());\n *\n * Methods:\n * - checkpoint(label: string): Record a timestamped checkpoint.\n * - stop(): Stop the timer and compute the total elapsed time.\n * - generateReport(): Return a performance report with total time and phases.\n * - formatPerformanceReport(): Return a formatted string of the performance report.\n * - getElapsedSeconds(): Get the current elapsed time in seconds.\n */\nexport class PerformanceTimer {\n private startTime: number;\n private checkpoints: Map<string, number>;\n private totalTime: number | null;\n\n constructor() {\n this.startTime = performance.now();\n this.checkpoints = new Map();\n this.totalTime = null;\n }\n\n /**\n * Gets the current elapsed time in seconds.\n * \n * @returns The elapsed time in seconds with 3 decimal places of precision.\n */\n getElapsedSeconds(): number {\n const elapsedMs = this.totalTime ?? (performance.now() - this.startTime);\n return Number((elapsedMs / 1000).toFixed(3));\n }\n\n /**\n * Records a checkpoint with the given label.\n *\n * @param label - A descriptive label for the checkpoint.\n */\n checkpoint(label: string): void {\n this.checkpoints.set(label, performance.now());\n }\n\n /**\n * Stops the timer and sets the total elapsed time.\n */\n stop(): void {\n this.totalTime = performance.now() - this.startTime;\n }\n\n /**\n * Generates a performance report containing the total elapsed time and \n * breakdown of phases between checkpoints.\n *\n * @returns A performance report object.\n * @throws Error if the timer is not stopped before generating the report.\n */\n analyseReportData(): PerformanceReport {\n if (this.totalTime === null) {\n throw new Error('Timer must be stopped before generating report');\n }\n\n const report: PerformanceReport = {\n totalTime: this.totalTime,\n phases: []\n };\n\n let lastTime = this.startTime;\n\n // Convert checkpoints to a sorted array by time\n const sortedCheckpoints = Array.from(this.checkpoints.entries())\n .sort((a, b) => a[1] - b[1]);\n\n for (const [label, time] of sortedCheckpoints) {\n const duration = time - lastTime;\n if (duration < 0) {\n throw new Error(`Negative duration detected for checkpoint: ${label}`);\n }\n report.phases.push({\n label,\n duration\n });\n lastTime = time;\n }\n\n // Add final phase from last checkpoint to stop\n if (sortedCheckpoints.length > 0) {\n const finalDuration = this.totalTime - lastTime;\n report.phases.push({\n label: 'Final Processing',\n duration: Math.max(finalDuration, 0) // Prevent negative duration\n });\n }\n return report;\n }\n\n /**\n * Returns a formatted string of the performance report.\n *\n * @returns A string detailing the total execution time and phase breakdown.\n */\n public generateReport(): string {\n const report = this.analyseReportData();\n \n // Format numbers with thousands separators and 2 decimal places\n const formatNumber = (num: number) => \n num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });\n\n // Calculate column widths\n const maxLabelLength = Math.max(...report.phases.map(p => p.label.length), 30);\n const maxDurationLength = Math.max(...report.phases.map(p => formatNumber(p.duration).length), 10);\n\n // Create table header\n let output = `\u2554${'\u2550'.repeat(maxLabelLength + 2)}\u2566${'\u2550'.repeat(maxDurationLength + 2)}\u2557\\n`;\n output += `\u2551 ${'Phase'.padEnd(maxLabelLength)} \u2551 ${'Time (ms)'.padEnd(maxDurationLength)} \u2551\\n`;\n output += `\u2560${'\u2550'.repeat(maxLabelLength + 2)}\u256C${'\u2550'.repeat(maxDurationLength + 2)}\u2563\\n`;\n\n // Add table rows\n report.phases.forEach(phase => {\n output += `\u2551 ${phase.label.padEnd(maxLabelLength)} \u2551 ${formatNumber(phase.duration).padStart(maxDurationLength)} \u2551\\n`;\n });\n\n // Add table footer with total\n output += `\u2560${'\u2550'.repeat(maxLabelLength + 2)}\u256C${'\u2550'.repeat(maxDurationLength + 2)}\u2563\\n`;\n output += `\u2551 ${'Total'.padEnd(maxLabelLength)} \u2551 ${formatNumber(report.totalTime).padStart(maxDurationLength)} \u2551\\n`;\n output += `\u255A${'\u2550'.repeat(maxLabelLength + 2)}\u2569${'\u2550'.repeat(maxDurationLength + 2)}\u255D\\n`;\n\n return output;\n }\n}\n\n/**\n * Interface representing a single phase of performance measurement.\n */\nexport interface PerformancePhase {\n label: string;\n duration: number;\n}\n\n/**\n * Interface representing the full performance report.\n */\nexport interface PerformanceReport {\n totalTime: number;\n phases: PerformancePhase[];\n}\n", "import type {\n DiscoMailApiErrorResponse,\n DiscoMailClientOptions,\n DiscoMailCreateDomainRequest,\n DiscoMailDomain,\n DiscoMailRequestOptions,\n DiscoMailSendRequest,\n DiscoMailSendResponse,\n DiscoMailVerifyDomainResponse,\n} from './types/disco-mail-types';\n\nconst DEFAULT_DISCO_MAIL_BASE_URL = 'https://mail.discomedia.co/api/v1';\n\ninterface DiscoMailErrorEnvelope {\n error?: DiscoMailApiErrorResponse;\n code?: string;\n message?: string;\n}\n\n/** Error returned when Disco Mail rejects an API request. */\nexport class DiscoMailApiError extends Error {\n public readonly code: string;\n public readonly status: number;\n\n public constructor(code: string, message: string, status: number) {\n super(`Disco Mail API error: ${code} ${message}`);\n this.name = 'DiscoMailApiError';\n this.code = code;\n this.status = status;\n }\n}\n\n/** Server-side client for the hosted Disco Mail API. */\nexport class DiscoMailAPI {\n public constructor(private readonly clientOptions: DiscoMailClientOptions = {}) {}\n\n public async send(\n payload: DiscoMailSendRequest,\n options: DiscoMailRequestOptions = {},\n ): Promise<DiscoMailSendResponse> {\n this.validateSendRequest(payload);\n\n const headers = new Headers();\n if (options.idempotencyKey) {\n headers.set('Idempotency-Key', options.idempotencyKey);\n }\n\n return this.request<DiscoMailSendResponse>('/emails', 'POST', options, payload, headers);\n }\n\n public async listDomains(options: DiscoMailRequestOptions = {}): Promise<DiscoMailDomain[]> {\n return this.request<DiscoMailDomain[]>('/domains', 'GET', options);\n }\n\n public async getDomain(domainId: number, options: DiscoMailRequestOptions = {}): Promise<DiscoMailDomain> {\n this.validateDomainId(domainId);\n return this.request<DiscoMailDomain>(`/domains/${domainId}`, 'GET', options);\n }\n\n public async createDomain(\n payload: DiscoMailCreateDomainRequest,\n options: DiscoMailRequestOptions = {},\n ): Promise<DiscoMailDomain> {\n if (!payload.name.trim()) {\n throw new Error('Disco Mail domain name must be a non-empty string');\n }\n if (!payload.region.trim()) {\n throw new Error('Disco Mail domain region must be a non-empty string');\n }\n\n return this.request<DiscoMailDomain>('/domains', 'POST', options, payload);\n }\n\n public async verifyDomain(\n domainId: number,\n options: DiscoMailRequestOptions = {},\n ): Promise<DiscoMailVerifyDomainResponse> {\n this.validateDomainId(domainId);\n return this.request<DiscoMailVerifyDomainResponse>(`/domains/${domainId}/verify`, 'PUT', options);\n }\n\n private async request<TResponse>(\n path: string,\n method: 'GET' | 'POST' | 'PUT',\n options: DiscoMailRequestOptions,\n body?: DiscoMailSendRequest | DiscoMailCreateDomainRequest,\n additionalHeaders: Headers = new Headers(),\n ): Promise<TResponse> {\n const apiKey = this.resolveApiKey(options);\n const headers = new Headers(additionalHeaders);\n headers.set('Authorization', `Bearer ${apiKey}`);\n headers.set('Content-Type', 'application/json');\n\n const response = await fetch(`${this.resolveBaseUrl(options)}${path}`, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!response.ok) {\n throw await this.createApiError(response);\n }\n\n return (await response.json()) as TResponse;\n }\n\n private resolveApiKey(options: DiscoMailRequestOptions): string {\n const apiKey = options.apiKey || this.clientOptions.apiKey || process.env.DISCO_MAIL_API_KEY || process.env.DISCOMAIL_API_KEY;\n if (!apiKey) {\n throw new Error(\n 'Disco Mail API key is not provided. Pass options.apiKey or set DISCO_MAIL_API_KEY or DISCOMAIL_API_KEY.',\n );\n }\n return apiKey;\n }\n\n private resolveBaseUrl(options: DiscoMailRequestOptions): string {\n const baseUrl = options.baseUrl || this.clientOptions.baseUrl || DEFAULT_DISCO_MAIL_BASE_URL;\n return baseUrl.replace(/\\/+$/, '');\n }\n\n private validateSendRequest(payload: DiscoMailSendRequest): void {\n const recipients = Array.isArray(payload.to) ? payload.to : [payload.to];\n if (recipients.length === 0 || recipients.some((recipient) => !recipient.trim())) {\n throw new Error('Disco Mail send requests require at least one non-empty recipient');\n }\n if (!payload.from.trim()) {\n throw new Error('Disco Mail send requests require a non-empty from address');\n }\n if (!payload.subject?.trim() && !payload.templateId?.trim()) {\n throw new Error('Disco Mail send requests require a non-empty subject or templateId');\n }\n if (!payload.html?.trim() && !payload.text?.trim()) {\n throw new Error('Disco Mail send requests require a non-empty html or text body');\n }\n if (payload.attachments && payload.attachments.length > 10) {\n throw new Error('Disco Mail send requests support a maximum of 10 attachments');\n }\n }\n\n private validateDomainId(domainId: number): void {\n if (!Number.isInteger(domainId) || domainId <= 0) {\n throw new Error('Disco Mail domainId must be a positive integer');\n }\n }\n\n private async createApiError(response: Response): Promise<DiscoMailApiError> {\n let body: DiscoMailErrorEnvelope | null = null;\n try {\n body = (await response.json()) as DiscoMailErrorEnvelope;\n } catch {\n body = null;\n }\n\n const apiError = body?.error ?? body;\n return new DiscoMailApiError(\n apiError?.code || `HTTP_${response.status}`,\n apiError?.message || response.statusText || 'Request failed',\n response.status,\n );\n }\n}\n", "import WebSocket from 'ws';\nimport { log as baseLog } from './logging';\nimport {\n AlpacaAccountDetails,\n AlpacaAPIErrorResponse,\n AlpacaCredentials,\n AlpacaRequestContext,\n AlpacaPosition,\n AssetClass,\n GetOptionContractsParams,\n GetOrdersParams,\n JsonObject,\n JsonValue,\n OptionAccountActivity,\n OptionContract,\n OptionContractsResponse,\n AlpacaOrder,\n OrderLeg,\n TradeUpdate,\n CreateOrderParams,\n CreateMultiLegOrderParams,\n PortfolioHistoryResponse,\n EquitiesTradeOptions,\n} from './types/alpaca-types';\nimport { LogOptions } from './types/logging-types';\nimport { marketDataAPI } from './alpaca-market-data-api';\nimport { getTradingDate } from './market-time';\n\nconst limitPriceSlippagePercent100 = 0.1; // 0.1%\n\ntype AlpacaRequestBody = CreateOrderParams | CreateMultiLegOrderParams | JsonObject;\n\nclass AlpacaRequestError extends Error {\n readonly method: string;\n readonly status: number | null;\n readonly url: string;\n readonly responseCode: number | null;\n readonly responseDetails: AlpacaAPIErrorResponse | null;\n readonly rawResponse: string | null;\n readonly symbol?: string;\n\n constructor(params: {\n message: string;\n method: string;\n status?: number;\n url: string;\n responseCode?: number | null;\n responseDetails?: AlpacaAPIErrorResponse | null;\n rawResponse?: string | null;\n symbol?: string;\n }) {\n super(params.message);\n this.name = 'AlpacaRequestError';\n this.method = params.method;\n this.status = params.status ?? null;\n this.url = params.url;\n this.responseCode = params.responseCode ?? null;\n this.responseDetails = params.responseDetails ?? null;\n this.rawResponse = params.rawResponse ?? null;\n this.symbol = params.symbol;\n }\n}\n\n/** \nWebsocket example\n const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials\n alpacaAPI.onTradeUpdate((update: TradeUpdate) => {\n this.log(`Received trade update: event ${update.event} for an order to ${update.order.side} ${update.order.qty} of ${update.order.symbol}`);\n });\n alpacaAPI.connectWebsocket(); // necessary to connect to the WebSocket\n\nPortfolio History examples\n // Get standard portfolio history\n const portfolioHistory = await alpacaAPI.getPortfolioHistory({\n timeframe: '1D',\n period: '1M'\n });\n\n // Get daily portfolio history with current day included (if available from hourly data)\n const dailyHistory = await alpacaAPI.getPortfolioDailyHistory({\n period: '1M'\n });\n*/\n\nexport class AlpacaTradingAPI {\n static new(credentials: AlpacaCredentials): AlpacaTradingAPI {\n return new AlpacaTradingAPI(credentials) as AlpacaTradingAPI;\n }\n\n static getInstance(credentials: AlpacaCredentials): AlpacaTradingAPI {\n return new AlpacaTradingAPI(credentials) as AlpacaTradingAPI;\n }\n\n private ws: WebSocket | null = null;\n private headers: Record<string, string>;\n private tradeUpdateCallback: ((update: TradeUpdate) => void) | null = null;\n private credentials: AlpacaCredentials;\n private apiBaseUrl: string;\n private wsUrl: string;\n private authenticated = false;\n private connecting = false;\n private reconnectDelay = 10000; // 10 seconds between reconnection attempts\n private reconnectTimeout: NodeJS.Timeout | null = null;\n private messageHandlers: Map<string, (data: any) => void> = new Map();\n private debugLogging = false;\n private manualDisconnect = false;\n\n /**\n * Constructor for AlpacaTradingAPI\n * @param credentials - Alpaca credentials,\n * accountName: string; // The account identifier used inthis.logs and tracking\n * apiKey: string; // Alpaca API key\n * apiSecret: string; // Alpaca API secret\n * type: AlpacaAccountType;\n * orderType: AlpacaOrderType;\n * @param options - Optional options\n * debugLogging: boolean; // Whether to log messages of type 'debug'\n */\n constructor(credentials: AlpacaCredentials, options?: { debugLogging?: boolean }) {\n this.credentials = credentials;\n\n // Set URLs based on account type\n this.apiBaseUrl =\n credentials.type === 'PAPER' ? 'https://paper-api.alpaca.markets/v2' : 'https://api.alpaca.markets/v2';\n\n this.wsUrl =\n credentials.type === 'PAPER' ? 'wss://paper-api.alpaca.markets/stream' : 'wss://api.alpaca.markets/stream';\n\n this.headers = {\n 'APCA-API-KEY-ID': credentials.apiKey,\n 'APCA-API-SECRET-KEY': credentials.apiSecret,\n 'Content-Type': 'application/json',\n };\n\n // Initialize message handlers\n this.messageHandlers.set('authorization', this.handleAuthMessage.bind(this));\n this.messageHandlers.set('listening', this.handleListenMessage.bind(this));\n this.messageHandlers.set('trade_updates', this.handleTradeUpdate.bind(this));\n\n this.debugLogging = options?.debugLogging || false;\n }\n\n private log(message: string, options: LogOptions = { type: 'info' }): void {\n if (this.debugLogging && options.type === 'debug') {\n return;\n }\n baseLog(message, { ...options, source: 'AlpacaTradingAPI', account: this.credentials.accountName });\n }\n\n /**\n * Round a price to the nearest 2 decimal places for Alpaca, or 4 decimal places for prices less than $1\n * @param price - The price to round\n * @returns The rounded price\n */\n private roundPriceForAlpaca = (price: number): number => {\n return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;\n };\n\n private isJsonObject(value: JsonValue): value is JsonObject {\n return value !== null && !Array.isArray(value) && typeof value === 'object';\n }\n\n private parseAlpacaAPIErrorResponse(rawResponse: string): AlpacaAPIErrorResponse | null {\n if (rawResponse.trim() === '') {\n return null;\n }\n\n try {\n const parsedValue = JSON.parse(rawResponse) as JsonValue;\n if (!this.isJsonObject(parsedValue)) {\n return null;\n }\n\n const code = parsedValue['code'];\n const message = parsedValue['message'];\n const symbol = parsedValue['symbol'];\n\n if (typeof code !== 'number' || typeof message !== 'string') {\n return null;\n }\n\n if (symbol !== undefined && typeof symbol !== 'string') {\n return null;\n }\n\n return parsedValue as AlpacaAPIErrorResponse;\n } catch {\n return null;\n }\n }\n\n private formatJsonValueForLog(value: JsonValue | undefined): string {\n if (value === undefined) {\n return 'undefined';\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');\n }\n\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'object') {\n return JSON.stringify(value);\n }\n\n return `${value}`;\n }\n\n private formatAlpacaAPIErrorDetails(errorResponse: AlpacaAPIErrorResponse): string {\n return Object.entries(errorResponse)\n .filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')\n .map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)\n .join(', ');\n }\n\n private formatRequestAction(requestContext?: AlpacaRequestContext): string {\n return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';\n }\n\n private buildAlpacaAPIErrorMessage(params: {\n requestContext?: AlpacaRequestContext;\n status: number;\n url: string;\n errorResponse: AlpacaAPIErrorResponse | null;\n rawResponse: string;\n }): string {\n const { requestContext, status, url, errorResponse, rawResponse } = params;\n const action = this.formatRequestAction(requestContext);\n const message = errorResponse?.message ?? (rawResponse || 'No error body returned');\n const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';\n const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';\n const detailText =\n detailSummary !== ''\n ? ` Details: ${detailSummary}.`\n : rawResponse.trim() !== '' && errorResponse === null\n ? ` Response: ${rawResponse}.`\n : '';\n\n return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;\n }\n\n private buildRequestExecutionErrorMessage(params: {\n requestContext?: AlpacaRequestContext;\n url: string;\n errorMessage: string;\n }): string {\n const { requestContext, url, errorMessage } = params;\n const action = this.formatRequestAction(requestContext);\n return `${action}: ${errorMessage}. Url: ${url}`;\n }\n\n private handleAuthMessage(data: any): void {\n if (data.status === 'authorized') {\n this.authenticated = true;\n this.log('WebSocket authenticated');\n } else {\n this.log(`Authentication failed: ${data.message || 'Unknown error'}`, {\n type: 'error',\n });\n }\n }\n\n private handleListenMessage(data: any): void {\n if (data.streams?.includes('trade_updates')) {\n this.log('Successfully subscribed to trade updates');\n }\n }\n\n private handleTradeUpdate(data: TradeUpdate): void {\n if (this.tradeUpdateCallback) {\n this.log(\n `Trade update: ${data.event} to ${data.order.side} ${data.order.qty} shares${\n data.event === 'partial_fill' ? ` (filled shares: ${data.order.filled_qty})` : ''\n }, type ${data.order.type}`,\n {\n symbol: data.order.symbol,\n type: 'debug',\n }\n );\n this.tradeUpdateCallback(data);\n }\n }\n\n private handleMessage(message: string): void {\n try {\n const data = JSON.parse(message);\n const handler = this.messageHandlers.get(data.stream);\n\n if (handler) {\n handler(data.data);\n } else {\n this.log(`Received message for unknown stream: ${data.stream}`, {\n type: 'warn',\n });\n }\n } catch (error) {\n this.log('Failed to parse WebSocket message', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n }\n }\n\n connectWebsocket(): void {\n // Reset manual disconnect flag to allow reconnection logic\n this.manualDisconnect = false;\n if (this.connecting) {\n this.log('Connection attempt skipped - already connecting');\n return;\n }\n\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.log('Connection attempt skipped - already connected');\n return;\n }\n\n this.connecting = true;\n\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws.terminate();\n this.ws = null;\n }\n\n this.log(`Connecting to WebSocket at ${this.wsUrl}...`);\n\n this.ws = new WebSocket(this.wsUrl);\n\n this.ws.on('open', async () => {\n try {\n this.log('WebSocket connected');\n await this.authenticate();\n await this.subscribeToTradeUpdates();\n this.connecting = false;\n } catch (error) {\n this.log('Failed to setup WebSocket connection', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n this.ws?.close();\n }\n });\n\n this.ws.on('message', (data: WebSocket.Data) => {\n this.handleMessage(data.toString());\n });\n\n this.ws.on('error', (error) => {\n this.log('WebSocket error', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n this.connecting = false;\n });\n\n this.ws.on('close', () => {\n this.log('WebSocket connection closed');\n this.authenticated = false;\n this.connecting = false;\n\n // Clear any existing reconnect timeout\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n\n // Schedule reconnection unless this was a manual disconnect\n if (!this.manualDisconnect) {\n this.reconnectTimeout = setTimeout(() => {\n this.log('Attempting to reconnect...');\n this.connectWebsocket();\n }, this.reconnectDelay);\n }\n });\n }\n\n /**\n * Cleanly disconnect from the WebSocket and stop auto-reconnects\n */\n disconnect(): void {\n // Prevent auto-reconnect scheduling\n this.manualDisconnect = true;\n\n // Clear any scheduled reconnect\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n\n if (this.ws) {\n this.log('Disconnecting WebSocket...');\n\n // Remove listeners first to avoid duplicate handlers after reconnects\n this.ws.removeAllListeners();\n\n try {\n // Attempt graceful close\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close(1000, 'Client disconnect');\n } else {\n this.ws.terminate();\n }\n } catch {\n // Fallback terminate on any error\n try {\n this.ws.terminate();\n } catch {\n /* no-op */\n }\n }\n\n this.ws = null;\n }\n\n this.authenticated = false;\n this.connecting = false;\n this.log('WebSocket disconnected');\n }\n\n private async authenticate(): Promise<void> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not ready for authentication');\n }\n\n const authMessage = {\n action: 'auth',\n key: this.credentials.apiKey,\n secret: this.credentials.apiSecret,\n };\n\n this.ws.send(JSON.stringify(authMessage));\n\n return new Promise((resolve, reject) => {\n const authTimeout = setTimeout(() => {\n this.log('Authentication timeout', { type: 'error' });\n reject(new Error('Authentication timed out'));\n }, 10000);\n\n const handleAuthResponse = (data: WebSocket.Data) => {\n try {\n const message = JSON.parse(data.toString());\n if (message.stream === 'authorization') {\n this.ws?.removeListener('message', handleAuthResponse);\n clearTimeout(authTimeout);\n\n if (message.data?.status === 'authorized') {\n this.authenticated = true;\n resolve();\n } else {\n const error = `Authentication failed: ${message.data?.message || 'Unknown error'}`;\n this.log(error, { type: 'error' });\n reject(new Error(error));\n }\n }\n } catch (error) {\n this.log('Failed to parse auth response', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n }\n };\n\n this.ws?.on('message', handleAuthResponse);\n });\n }\n\n private async subscribeToTradeUpdates(): Promise<void> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN || !this.authenticated) {\n throw new Error('WebSocket not ready for subscription');\n }\n\n const listenMessage = {\n action: 'listen',\n data: {\n streams: ['trade_updates'],\n },\n };\n\n this.ws.send(JSON.stringify(listenMessage));\n\n return new Promise((resolve, reject) => {\n const listenTimeout = setTimeout(() => {\n reject(new Error('Subscribe timeout'));\n }, 10000);\n\n const handleListenResponse = (data: WebSocket.Data) => {\n try {\n const message = JSON.parse(data.toString());\n if (message.stream === 'listening') {\n this.ws?.removeListener('message', handleListenResponse);\n clearTimeout(listenTimeout);\n\n if (message.data?.streams?.includes('trade_updates')) {\n resolve();\n } else {\n reject(new Error('Failed to subscribe to trade updates'));\n }\n }\n } catch (error) {\n this.log('Failed to parse listen response', {\n type: 'error',\n metadata: { error: error instanceof Error ? error.message : 'Unknown error' },\n });\n }\n };\n\n this.ws?.on('message', handleListenResponse);\n });\n }\n\n private async makeRequest<TResponse>(\n endpoint: string,\n method: string = 'GET',\n body?: AlpacaRequestBody,\n queryString: string = '',\n requestContext?: AlpacaRequestContext\n ): Promise<TResponse> {\n const url = `${this.apiBaseUrl}${endpoint}${queryString}`;\n try {\n const response = await fetch(url, {\n method,\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const rawResponse = await response.text();\n const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);\n const symbol = requestContext?.symbol ?? errorResponse?.symbol;\n const error = new AlpacaRequestError({\n message: this.buildAlpacaAPIErrorMessage({\n requestContext,\n status: response.status,\n url,\n errorResponse,\n rawResponse,\n }),\n method,\n status: response.status,\n url,\n responseCode: errorResponse?.code ?? null,\n responseDetails: errorResponse,\n rawResponse,\n symbol,\n });\n\n this.log(error.message, { symbol, type: 'error' });\n throw error;\n }\n\n // Handle responses with no content (e.g., 204 No Content)\n if (response.status === 204 || response.headers.get('content-length') === '0') {\n return null as TResponse;\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType && contentType.includes('application/json')) {\n return (await response.json()) as TResponse;\n }\n\n // For non-JSON responses, return the text content\n const textContent = await response.text();\n return (textContent || null) as TResponse;\n } catch (error) {\n if (error instanceof AlpacaRequestError) {\n throw error;\n }\n\n const normalizedError = error instanceof Error ? error : new Error(`${error}`);\n const symbol = requestContext?.symbol;\n const requestError = new AlpacaRequestError({\n message: this.buildRequestExecutionErrorMessage({\n requestContext,\n url,\n errorMessage: normalizedError.message,\n }),\n method,\n url,\n rawResponse: null,\n symbol,\n });\n\n this.log(requestError.message, { symbol, type: 'error' });\n throw requestError;\n }\n }\n\n async getPositions(assetClass?: AssetClass): Promise<AlpacaPosition[]> {\n const positions = await this.makeRequest<AlpacaPosition[]>('/positions', 'GET', undefined, '', {\n action: 'Get positions',\n });\n if (assetClass) {\n return positions.filter((position) => position.asset_class === assetClass);\n }\n return positions;\n }\n\n /**\n * Get all orders\n * @param params (GetOrdersParams) - optional parameters to filter the orders\n * - status: 'open' | 'closed' | 'all'\n * - limit: number\n * - after: string\n * - until: string\n * - direction: 'asc' | 'desc'\n * - nested: boolean\n * - symbols: string[], an array of all the symbols\n * - side: 'buy' | 'sell'\n * @returns all orders\n */\n async getOrders(params: GetOrdersParams = {}): Promise<AlpacaOrder[]> {\n const queryParams = new URLSearchParams();\n\n if (params.status) queryParams.append('status', params.status);\n if (params.limit) queryParams.append('limit', params.limit.toString());\n if (params.after) queryParams.append('after', params.after);\n if (params.until) queryParams.append('until', params.until);\n if (params.direction) queryParams.append('direction', params.direction);\n if (params.nested) queryParams.append('nested', params.nested.toString());\n if (params.symbols) queryParams.append('symbols', params.symbols.join(','));\n if (params.side) queryParams.append('side', params.side);\n\n const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n return this.makeRequest<AlpacaOrder[]>(endpoint, 'GET', undefined, '', {\n action: 'Get orders',\n symbol: params.symbols?.join(','),\n });\n }\n\n async getAccountDetails(): Promise<AlpacaAccountDetails> {\n return this.makeRequest<AlpacaAccountDetails>('/account', 'GET', undefined, '', {\n action: 'Get account details',\n });\n }\n\n /**\n * Create a trailing stop order\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param trailPercent100 (number) - the trail percent of the order (scale 100, i.e. 0.5 = 0.5%)\n * @param position_intent (string) - the position intent of the order\n * @param client_order_id (string) - optional client order id\n * @returns The created trailing stop order\n */\n async createTrailingStop(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n trailPercent100: number,\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating trailing stop ${side.toUpperCase()} ${qty} shares for ${symbol} with trail percent ${trailPercent100}%`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n order_class: 'simple',\n type: 'trailing_stop',\n trail_percent: trailPercent100.toString(),\n time_in_force: 'gtc',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create trailing stop order',\n symbol,\n });\n }\n\n /**\n * Create a stop order (stop or stop-limit)\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param stopPrice (number) - the stop price that triggers the order\n * @param position_intent (string) - the position intent of the order\n * @param limitPrice (number) - optional limit price (if provided, creates a stop-limit order)\n * @param client_order_id (string) - optional client order id\n * @returns The created stop order\n */\n async createStopOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n stopPrice: number,\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n limitPrice?: number,\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n const isStopLimit = limitPrice !== undefined;\n const orderType = isStopLimit ? 'stop-limit' : 'stop';\n\n this.log(\n `Creating ${orderType} ${side.toUpperCase()} ${qty} shares for ${symbol} with stop price ${stopPrice}${isStopLimit ? ` and limit price ${limitPrice}` : ''}`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n order_class: 'simple',\n type: isStopLimit ? 'stop_limit' : 'stop',\n stop_price: this.roundPriceForAlpaca(stopPrice).toString(),\n time_in_force: 'gtc',\n };\n\n if (limitPrice !== undefined) {\n body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: `Create ${orderType} order`,\n symbol,\n });\n }\n\n /**\n * Create a market order\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param position_intent (string) - the position intent of the order. Important for knowing if a position needs a trailing stop.\n * @param client_order_id (string) - optional client order id\n */\n async createMarketOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(`Creating market order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {\n symbol,\n });\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'market',\n time_in_force: 'day',\n order_class: 'simple',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create market order',\n symbol,\n });\n }\n\n /**\n * Create a Market on Open (MOO) order - executes in the opening auction\n *\n * IMPORTANT TIMING CONSTRAINTS:\n * - Valid submission window: After 7:00pm ET and before 9:28am ET\n * - Orders submitted between 9:28am and 7:00pm ET will be REJECTED\n * - Orders submitted after 7:00pm ET are queued for the next trading day's opening auction\n * - Example: An order at 8:00pm Monday will execute at Tuesday's market open (9:30am)\n *\n * @param symbol - The symbol of the order\n * @param qty - The quantity of shares\n * @param side - Buy or sell\n * @param position_intent - The position intent (buy_to_open, sell_to_close, etc.)\n * @param client_order_id - Optional client order id\n * @returns The created order\n */\n async createMOOOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(`Creating Market on Open order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {\n symbol,\n });\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'market',\n time_in_force: 'opg',\n order_class: 'simple',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create market on open order',\n symbol,\n });\n }\n\n /**\n * Create a Market on Close (MOC) order - executes in the closing auction\n *\n * IMPORTANT TIMING CONSTRAINTS:\n * - Valid submission window: After 7:00pm ET (previous day) and before 3:50pm ET (same day)\n * - Orders submitted between 3:50pm and 7:00pm ET will be REJECTED\n * - Orders submitted after 7:00pm ET are queued for the next trading day's closing auction\n * - Example: An order at 8:00pm Monday will execute at Tuesday's market close (4:00pm)\n *\n * @param symbol - The symbol of the order\n * @param qty - The quantity of shares\n * @param side - Buy or sell\n * @param position_intent - The position intent (buy_to_open, sell_to_close, etc.)\n * @param client_order_id - Optional client order id\n * @returns The created order\n */\n async createMOCOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(`Creating Market on Close order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {\n symbol,\n });\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'market',\n time_in_force: 'cls',\n order_class: 'simple',\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create market on close order',\n symbol,\n });\n }\n\n /**\n * Create an OCO (One-Cancels-Other) order with take profit and stop loss\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order (buy or sell)\n * @param position_intent (string) - the position intent of the order\n * @param limitPrice (number) - the limit price for the entry order (OCO orders must be limit orders)\n * @param takeProfitPrice (number) - the take profit price\n * @param stopLossPrice (number) - the stop loss price\n * @param stopLossLimitPrice (number) - optional limit price for stop loss (creates stop-limit instead of stop)\n * @param client_order_id (string) - optional client order id\n * @returns The created OCO order\n */\n async createOCOOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n limitPrice: number,\n takeProfitPrice: number,\n stopLossPrice: number,\n stopLossLimitPrice?: number,\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating OCO order ${side.toUpperCase()} ${qty} shares for ${symbol} at limit ${limitPrice} with take profit ${takeProfitPrice} and stop loss ${stopLossPrice}`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n order_class: 'oco',\n type: 'limit',\n limit_price: this.roundPriceForAlpaca(limitPrice).toString(),\n time_in_force: 'gtc',\n take_profit: {\n limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),\n },\n stop_loss: {\n stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),\n },\n };\n\n // If stop loss limit price is provided, create stop-limit order\n if (stopLossLimitPrice !== undefined) {\n body.stop_loss = {\n stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),\n limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),\n };\n }\n\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create OCO order',\n symbol,\n });\n }\n\n /**\n * Get the current trail percent for a symbol, assuming that it has an open position and a trailing stop order to close it. Because this relies on an orders request for one symbol, you can't do it too often.\n * @param symbol (string) - the symbol of the order\n * @returns the current trail percent\n */\n async getCurrentTrailPercent(symbol: string): Promise<number | null> {\n const orders = await this.getOrders({\n status: 'open',\n symbols: [symbol],\n });\n\n const trailingStopOrder = orders.find(\n (order) =>\n order.type === 'trailing_stop' &&\n (order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close')\n );\n\n if (!trailingStopOrder) {\n this.log(`No closing trailing stop order found for ${symbol}`, {\n symbol,\n });\n return null;\n }\n\n if (!trailingStopOrder.trail_percent) {\n this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {\n symbol,\n });\n return null;\n }\n\n const trailPercent = parseFloat(trailingStopOrder.trail_percent);\n return trailPercent;\n }\n\n /**\n * Update the trail percent for a trailing stop order\n * @param symbol (string) - the symbol of the order\n * @param trailPercent100 (number) - the trail percent of the order (scale 100, i.e. 0.5 = 0.5%)\n */\n async updateTrailingStop(symbol: string, trailPercent100: number): Promise<void> {\n // First get all open orders for this symbol\n const orders = await this.getOrders({\n status: 'open',\n symbols: [symbol],\n });\n\n // Find the trailing stop order\n const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop');\n\n if (!trailingStopOrder) {\n this.log(`No open trailing stop order found for ${symbol}`, { type: 'error', symbol });\n return;\n }\n\n // Check if the trail_percent is already set to the desired value\n const currentTrailPercent = trailingStopOrder.trail_percent ? parseFloat(trailingStopOrder.trail_percent) : null;\n\n // Compare with a small epsilon to handle floating point precision\n const epsilon = 0.0001;\n if (currentTrailPercent !== null && Math.abs(currentTrailPercent - trailPercent100) < epsilon) {\n this.log(\n `Trailing stop for ${symbol} already set to ${trailPercent100}% (current: ${currentTrailPercent}%), skipping update`,\n {\n symbol,\n }\n );\n return;\n }\n\n this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {\n symbol,\n });\n\n await this.makeRequest<AlpacaOrder>(\n `/orders/${trailingStopOrder.id}`,\n 'PATCH',\n { trail: trailPercent100.toString() },\n '',\n {\n action: 'Update trailing stop order',\n symbol,\n }\n );\n }\n\n /**\n * Cancel all open orders\n */\n async cancelAllOrders(): Promise<void> {\n this.log(`Canceling all open orders`);\n try {\n await this.makeRequest<null>('/orders', 'DELETE', undefined, '', {\n action: 'Cancel all open orders',\n });\n } catch (error) {\n if (!(error instanceof AlpacaRequestError)) {\n this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {\n type: 'error',\n });\n }\n }\n }\n\n /**\n * Cancel a specific order by its ID\n * @param orderId The id of the order to cancel\n * @throws Error if the order is not cancelable (status 422) or if the order doesn't exist\n * @returns Promise that resolves when the order is successfully canceled\n */\n async cancelOrder(orderId: string): Promise<void> {\n this.log(`Attempting to cancel order ${orderId}`);\n\n try {\n await this.makeRequest<null>(`/orders/${orderId}`, 'DELETE', undefined, '', {\n action: `Cancel order ${orderId}`,\n });\n this.log(`Successfully canceled order ${orderId}`);\n } catch (error) {\n // If the error is a 422, it means the order is not cancelable\n if (error instanceof AlpacaRequestError && error.status === 422) {\n throw new Error(`Order ${orderId} is not cancelable`);\n }\n // Re-throw other errors\n throw error;\n }\n }\n\n /**\n * Create a limit order\n * @param symbol (string) - the symbol of the order\n * @param qty (number) - the quantity of the order\n * @param side (string) - the side of the order\n * @param limitPrice (number) - the limit price of the order\n * @param position_intent (string) - the position intent of the order\n * @param extended_hours (boolean) - whether the order is in extended hours\n * @param client_order_id (string) - the client order id of the order\n */\n async createLimitOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n limitPrice: number,\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n extended_hours: boolean = false,\n client_order_id?: string\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating limit order for ${symbol}: ${side} ${qty} shares at $${limitPrice.toFixed(2)} (${position_intent})`,\n {\n symbol,\n }\n );\n\n const body: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n position_intent,\n type: 'limit',\n limit_price: this.roundPriceForAlpaca(limitPrice).toString(),\n time_in_force: 'day',\n order_class: 'simple',\n extended_hours,\n };\n if (client_order_id !== undefined) {\n body.client_order_id = client_order_id;\n }\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', body, '', {\n action: 'Create limit order',\n symbol,\n });\n }\n\n /**\n * Close all equities positions\n * @param options (object) - the options for closing the positions\n * - cancel_orders (boolean) - whether to cancel related orders\n * - useLimitOrders (boolean) - whether to use limit orders to close the positions\n */\n async closeAllPositions(\n options: { cancel_orders: boolean; useLimitOrders: boolean } = { cancel_orders: true, useLimitOrders: false }\n ): Promise<void> {\n this.log(\n `Closing all positions${options.useLimitOrders ? ' using limit orders' : ''}${\n options.cancel_orders ? ' and canceling open orders' : ''\n }`\n );\n\n if (options.useLimitOrders) {\n // Get all positions\n const positions = await this.getPositions('us_equity');\n\n if (positions.length === 0) {\n this.log('No positions to close');\n return;\n }\n\n this.log(`Found ${positions.length} positions to close`);\n\n // Get latest quotes for all positions\n const symbols = positions.map((position) => position.symbol);\n const quotesResponse = await marketDataAPI.getLatestQuotes(symbols);\n\n const lengthOfQuotes = Object.keys(quotesResponse.quotes).length;\n if (lengthOfQuotes === 0) {\n this.log('No quotes available for positions, received 0 quotes', {\n type: 'error',\n });\n return;\n }\n\n if (lengthOfQuotes !== positions.length) {\n this.log(\n `Received ${lengthOfQuotes} quotes for ${positions.length} positions, expected ${positions.length} quotes`,\n { type: 'warn' }\n );\n return;\n }\n\n // Create limit orders to close each position\n for (const position of positions) {\n const quote = quotesResponse.quotes[position.symbol];\n if (!quote) {\n this.log(`No quote available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n const qty = Math.abs(parseFloat(position.qty));\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n // Get the current price from the quote\n const currentPrice = side === 'sell' ? quote.bp : quote.ap; // Use bid for sells, ask for buys\n\n if (!currentPrice) {\n this.log(`No valid price available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n // Apply slippage from config\n const limitSlippagePercent1 = limitPriceSlippagePercent100 / 100;\n const limitPrice =\n side === 'sell'\n ? this.roundPriceForAlpaca(currentPrice * (1 - limitSlippagePercent1)) // Sell slightly lower\n : this.roundPriceForAlpaca(currentPrice * (1 + limitSlippagePercent1)); // Buy slightly higher\n\n this.log(\n `Creating limit order to close ${position.symbol} position: ${side} ${qty} shares at $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: position.symbol,\n }\n );\n\n await this.createLimitOrder(position.symbol, qty, side, limitPrice, positionIntent);\n }\n } else {\n await this.makeRequest<null>('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {\n action: 'Close all positions',\n });\n }\n }\n\n /**\n * Close all equities positions using limit orders during extended hours trading\n * @param cancelOrders Whether to cancel related orders (default: true)\n * @returns Promise that resolves when all positions are closed\n */\n async closeAllPositionsAfterHours(): Promise<void> {\n this.log('Closing all positions using limit orders during extended hours trading');\n\n // Get all positions\n const positions = await this.getPositions();\n this.log(`Found ${positions.length} positions to close`);\n\n if (positions.length === 0) {\n this.log('No positions to close');\n return;\n }\n\n await this.cancelAllOrders();\n this.log(`Cancelled all open orders`);\n\n // Get latest quotes for all positions\n const symbols = positions.map((position) => position.symbol);\n const quotesResponse = await marketDataAPI.getLatestQuotes(symbols);\n\n // Create limit orders to close each position\n for (const position of positions) {\n const quote = quotesResponse.quotes[position.symbol];\n if (!quote) {\n this.log(`No quote available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n const qty = Math.abs(parseFloat(position.qty));\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n // Get the current price from the quote\n const currentPrice = side === 'sell' ? quote.bp : quote.ap; // Use bid for sells, ask for buys\n\n if (!currentPrice) {\n this.log(`No valid price available for ${position.symbol}, skipping limit order`, {\n symbol: position.symbol,\n type: 'warn',\n });\n continue;\n }\n\n // Apply slippage from config\n const limitSlippagePercent1 = limitPriceSlippagePercent100 / 100;\n const limitPrice =\n side === 'sell'\n ? this.roundPriceForAlpaca(currentPrice * (1 - limitSlippagePercent1)) // Sell slightly lower\n : this.roundPriceForAlpaca(currentPrice * (1 + limitSlippagePercent1)); // Buy slightly higher\n\n this.log(\n `Creating extended hours limit order to close ${\n position.symbol\n } position: ${side} ${qty} shares at $${limitPrice.toFixed(2)}`,\n {\n symbol: position.symbol,\n }\n );\n\n await this.createLimitOrder(\n position.symbol,\n qty,\n side,\n limitPrice,\n positionIntent,\n true // Enable extended hours trading\n );\n }\n\n this.log(`All positions closed: ${positions.map((p) => p.symbol).join(', ')}`);\n }\n\n onTradeUpdate(callback: (update: TradeUpdate) => void): void {\n this.tradeUpdateCallback = callback;\n }\n\n /**\n * Get portfolio history for the account\n * @param params Parameters for the portfolio history request\n * @returns Portfolio history data\n */\n async getPortfolioHistory(params: {\n timeframe?: '1Min' | '5Min' | '15Min' | '1H' | '1D';\n period?: string;\n start?: string; // Start date in ISO format\n end?: string; // End date in ISO format\n extended_hours?: boolean;\n date_end?: string;\n }): Promise<PortfolioHistoryResponse> {\n const queryParams = new URLSearchParams();\n if (params.timeframe) queryParams.append('timeframe', params.timeframe);\n if (params.period) queryParams.append('period', params.period);\n if (params.extended_hours !== undefined) queryParams.append('extended_hours', params.extended_hours.toString());\n if (params.start) queryParams.append('start', params.start);\n if (params.end) queryParams.append('end', params.end);\n if (params.date_end) queryParams.append('date_end', params.date_end);\n\n const response = await this.makeRequest<PortfolioHistoryResponse>(\n `/account/portfolio/history?${queryParams.toString()}`,\n 'GET',\n undefined,\n '',\n {\n action: 'Get portfolio history',\n }\n );\n return response;\n }\n\n /**\n * Get portfolio daily history for the account, ensuring the most recent day is included\n * by combining daily and hourly history if needed.\n *\n * This function performs two API calls:\n * 1. Retrieves daily portfolio history\n * 2. Retrieves hourly portfolio history to check for more recent data\n *\n * If hourly history has timestamps more recent than the last timestamp in daily history,\n * it appends one additional day to the daily history using the most recent hourly values.\n *\n * @param params Parameters for the portfolio history request (same as getPortfolioHistory except timeframe is forced to '1D')\n * @returns Portfolio history data with daily timeframe, including the most recent day if available from hourly data\n */\n async getPortfolioDailyHistory(params: {\n period?: string;\n start?: string; // Start date in ISO format\n end?: string; // End date in ISO format\n extended_hours?: boolean;\n date_end?: string;\n }): Promise<PortfolioHistoryResponse> {\n // Get daily and hourly history in parallel\n const dailyParams = { ...params, timeframe: '1D' as const };\n const hourlyParams = { timeframe: '1Min' as const, period: '1D' };\n\n const [dailyHistory, hourlyHistory] = await Promise.all([\n this.getPortfolioHistory(dailyParams),\n this.getPortfolioHistory(hourlyParams),\n ]);\n\n // If no hourly history, return daily as-is\n if (!hourlyHistory.timestamp || hourlyHistory.timestamp.length === 0) {\n return dailyHistory;\n }\n\n // Get the last timestamp from daily history\n const lastDailyTimestamp = dailyHistory.timestamp[dailyHistory.timestamp.length - 1];\n\n // Check if hourly history has more recent data\n const recentHourlyData = hourlyHistory.timestamp\n .map((timestamp, index) => ({ timestamp, index }))\n .filter(({ timestamp }) => timestamp > lastDailyTimestamp);\n\n // If no more recent hourly data, return daily history as-is\n if (recentHourlyData.length === 0) {\n return dailyHistory;\n }\n\n // Get the most recent hourly data point\n const mostRecentHourly = recentHourlyData[recentHourlyData.length - 1];\n const mostRecentIndex = mostRecentHourly.index;\n\n // Calculate the timestamp for the new daily entry.\n // Alpaca's daily history timestamps are at 00:00:00Z for the calendar day\n // following the NY trading date. Derive the trading date in NY time from the\n // most recent intraday timestamp, then set the new daily timestamp to\n // midnight UTC of the next calendar day.\n const mostRecentMs = mostRecentHourly.timestamp * 1000; // hourly timestamps are seconds\n const tradingDateStr = getTradingDate(new Date(mostRecentMs)); // e.g., '2025-09-05' (NY trading date)\n const [yearStr, monthStr, dayStr] = tradingDateStr.split('-');\n const year = Number(yearStr);\n const month = Number(monthStr); // 1-based\n const day = Number(dayStr);\n const newDailyTimestamp = Math.floor(Date.UTC(year, month - 1, day + 1, 0, 0, 0, 0) / 1000);\n\n // Create a new daily history entry with the most recent hourly values\n const updatedDailyHistory: PortfolioHistoryResponse = {\n ...dailyHistory,\n timestamp: [...dailyHistory.timestamp, newDailyTimestamp],\n equity: [...dailyHistory.equity, hourlyHistory.equity[mostRecentIndex]],\n profit_loss: [...dailyHistory.profit_loss, hourlyHistory.profit_loss[mostRecentIndex]],\n profit_loss_pct: [...dailyHistory.profit_loss_pct, hourlyHistory.profit_loss_pct[mostRecentIndex]],\n };\n\n return updatedDailyHistory;\n }\n\n /**\n * Get option contracts based on specified parameters\n * @param params Parameters to filter option contracts\n * @returns Option contracts matching the criteria\n */\n async getOptionContracts(params: GetOptionContractsParams): Promise<OptionContractsResponse> {\n const queryParams = new URLSearchParams();\n\n queryParams.append('underlying_symbols', params.underlying_symbols.join(','));\n\n if (params.expiration_date_gte) queryParams.append('expiration_date_gte', params.expiration_date_gte);\n if (params.expiration_date_lte) queryParams.append('expiration_date_lte', params.expiration_date_lte);\n if (params.strike_price_gte) queryParams.append('strike_price_gte', params.strike_price_gte);\n if (params.strike_price_lte) queryParams.append('strike_price_lte', params.strike_price_lte);\n if (params.type) queryParams.append('type', params.type);\n if (params.status) queryParams.append('status', params.status);\n if (params.limit) queryParams.append('limit', params.limit.toString());\n if (params.page_token) queryParams.append('page_token', params.page_token);\n\n this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {\n symbol: params.underlying_symbols.join(', '),\n });\n\n const response = await this.makeRequest<OptionContractsResponse>(\n `/options/contracts?${queryParams.toString()}`,\n 'GET',\n undefined,\n '',\n {\n action: 'Get option contracts',\n symbol: params.underlying_symbols.join(', '),\n }\n );\n this.log(`Found ${response.option_contracts.length} option contracts`, {\n symbol: params.underlying_symbols.join(', '),\n });\n return response;\n }\n\n /**\n * Get a specific option contract by symbol or ID\n * @param symbolOrId The symbol or ID of the option contract\n * @returns The option contract details\n */\n async getOptionContract(symbolOrId: string): Promise<OptionContract> {\n this.log(`Fetching option contract details for ${symbolOrId}`, {\n symbol: symbolOrId,\n });\n const response = await this.makeRequest<OptionContract>(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {\n action: 'Get option contract details',\n symbol: symbolOrId,\n });\n this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {\n symbol: symbolOrId,\n });\n return response;\n }\n\n /**\n * Create a simple option order (market or limit)\n * @param symbol Option contract symbol\n * @param qty Quantity of contracts (must be a whole number)\n * @param side Buy or sell\n * @param position_intent Position intent (buy_to_open, buy_to_close, sell_to_open, sell_to_close)\n * @param type Order type (market or limit)\n * @param limitPrice Limit price (required for limit orders)\n * @returns The created order\n */\n async createOptionOrder(\n symbol: string,\n qty: number,\n side: 'buy' | 'sell',\n position_intent: 'buy_to_open' | 'buy_to_close' | 'sell_to_open' | 'sell_to_close',\n type: 'market' | 'limit',\n limitPrice?: number\n ): Promise<AlpacaOrder> {\n if (!Number.isInteger(qty) || qty <= 0) {\n this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });\n }\n\n if (type === 'limit' && limitPrice === undefined) {\n this.log('Limit price is required for limit orders', { symbol, type: 'error' });\n }\n\n this.log(\n `Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${\n type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''\n }`,\n {\n symbol,\n }\n );\n\n const orderData: CreateOrderParams = {\n symbol,\n qty: qty.toString(),\n side,\n position_intent,\n type,\n time_in_force: 'day',\n order_class: 'simple',\n extended_hours: false,\n };\n\n if (type === 'limit' && limitPrice !== undefined) {\n orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', orderData, '', {\n action: 'Create option order',\n symbol,\n });\n }\n\n /**\n * Create a multi-leg option order\n * @param legs Array of order legs\n * @param qty Quantity of the multi-leg order (must be a whole number)\n * @param type Order type (market or limit)\n * @param limitPrice Limit price (required for limit orders)\n * @returns The created multi-leg order\n */\n async createMultiLegOptionOrder(\n legs: OrderLeg[],\n qty: number,\n type: 'market' | 'limit',\n limitPrice?: number\n ): Promise<AlpacaOrder> {\n const legSymbols = legs.map((leg) => leg.symbol).join(', ');\n\n if (!Number.isInteger(qty) || qty <= 0) {\n this.log('Quantity must be a positive whole number for option orders', {\n symbol: legSymbols,\n type: 'error',\n });\n }\n\n if (type === 'limit' && limitPrice === undefined) {\n this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });\n }\n\n if (legs.length < 2) {\n this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });\n }\n\n this.log(\n `Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${\n type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''\n }`,\n {\n symbol: legSymbols,\n }\n );\n\n const orderData: CreateMultiLegOrderParams = {\n order_class: 'mleg',\n qty: qty.toString(),\n type,\n time_in_force: 'day',\n legs,\n };\n\n if (type === 'limit' && limitPrice !== undefined) {\n orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', orderData, '', {\n action: 'Create multi-leg option order',\n symbol: legSymbols,\n });\n }\n\n /**\n * Exercise an option contract\n * @param symbolOrContractId The symbol or ID of the option contract to exercise\n * @returns Response from the exercise request\n */\n async exerciseOption(symbolOrContractId: string): Promise<null> {\n this.log(`Exercising option contract ${symbolOrContractId}`, {\n symbol: symbolOrContractId,\n });\n return this.makeRequest<null>(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {\n action: 'Exercise option contract',\n symbol: symbolOrContractId,\n });\n }\n\n /**\n * Get option positions\n * @returns Array of option positions\n */\n async getOptionPositions(): Promise<AlpacaPosition[]> {\n this.log('Fetching option positions');\n const positions = await this.getPositions('us_option');\n return positions;\n }\n\n async getOptionsOpenSpreadTrades(): Promise<void> {\n this.log('Fetching option open trades');\n // this function will get all open positions, extract the symbol and see when they were created.\n // figures out when the earliest date was (should be today)\n // then it pulls all orders after the earliest date that were closed and that were of class 'mleg'\n // Each of these contains two orders. they look like this:\n }\n\n /**\n * Get option account activities (exercises, assignments, expirations)\n * @param activityType Type of option activity to filter by\n * @param date Date to filter activities (YYYY-MM-DD format)\n * @returns Array of option account activities\n */\n async getOptionActivities(\n activityType?: 'OPEXC' | 'OPASN' | 'OPEXP',\n date?: string\n ): Promise<OptionAccountActivity[]> {\n const queryParams = new URLSearchParams();\n\n if (activityType) {\n queryParams.append('activity_types', activityType);\n } else {\n queryParams.append('activity_types', 'OPEXC,OPASN,OPEXP');\n }\n\n if (date) {\n queryParams.append('date', date);\n }\n\n this.log(\n `Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`\n );\n\n return this.makeRequest<OptionAccountActivity[]>(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {\n action: 'Get option activities',\n });\n }\n\n /**\n * Create a long call spread (buy lower strike call, sell higher strike call)\n * @param lowerStrikeCallSymbol Symbol of the lower strike call option\n * @param higherStrikeCallSymbol Symbol of the higher strike call option\n * @param qty Quantity of spreads to create (must be a whole number)\n * @param limitPrice Limit price for the spread\n * @returns The created multi-leg order\n */\n async createLongCallSpread(\n lowerStrikeCallSymbol: string,\n higherStrikeCallSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating long call spread: Buy ${lowerStrikeCallSymbol}, Sell ${higherStrikeCallSymbol}, Qty: ${qty}, Price: $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: `${lowerStrikeCallSymbol},${higherStrikeCallSymbol}`,\n }\n );\n\n const legs: OrderLeg[] = [\n {\n symbol: lowerStrikeCallSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n {\n symbol: higherStrikeCallSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Create a long put spread (buy higher strike put, sell lower strike put)\n * @param higherStrikePutSymbol Symbol of the higher strike put option\n * @param lowerStrikePutSymbol Symbol of the lower strike put option\n * @param qty Quantity of spreads to create (must be a whole number)\n * @param limitPrice Limit price for the spread\n * @returns The created multi-leg order\n */\n async createLongPutSpread(\n higherStrikePutSymbol: string,\n lowerStrikePutSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating long put spread: Buy ${higherStrikePutSymbol}, Sell ${lowerStrikePutSymbol}, Qty: ${qty}, Price: $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: `${higherStrikePutSymbol},${lowerStrikePutSymbol}`,\n }\n );\n\n const legs: OrderLeg[] = [\n {\n symbol: higherStrikePutSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n {\n symbol: lowerStrikePutSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Create an iron condor (sell call spread and put spread)\n * @param longPutSymbol Symbol of the lower strike put (long)\n * @param shortPutSymbol Symbol of the higher strike put (short)\n * @param shortCallSymbol Symbol of the lower strike call (short)\n * @param longCallSymbol Symbol of the higher strike call (long)\n * @param qty Quantity of iron condors to create (must be a whole number)\n * @param limitPrice Limit price for the iron condor (credit)\n * @returns The created multi-leg order\n */\n async createIronCondor(\n longPutSymbol: string,\n shortPutSymbol: string,\n shortCallSymbol: string,\n longCallSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(`Creating iron condor with ${qty} contracts at $${limitPrice.toFixed(2)}`, {\n symbol: `${longPutSymbol},${shortPutSymbol},${shortCallSymbol},${longCallSymbol}`,\n });\n\n const legs: OrderLeg[] = [\n {\n symbol: longPutSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n {\n symbol: shortPutSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n {\n symbol: shortCallSymbol,\n ratio_qty: '1',\n side: 'sell',\n position_intent: 'sell_to_open',\n },\n {\n symbol: longCallSymbol,\n ratio_qty: '1',\n side: 'buy',\n position_intent: 'buy_to_open',\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Create a covered call (sell call option against owned stock)\n * @param stockSymbol Symbol of the underlying stock\n * @param callOptionSymbol Symbol of the call option to sell\n * @param qty Quantity of covered calls to create (must be a whole number)\n * @param limitPrice Limit price for the call option\n * @returns The created order\n */\n async createCoveredCall(\n stockSymbol: string,\n callOptionSymbol: string,\n qty: number,\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(\n `Creating covered call: Sell ${callOptionSymbol} against ${stockSymbol}, Qty: ${qty}, Price: $${limitPrice.toFixed(\n 2\n )}`,\n {\n symbol: `${stockSymbol},${callOptionSymbol}`,\n }\n );\n\n // For covered calls, we don't need to include the stock leg if we already own the shares\n // We just create a simple sell order for the call option\n return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);\n }\n\n /**\n * Roll an option position to a new expiration or strike\n * @param currentOptionSymbol Symbol of the current option position\n * @param newOptionSymbol Symbol of the new option to roll to\n * @param qty Quantity of options to roll (must be a whole number)\n * @param currentPositionSide Side of the current position ('buy' or 'sell')\n * @param limitPrice Net limit price for the roll\n * @returns The created multi-leg order\n */\n async rollOptionPosition(\n currentOptionSymbol: string,\n newOptionSymbol: string,\n qty: number,\n currentPositionSide: 'buy' | 'sell',\n limitPrice: number\n ): Promise<AlpacaOrder> {\n this.log(`Rolling ${qty} ${currentOptionSymbol} to ${newOptionSymbol} at net price $${limitPrice.toFixed(2)}`, {\n symbol: `${currentOptionSymbol},${newOptionSymbol}`,\n });\n\n // If current position is long, we need to sell to close and buy to open\n // If current position is short, we need to buy to close and sell to open\n const closePositionSide = currentPositionSide === 'buy' ? 'sell' : 'buy';\n const openPositionSide = currentPositionSide;\n\n const closePositionIntent = closePositionSide === 'buy' ? 'buy_to_close' : 'sell_to_close';\n const openPositionIntent = openPositionSide === 'buy' ? 'buy_to_open' : 'sell_to_open';\n\n const legs: OrderLeg[] = [\n {\n symbol: currentOptionSymbol,\n ratio_qty: '1',\n side: closePositionSide,\n position_intent: closePositionIntent,\n },\n {\n symbol: newOptionSymbol,\n ratio_qty: '1',\n side: openPositionSide,\n position_intent: openPositionIntent,\n },\n ];\n\n return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);\n }\n\n /**\n * Get option chain for a specific underlying symbol and expiration date\n * @param underlyingSymbol The underlying stock symbol\n * @param expirationDate The expiration date (YYYY-MM-DD format)\n * @returns Option contracts for the specified symbol and expiration date\n */\n async getOptionChain(underlyingSymbol: string, expirationDate: string): Promise<OptionContract[]> {\n this.log(`Fetching option chain for ${underlyingSymbol} with expiration date ${expirationDate}`, {\n symbol: underlyingSymbol,\n });\n\n try {\n const params: GetOptionContractsParams = {\n underlying_symbols: [underlyingSymbol],\n expiration_date_gte: expirationDate,\n expiration_date_lte: expirationDate,\n status: 'active',\n limit: 500, // Get a large number to ensure we get all strikes\n };\n\n const response = await this.getOptionContracts(params);\n return response.option_contracts || [];\n } catch (error) {\n if (!(error instanceof AlpacaRequestError)) {\n this.log(\n `Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`,\n {\n type: 'error',\n symbol: underlyingSymbol,\n }\n );\n }\n return [];\n }\n }\n\n /**\n * Get all available expiration dates for a specific underlying symbol\n * @param underlyingSymbol The underlying stock symbol\n * @returns Array of available expiration dates\n */\n async getOptionExpirationDates(underlyingSymbol: string): Promise<string[]> {\n this.log(`Fetching available expiration dates for ${underlyingSymbol}`, {\n symbol: underlyingSymbol,\n });\n\n try {\n const params: GetOptionContractsParams = {\n underlying_symbols: [underlyingSymbol],\n status: 'active',\n limit: 1000, // Get a large number to ensure we get contracts with all expiration dates\n };\n\n const response = await this.getOptionContracts(params);\n\n // Extract unique expiration dates\n const expirationDates = new Set<string>();\n if (response.option_contracts) {\n response.option_contracts.forEach((contract) => {\n expirationDates.add(contract.expiration_date);\n });\n }\n\n // Convert to array and sort\n return Array.from(expirationDates).sort();\n } catch (error) {\n if (!(error instanceof AlpacaRequestError)) {\n this.log(\n `Failed to fetch expiration dates for ${underlyingSymbol}: ${\n error instanceof Error ? error.message : `${error}`\n }`,\n {\n type: 'error',\n symbol: underlyingSymbol,\n }\n );\n }\n return [];\n }\n }\n\n /**\n * Get the current options trading level for the account\n * @returns The options trading level (0-3)\n */\n async getOptionsTradingLevel(): Promise<number> {\n this.log('Fetching options trading level');\n\n const accountDetails = await this.getAccountDetails();\n return accountDetails.options_trading_level || 0;\n }\n\n /**\n * Check if the account has options trading enabled\n * @returns Boolean indicating if options trading is enabled\n */\n async isOptionsEnabled(): Promise<boolean> {\n this.log('Checking if options trading is enabled');\n\n const accountDetails = await this.getAccountDetails();\n\n // Check if options trading level is 2 or higher (Level 2+ allows buying calls/puts)\n // Level 0: Options disabled\n // Level 1: Only covered calls and cash-secured puts\n // Level 2+: Can buy calls and puts (required for executeOptionsOrder)\n const optionsLevel = accountDetails.options_trading_level || 0;\n const isEnabled = optionsLevel >= 2;\n\n this.log(`Options trading level: ${optionsLevel}, enabled: ${isEnabled}`);\n\n return isEnabled;\n }\n\n /**\n * Close all option positions\n * @param cancelOrders Whether to cancel related orders (default: true)\n * @returns Response from the close positions request\n */\n async closeAllOptionPositions(cancelOrders: boolean = true): Promise<void> {\n this.log(`Closing all option positions${cancelOrders ? ' and canceling related orders' : ''}`);\n\n const optionPositions = await this.getOptionPositions();\n\n if (optionPositions.length === 0) {\n this.log('No option positions to close');\n return;\n }\n\n // Create market orders to close each position\n for (const position of optionPositions) {\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n this.log(`Closing ${position.side} position of ${position.qty} contracts for ${position.symbol}`, {\n symbol: position.symbol,\n });\n\n await this.createOptionOrder(position.symbol, parseInt(position.qty), side, positionIntent, 'market');\n }\n\n if (cancelOrders) {\n // Get all open option orders\n const orders = await this.getOrders({ status: 'open' });\n const optionOrders = orders.filter((order) => order.asset_class === 'us_option');\n\n // Cancel each open option order\n for (const order of optionOrders) {\n this.log(`Canceling open order for ${order.symbol}`, {\n symbol: order.symbol,\n });\n await this.makeRequest<null>(`/orders/${order.id}`, 'DELETE', undefined, '', {\n action: `Cancel option order ${order.id}`,\n symbol: order.symbol,\n });\n }\n }\n }\n\n /**\n * Close a specific option position\n * @param symbol The option contract symbol\n * @param qty Optional quantity to close (defaults to entire position)\n * @returns The created order\n */\n async closeOptionPosition(symbol: string, qty?: number): Promise<AlpacaOrder> {\n this.log(`Closing option position for ${symbol}${qty ? ` (${qty} contracts)` : ''}`, {\n symbol,\n });\n\n // Get the position details\n const positions = await this.getOptionPositions();\n const position = positions.find((p) => p.symbol === symbol);\n\n if (!position) {\n throw new Error(`No position found for option contract ${symbol}`);\n }\n\n const quantityToClose = qty || parseInt(position.qty);\n const side = position.side === 'long' ? 'sell' : 'buy';\n const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';\n\n return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');\n }\n\n /**\n * Create a complete equities trade with optional stop loss and take profit\n * @param params Trade parameters including symbol, qty, side, and optional referencePrice\n * @param options Trade options including order type, extended hours, stop loss, and take profit settings\n * @returns The created order\n */\n async createEquitiesTrade(\n params: {\n symbol: string;\n qty: number;\n side: 'buy' | 'sell';\n referencePrice?: number;\n },\n options?: EquitiesTradeOptions\n ): Promise<AlpacaOrder> {\n const { symbol, qty, side, referencePrice } = params;\n const {\n type = 'market',\n limitPrice,\n extendedHours = false,\n useStopLoss = false,\n stopPrice,\n stopPercent100,\n useTakeProfit = false,\n takeProfitPrice,\n takeProfitPercent100,\n clientOrderId,\n } = options || {};\n\n // Validation: Extended hours + market order is not allowed\n if (extendedHours && type === 'market') {\n this.log('Cannot create market order with extended hours enabled', {\n symbol,\n type: 'error',\n });\n throw new Error('Cannot create market order with extended hours enabled');\n }\n\n // Validation: Limit orders require limit price\n if (type === 'limit' && limitPrice === undefined) {\n this.log('Limit price is required for limit orders', {\n symbol,\n type: 'error',\n });\n throw new Error('Limit price is required for limit orders');\n }\n\n let calculatedStopPrice: number | undefined;\n let calculatedTakeProfitPrice: number | undefined;\n\n // Handle stop loss validation and calculation\n if (useStopLoss) {\n if (stopPrice === undefined && stopPercent100 === undefined) {\n this.log('Either stopPrice or stopPercent100 must be provided when useStopLoss is true', {\n symbol,\n type: 'error',\n });\n throw new Error('Either stopPrice or stopPercent100 must be provided when useStopLoss is true');\n }\n\n if (stopPercent100 !== undefined) {\n if (referencePrice === undefined) {\n this.log('referencePrice is required when using stopPercent100', {\n symbol,\n type: 'error',\n });\n throw new Error('referencePrice is required when using stopPercent100');\n }\n\n // Calculate stop price based on percentage and side\n const stopPercentDecimal = stopPercent100 / 100;\n if (side === 'buy') {\n // For buy orders, stop loss is below the reference price\n calculatedStopPrice = referencePrice * (1 - stopPercentDecimal);\n } else {\n // For sell orders, stop loss is above the reference price\n calculatedStopPrice = referencePrice * (1 + stopPercentDecimal);\n }\n } else {\n calculatedStopPrice = stopPrice;\n }\n }\n\n // Handle take profit validation and calculation\n if (useTakeProfit) {\n if (takeProfitPrice === undefined && takeProfitPercent100 === undefined) {\n this.log('Either takeProfitPrice or takeProfitPercent100 must be provided when useTakeProfit is true', {\n symbol,\n type: 'error',\n });\n throw new Error('Either takeProfitPrice or takeProfitPercent100 must be provided when useTakeProfit is true');\n }\n\n if (takeProfitPercent100 !== undefined) {\n if (referencePrice === undefined) {\n this.log('referencePrice is required when using takeProfitPercent100', {\n symbol,\n type: 'error',\n });\n throw new Error('referencePrice is required when using takeProfitPercent100');\n }\n\n // Calculate take profit price based on percentage and side\n const takeProfitPercentDecimal = takeProfitPercent100 / 100;\n if (side === 'buy') {\n // For buy orders, take profit is above the reference price\n calculatedTakeProfitPrice = referencePrice * (1 + takeProfitPercentDecimal);\n } else {\n // For sell orders, take profit is below the reference price\n calculatedTakeProfitPrice = referencePrice * (1 - takeProfitPercentDecimal);\n }\n } else {\n calculatedTakeProfitPrice = takeProfitPrice;\n }\n }\n\n // Determine order class based on what's enabled\n let orderClass: 'simple' | 'oto' | 'bracket' = 'simple';\n if (useStopLoss && useTakeProfit) {\n orderClass = 'bracket';\n } else if (useStopLoss || useTakeProfit) {\n orderClass = 'oto';\n }\n\n // Build the order request\n const orderData: CreateOrderParams = {\n symbol,\n qty: Math.abs(qty).toString(),\n side,\n type,\n time_in_force: 'day',\n order_class: orderClass,\n extended_hours: extendedHours,\n position_intent: side === 'buy' ? 'buy_to_open' : 'sell_to_open',\n };\n\n if (clientOrderId) {\n orderData.client_order_id = clientOrderId;\n }\n\n // Add limit price for limit orders\n if (type === 'limit' && limitPrice !== undefined) {\n orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();\n }\n\n // Add stop loss if enabled\n if (useStopLoss && calculatedStopPrice !== undefined) {\n orderData.stop_loss = {\n stop_price: this.roundPriceForAlpaca(calculatedStopPrice).toString(),\n };\n }\n\n // Add take profit if enabled\n if (useTakeProfit && calculatedTakeProfitPrice !== undefined) {\n orderData.take_profit = {\n limit_price: this.roundPriceForAlpaca(calculatedTakeProfitPrice).toString(),\n };\n }\n\n const logMessage = `Creating ${orderClass} ${type} ${side} order for ${symbol}: ${qty} shares${\n type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''\n }${useStopLoss ? ` with stop loss at $${calculatedStopPrice?.toFixed(2)}` : ''}${\n useTakeProfit ? ` with take profit at $${calculatedTakeProfitPrice?.toFixed(2)}` : ''\n }${extendedHours ? ' (extended hours)' : ''}`;\n\n this.log(logMessage, {\n symbol,\n });\n\n return this.makeRequest<AlpacaOrder>('/orders', 'POST', orderData, '', {\n action: 'Create equities trade',\n symbol,\n });\n }\n}\n", "import 'dotenv/config';\nimport { log as baseLog } from './logging';\nimport { LogOptions } from './types/logging-types';\nimport {\n Bar,\n AlpacaQuote,\n TimeFrame,\n AlpacaTrade,\n AlpacaAsset,\n AssetClass,\n GetAssetsParams,\n OptionBar,\n OptionTrade,\n OptionsChainParams,\n OptionsChainResponse,\n LatestOptionsTradesParams,\n LatestOptionsTradesResponse,\n LatestOptionsQuotesParams,\n LatestOptionsQuotesResponse,\n LatestQuotesResponse,\n LatestTradesResponse,\n HistoricalOptionsBarsParams,\n HistoricalOptionsBarsResponse,\n HistoricalOptionsTradesParams,\n HistoricalOptionsTradesResponse,\n OptionsSnapshotsParams,\n OptionsSnapshotsResponse,\n OptionsConditionCodesResponse,\n OptionsExchangeCodesResponse,\n OptionTickType,\n SimpleNews,\n AlpacaNewsArticle,\n DataFeed,\n AlpacaStockStreamMessage,\n AlpacaOptionStreamMessage,\n StockStreamEventName,\n OptionStreamEventName,\n StockStreamEventMap,\n OptionStreamEventMap,\n CryptoTrade,\n CryptoQuote,\n CryptoOrderbook,\n CryptoSnapshot,\n CryptoHistoricalBarsResponse,\n CryptoLatestBarsResponse,\n CryptoHistoricalQuotesResponse,\n CryptoLatestQuotesResponse,\n CryptoHistoricalTradesResponse,\n CryptoLatestTradesResponse,\n CryptoSnapshotsResponse,\n CryptoLatestOrderbooksResponse,\n CryptoHistoricalBarsParams,\n CryptoHistoricalQuotesParams,\n CryptoHistoricalTradesParams,\n} from './types/alpaca-types';\nimport { getLastFullTradingDate } from './market-time';\nimport { EventEmitter } from 'events';\nimport WebSocket from 'ws';\n\nconst DEBUG_LOGGING = process.env['DEBUG'] === 'true' || false;\n\nconst log = (message: string, options: LogOptions = { type: 'info' }) => {\n if (!DEBUG_LOGGING && options.type === 'debug') {\n return;\n }\n baseLog(message, { ...options, source: 'AlpacaMarketDataAPI' });\n};\n\n// Default settings for market data API\nconst DEFAULT_ADJUSTMENT = 'all' as const;\nconst DEFAULT_FEED = 'sip' as DataFeed;\nconst DEFAULT_CURRENCY = 'USD' as const;\n\n/**\n * Parameters for retrieving historical market data bars\n * @see https://data.alpaca.markets/v2/stocks/bars\n */\nexport interface HistoricalBarsParams {\n /** Comma-separated list of stock symbols to query, e.g. 'AAPL,MSFT,TSLA' */\n symbols: string[];\n /**\n * Bar duration/timeframe\n * Format: [1-59]Min/T, [1-23]Hour/H, 1Day/D, 1Week/W, [1,2,3,4,6,12]Month/M\n * Examples: \"1Min\", \"5Min\", \"1Hour\", \"1Day\", \"1Week\", \"1Month\"\n */\n timeframe: TimeFrame;\n /**\n * Start datetime in RFC-3339 format (YYYY-MM-DD)\n * Example: \"2024-02-11T09:00:00Z\"\n */\n start?: string;\n /**\n * End datetime in RFC-3339 format (YYYY-MM-DD)\n * Example: \"2024-02-11T16:00:00Z\"\n */\n end?: string;\n /**\n * Number of bars to return (1-10000)\n * Default: 1000\n */\n limit?: number;\n /** \n\n /** \n * Pagination token for retrieving next page of results\n * Returned in the next_page_token field of the response\n */\n page_token?: string;\n /**\n * Specifies the price adjustments applied to the bars\n * - raw: no adjustments\n * - split: adjust for forward and reverse stock splits\n * - dividend: adjust for cash dividends\n * - spin-off: adjust for spin-offs\n * - all: apply all adjustments (default)\n * Can also be comma-separated combinations, e.g. 'split,spin-off'\n */\n adjustment?: 'raw' | 'split' | 'dividend' | 'spin-off' | 'all' | string;\n /**\n * Sort order of returned bars\n * - asc: Oldest to newest (default)\n * - desc: Newest to oldest\n */\n sort?: 'asc' | 'desc';\n}\n\n/**\n * Response from historical bars endpoint\n * Contains OHLCV (Open, High, Low, Close, Volume) data for requested symbols\n */\nexport interface HistoricalBarsResponse {\n /**\n * Map of symbol to array of bar data\n * Each bar contains OHLCV data for the specified timeframe\n */\n bars: {\n [symbol: string]: Bar[];\n };\n /**\n * Token for retrieving the next page of results\n * null if there are no more results\n */\n next_page_token: string | null;\n /** Currency of the price data in ISO 4217 format */\n currency: string;\n}\n\n/**\n * Response from latest bars endpoint\n * Contains the most recent minute bar for each requested symbol\n */\nexport interface LatestBarsResponse {\n /**\n * Map of symbol to latest bar data\n * Each bar contains OHLCV data for the most recent minute\n */\n bars: {\n [symbol: string]: Bar;\n };\n /** Currency of the price data in ISO 4217 format */\n currency: string;\n}\n\n/**\n * Response from last trade endpoint for a single symbol\n * Contains detailed information about the most recent trade\n */\nexport interface LastTradeResponse {\n /** Status of the request */\n status: string;\n /** The stock symbol that was queried */\n symbol: string;\n /**\n * Details of the last trade\n * @property price - Trade price\n * @property size - Trade size (quantity)\n * @property exchange - Exchange where trade occurred (see Common Exchange Codes in docs)\n * @property cond1-4 - Trade conditions\n * @property timestamp - UNIX epoch timestamp in milliseconds\n */\n last: {\n price: number;\n size: number;\n exchange: number;\n cond1: number;\n cond2: number;\n cond3: number;\n cond4: number;\n timestamp: number;\n };\n}\n\n/**\n * Singleton class for interacting with Alpaca Market Data API\n * Provides methods for fetching historical bars, latest bars, last trades, latest trades, latest quotes, and latest quote for a single symbol\n */\nexport class AlpacaMarketDataAPI extends EventEmitter {\n private static instance: AlpacaMarketDataAPI;\n private headers: Record<string, string>;\n private dataURL: string;\n private apiURL: string;\n private v1beta1url: string;\n private v1beta3url: string;\n private stockStreamUrl: string = 'wss://stream.data.alpaca.markets/v2/sip'; // production values\n private optionStreamUrl: string = 'wss://stream.data.alpaca.markets/v1beta3/options'; // production values\n private stockWs: WebSocket | null = null;\n private optionWs: WebSocket | null = null;\n private stockSubscriptions: Record<string, string[]> = { trades: [], quotes: [], bars: [] };\n private optionSubscriptions: Record<string, string[]> = { trades: [], quotes: [], bars: [] };\n private autoReconnect: boolean = true;\n private stockReconnectAttempts: number = 0;\n private optionReconnectAttempts: number = 0;\n private stockReconnectTimeout: NodeJS.Timeout | null = null;\n private optionReconnectTimeout: NodeJS.Timeout | null = null;\n\n public setMode(mode: 'sandbox' | 'test' | 'production' = 'production'): void {\n if (mode === 'sandbox') {\n // sandbox mode\n this.stockStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v2/sip';\n this.optionStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/options';\n } else if (mode === 'test') {\n // test mode, can only use ticker FAKEPACA\n this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/test';\n this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // there's no test mode for options\n } else {\n // production\n this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip';\n this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options';\n }\n }\n\n public getMode(): 'sandbox' | 'test' | 'production' {\n if (this.stockStreamUrl.includes('sandbox')) {\n return 'sandbox';\n } else if (this.stockStreamUrl.includes('test')) {\n return 'test';\n } else {\n return 'production';\n }\n }\n\n public setAutoReconnect(enabled: boolean): void {\n this.autoReconnect = enabled;\n log(`Auto-reconnect ${enabled ? 'enabled' : 'disabled'}`);\n }\n\n public getAutoReconnect(): boolean {\n return this.autoReconnect;\n }\n\n private constructor() {\n super();\n this.dataURL = 'https://data.alpaca.markets/v2';\n this.apiURL =\n process.env.ALPACA_ACCOUNT_TYPE === 'PAPER'\n ? 'https://paper-api.alpaca.markets/v2'\n : 'https://api.alpaca.markets/v2'; // used by some, e.g. getAssets\n this.v1beta1url = 'https://data.alpaca.markets/v1beta1'; // used for options endpoints\n this.v1beta3url = 'https://data.alpaca.markets/v1beta3'; // used for crypto endpoints\n this.setMode('production'); // sets stockStreamUrl and optionStreamUrl\n this.headers = {\n 'APCA-API-KEY-ID': process.env.ALPACA_API_KEY!,\n 'APCA-API-SECRET-KEY': process.env.ALPACA_SECRET_KEY!,\n 'Content-Type': 'application/json',\n };\n }\n\n public static getInstance(): AlpacaMarketDataAPI {\n if (!AlpacaMarketDataAPI.instance) {\n AlpacaMarketDataAPI.instance = new AlpacaMarketDataAPI();\n }\n return AlpacaMarketDataAPI.instance;\n }\n\n private getReconnectDelay(attempt: number): number {\n // 0: instant (0ms), 1: 5s, 2: 10s, 3: 15s, 4+: 60s\n const delays = [0, 5000, 10000, 15000, 60000];\n return attempt < delays.length ? delays[attempt] : 60000;\n }\n\n private scheduleReconnect(streamType: 'stock' | 'option'): void {\n if (!this.autoReconnect) {\n log(`Auto-reconnect disabled, not reconnecting ${streamType} stream`);\n return;\n }\n\n const attempts = streamType === 'stock' ? this.stockReconnectAttempts : this.optionReconnectAttempts;\n const delay = this.getReconnectDelay(attempts);\n \n log(`Scheduling ${streamType} stream reconnect (attempt ${attempts + 1}) in ${delay}ms`);\n\n const timeout = setTimeout(() => {\n log(`Attempting to reconnect ${streamType} stream (attempt ${attempts + 1})`);\n if (streamType === 'stock') {\n this.stockReconnectAttempts++;\n } else {\n this.optionReconnectAttempts++;\n }\n this.connect(streamType);\n }, delay);\n\n if (streamType === 'stock') {\n this.stockReconnectTimeout = timeout;\n } else {\n this.optionReconnectTimeout = timeout;\n }\n }\n\n // Type-safe event emitter methods\n public on<K extends StockStreamEventName>(event: K, listener: (data: StockStreamEventMap[K]) => void): this;\n public on<K extends OptionStreamEventName>(event: K, listener: (data: OptionStreamEventMap[K]) => void): this;\n public on(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.on(event, listener);\n }\n\n public emit<K extends StockStreamEventName>(event: K, data: StockStreamEventMap[K]): boolean;\n public emit<K extends OptionStreamEventName>(event: K, data: OptionStreamEventMap[K]): boolean;\n public emit(event: string | symbol, ...args: any[]): boolean {\n return super.emit(event, ...args);\n }\n\n private connect(streamType: 'stock' | 'option'): void {\n const url = streamType === 'stock' ? this.stockStreamUrl : this.optionStreamUrl;\n const ws = new WebSocket(url);\n if (streamType === 'stock') {\n this.stockWs = ws;\n } else {\n this.optionWs = ws;\n }\n\n ws.on('open', () => {\n log(`${streamType} stream connected`);\n // Reset reconnect attempts on successful connection\n if (streamType === 'stock') {\n this.stockReconnectAttempts = 0;\n if (this.stockReconnectTimeout) {\n clearTimeout(this.stockReconnectTimeout);\n this.stockReconnectTimeout = null;\n }\n } else {\n this.optionReconnectAttempts = 0;\n if (this.optionReconnectTimeout) {\n clearTimeout(this.optionReconnectTimeout);\n this.optionReconnectTimeout = null;\n }\n }\n const authMessage = {\n action: 'auth',\n key: process.env.ALPACA_API_KEY!,\n secret: process.env.ALPACA_SECRET_KEY!,\n };\n ws.send(JSON.stringify(authMessage));\n });\n\n ws.on('message', (data: WebSocket.Data) => {\n //log(`RAW MESSASGE: ${data.toString()}`);\n const messages = JSON.parse(data.toString());\n for (const message of messages) {\n if (message.T === 'success' && message.msg === 'authenticated') {\n log(`${streamType} stream authenticated`);\n this.sendSubscription(streamType);\n } else if (message.T === 'error') {\n log(`${streamType} stream error: ${message.msg}`, { type: 'error' });\n } else if (message.S) {\n super.emit(`${streamType}-${message.T}`, message);\n super.emit(`${streamType}-data`, message as AlpacaStockStreamMessage | AlpacaOptionStreamMessage);\n }\n }\n });\n\n ws.on('close', (code: number, reason: Buffer) => {\n const reasonStr = reason.toString() || 'No reason provided';\n const codeDesc = this.getCloseCodeDescription(code);\n log(`${streamType} stream disconnected - Code: ${code} (${codeDesc}), Reason: ${reasonStr}`, { type: 'warn' });\n \n if (streamType === 'stock') {\n this.stockWs = null;\n } else {\n this.optionWs = null;\n }\n \n this.scheduleReconnect(streamType);\n });\n\n ws.on('error', (error: Error) => {\n log(`${streamType} stream error: ${error.message}`, { type: 'error' });\n });\n }\n\n private getCloseCodeDescription(code: number): string {\n const codes: Record<number, string> = {\n 1000: 'Normal Closure',\n 1001: 'Going Away',\n 1002: 'Protocol Error',\n 1003: 'Unsupported Data',\n 1005: 'No Status Received',\n 1006: 'Abnormal Closure',\n 1007: 'Invalid Frame Payload Data',\n 1008: 'Policy Violation',\n 1009: 'Message Too Big',\n 1010: 'Mandatory Extension',\n 1011: 'Internal Server Error',\n 1012: 'Service Restart',\n 1013: 'Try Again Later',\n 1014: 'Bad Gateway',\n 1015: 'TLS Handshake',\n };\n return codes[code] || 'Unknown';\n }\n\n private sendSubscription(streamType: 'stock' | 'option'): void {\n const ws = streamType === 'stock' ? this.stockWs : this.optionWs;\n const subscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;\n if (ws && ws.readyState === WebSocket.OPEN) {\n const subMessagePayload: { trades?: string[]; quotes?: string[]; bars?: string[] } = {};\n\n if (subscriptions.trades.length > 0) {\n subMessagePayload.trades = subscriptions.trades;\n }\n if (subscriptions.quotes.length > 0) {\n subMessagePayload.quotes = subscriptions.quotes;\n }\n if (subscriptions.bars.length > 0) {\n subMessagePayload.bars = subscriptions.bars;\n }\n\n if (Object.keys(subMessagePayload).length > 0) {\n const subMessage = {\n action: 'subscribe',\n ...subMessagePayload,\n };\n ws.send(JSON.stringify(subMessage));\n }\n }\n }\n\n public connectStockStream(): void {\n if (!this.stockWs) {\n this.connect('stock');\n }\n }\n\n public connectOptionStream(): void {\n if (!this.optionWs) {\n this.connect('option');\n }\n }\n\n public disconnectStockStream(): void {\n if (this.stockReconnectTimeout) {\n clearTimeout(this.stockReconnectTimeout);\n this.stockReconnectTimeout = null;\n }\n this.stockReconnectAttempts = 0;\n if (this.stockWs) {\n this.stockWs.close();\n }\n }\n\n public disconnectOptionStream(): void {\n if (this.optionReconnectTimeout) {\n clearTimeout(this.optionReconnectTimeout);\n this.optionReconnectTimeout = null;\n }\n this.optionReconnectAttempts = 0;\n if (this.optionWs) {\n this.optionWs.close();\n }\n }\n\n public subscribe(\n streamType: 'stock' | 'option',\n subscriptions: { trades?: string[]; quotes?: string[]; bars?: string[] }\n ): void {\n const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;\n Object.entries(subscriptions).forEach(([key, value]) => {\n if (value) {\n currentSubscriptions[key] = [...new Set([...(currentSubscriptions[key] || []), ...value])];\n }\n });\n\n this.sendSubscription(streamType);\n }\n\n public unsubscribe(\n streamType: 'stock' | 'option',\n subscriptions: { trades?: string[]; quotes?: string[]; bars?: string[] }\n ): void {\n const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;\n Object.entries(subscriptions).forEach(([key, value]) => {\n if (value) {\n currentSubscriptions[key] = (currentSubscriptions[key] || []).filter((s) => !value.includes(s));\n }\n });\n const unsubMessage = {\n action: 'unsubscribe',\n ...subscriptions,\n };\n\n const ws = streamType === 'stock' ? this.stockWs : this.optionWs;\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(unsubMessage));\n }\n }\n\n private async makeRequest(\n endpoint: string,\n method: string = 'GET',\n params?: Record<string, any>,\n baseUrlName: 'data' | 'api' | 'v1beta1' | 'v1beta3' = 'data'\n ): Promise<any> {\n const baseUrl = baseUrlName === 'data' ? this.dataURL : \n baseUrlName === 'api' ? this.apiURL : \n baseUrlName === 'v1beta1' ? this.v1beta1url : this.v1beta3url;\n const url = new URL(`${baseUrl}${endpoint}`);\n\n try {\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n url.searchParams.append(key, value.join(','));\n } else if (value !== undefined) {\n url.searchParams.append(key, value.toString());\n }\n });\n }\n\n const response = await fetch(url.toString(), {\n method,\n headers: this.headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n log(`Market Data API error (${response.status}): ${errorText}`, { type: 'error' });\n throw new Error(`Market Data API error (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n return data;\n } catch (err) {\n const error = err as Error;\n log(`Error in makeRequest: ${error.message}. Endpoint: ${endpoint}. Url: ${url.toString()}`, { type: 'error' });\n if (error instanceof TypeError) {\n log(`Network error details: ${error.stack}`, { type: 'error' });\n }\n throw error;\n }\n }\n\n /**\n * Get historical OHLCV bars for specified symbols, including pre-market and post-market data\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for historical bars request\n * @returns Historical bars data with all pages combined\n */\n async getHistoricalBars(params: HistoricalBarsParams): Promise<HistoricalBarsResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allBars: { [symbol: string]: Bar[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalBarsCount = 0;\n let pageCount = 0;\n let currency = '';\n\n // Initialize bar arrays for each symbol\n symbols.forEach((symbol) => {\n allBars[symbol] = [];\n });\n\n log(\n `Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr }\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n adjustment: params.adjustment ?? DEFAULT_ADJUSTMENT,\n feed: DEFAULT_FEED,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: HistoricalBarsResponse = await this.makeRequest('/stocks/bars', 'GET', requestParams);\n\n if (!response.bars) {\n log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });\n break;\n }\n\n // Track currency from first response\n if (!currency) {\n currency = response.currency;\n }\n\n // Combine bars for each symbol\n let pageBarsCount = 0;\n let earliestTimestamp: Date | null = null;\n let latestTimestamp: Date | null = null;\n\n Object.entries(response.bars).forEach(([symbol, bars]) => {\n if (bars && bars.length > 0) {\n allBars[symbol] = [...allBars[symbol], ...bars];\n pageBarsCount += bars.length;\n\n // Track date range for this page\n bars.forEach((bar) => {\n const barDate = new Date(bar.t);\n if (!earliestTimestamp || barDate < earliestTimestamp) {\n earliestTimestamp = barDate;\n }\n if (!latestTimestamp || barDate > latestTimestamp) {\n latestTimestamp = barDate;\n }\n });\n }\n });\n\n totalBarsCount += pageBarsCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n // Enhanced logging with date range and progress info\n const dateRangeStr =\n earliestTimestamp && latestTimestamp\n ? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(\n latestTimestamp\n ).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`\n : 'unknown range';\n\n log(\n `Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${\n symbols.length\n } symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {symbol: symbolsStr, type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n // Final summary\n const symbolCounts = Object.entries(allBars)\n .map(([symbol, bars]) => `${symbol}: ${bars.length}`)\n .join(', ');\n log(\n `${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length\n } symbols (${symbolCounts})`, { symbol: symbolsStr }\n );\n\n return {\n bars: allBars,\n next_page_token: null, // Always null since we fetch all pages\n currency: currency || DEFAULT_CURRENCY,\n };\n }\n\n /**\n * Get the most recent minute bar for requested symbols\n * @param symbols Array of stock symbols to query\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest bar data for each symbol\n \n */\n async getLatestBars(symbols: string[], currency?: string): Promise<LatestBarsResponse> {\n return this.makeRequest('/stocks/bars/latest', 'GET', {\n symbols,\n feed: DEFAULT_FEED,\n currency: currency || DEFAULT_CURRENCY,\n });\n }\n\n /**\n * Get the last trade for a single symbol\n * @param symbol The stock symbol to query\n * @returns Last trade details including price, size, exchange, and conditions\n */\n async getLastTrade(symbol: string): Promise<LastTradeResponse> {\n return this.makeRequest(`/v1/last/stocks/${symbol}`, 'GET');\n }\n\n /**\n * Get the most recent trades for requested symbols\n * @param symbols Array of stock symbols to query\n * @param feed Optional data source (sip/iex/delayed_sip)\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest trade data for each symbol\n \n */\n async getLatestTrades(symbols: string[], feed?: DataFeed, currency?: string): Promise<LatestTradesResponse> {\n return this.makeRequest('/stocks/trades/latest', 'GET', {\n symbols,\n feed: feed || DEFAULT_FEED,\n currency: currency || DEFAULT_CURRENCY,\n });\n }\n\n /**\n * Get the most recent quotes for requested symbols\n * @param symbols Array of stock symbols to query\n * @param feed Optional data source (sip/iex/delayed_sip)\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest quote data for each symbol\n */\n async getLatestQuotes(symbols: string[], feed?: DataFeed, currency?: string): Promise<LatestQuotesResponse> {\n // Return empty response if symbols array is empty to avoid API error\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getLatestQuotes, returning empty response', { type: 'warn' });\n return {\n quotes: {},\n currency: currency || DEFAULT_CURRENCY,\n };\n }\n\n return this.makeRequest('/stocks/quotes/latest', 'GET', {\n symbols,\n feed: feed || DEFAULT_FEED,\n currency: currency || DEFAULT_CURRENCY,\n });\n }\n\n /**\n * Get the latest quote for a single symbol\n * @param symbol The stock symbol to query\n * @param feed Optional data source (sip/iex/delayed_sip)\n * @param currency Optional currency in ISO 4217 format\n * @returns Latest quote data with symbol and currency information\n */\n async getLatestQuote(\n symbol: string,\n feed?: DataFeed,\n currency?: string\n ): Promise<{ quote: AlpacaQuote; symbol: string; currency: string }> {\n return this.makeRequest(`/stocks/${symbol}/quotes/latest`, 'GET', {\n feed: feed || DEFAULT_FEED,\n currency,\n });\n }\n\n /**\n * Get the previous day's closing price for a symbol\n * @param symbol The stock symbol to query\n * @param referenceDate Optional reference date to get the previous close for\n * @returns Previous day's closing price data\n */\n async getPreviousClose(symbol: string, referenceDate?: Date): Promise<Bar | null> {\n const date = referenceDate || new Date();\n const prevMarketDate = getLastFullTradingDate(date);\n\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '1Day',\n start: prevMarketDate.toISOString(),\n end: prevMarketDate.toISOString(),\n limit: 1,\n });\n\n if (!response.bars[symbol] || response.bars[symbol].length === 0) {\n log(`No previous close data available for ${symbol}`, { type: 'error', symbol });\n return null;\n }\n\n return response.bars[symbol][0];\n }\n\n /**\n * Get hourly price data for a symbol\n * @param symbol The stock symbol to query\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of hourly price bars\n */\n async getHourlyPrices(symbol: string, start: number, end: number): Promise<Bar[]> {\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '1Hour',\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n limit: 96, // Last 96 hours (4 days)\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Get half-hourly price data for a symbol\n * @param symbol The stock symbol to query\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of half-hourly price bars\n */\n async getHalfHourlyPrices(symbol: string, start: number, end: number): Promise<Bar[]> {\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '30Min',\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n limit: 16 * 2 * 4, // last 4 days, 16 hours per day, 2 bars per hour\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Get daily price data for a symbol\n * @param symbol The stock symbol to query\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of daily price bars\n */\n async getDailyPrices(symbol: string, start: number, end: number): Promise<Bar[]> {\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe: '1Day',\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n limit: 100, // Last 100 days\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Get intraday price data for a symbol\n * @param symbol The stock symbol to query\n * @param minutePeriod Minutes per bar (1, 5, 15, etc.)\n * @param start Start time in milliseconds\n * @param end End time in milliseconds\n * @returns Array of intraday price bars\n */\n async getIntradayPrices(symbol: string, minutePeriod: number, start: number, end: number): Promise<Bar[]> {\n const timeframe = `${minutePeriod}Min` as TimeFrame;\n const response = await this.getHistoricalBars({\n symbols: [symbol],\n timeframe,\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n });\n\n return response.bars[symbol] || [];\n }\n\n /**\n * Analyzes an array of price bars and returns a summary string\n * @param bars Array of price bars to analyze\n * @returns A string summarizing the price data\n */\n static analyzeBars(bars: Bar[]): string {\n if (!bars || bars.length === 0) {\n return 'No price data available';\n }\n\n const firstBar = bars[0];\n const lastBar = bars[bars.length - 1];\n const priceChange = lastBar.c - firstBar.o;\n const percentChange = (priceChange / firstBar.o) * 100;\n\n const volumeChange = lastBar.v - firstBar.v;\n const percentVolumeChange = (volumeChange / firstBar.v) * 100;\n\n const high = Math.max(...bars.map((bar) => bar.h));\n const low = Math.min(...bars.map((bar) => bar.l));\n const totalVolume = bars.reduce((sum, bar) => sum + bar.v, 0);\n const avgVolume = totalVolume / bars.length;\n\n return (\n `Price: $${firstBar.o.toFixed(2)} -> $${lastBar.c.toFixed(2)} (${percentChange.toFixed(2)}%), ` +\n `Volume: ${firstBar.v.toLocaleString()} -> ${lastBar.v.toLocaleString()} (${percentVolumeChange.toFixed(2)}%), ` +\n `High: $${high.toFixed(2)}, Low: $${low.toFixed(2)}, ` +\n `Avg Volume: ${avgVolume.toLocaleString()}`\n );\n }\n\n /**\n * Get assets available for trade and data consumption from Alpaca\n * @param params Optional query params\n * - status: 'active' | 'inactive' (default 'active')\n * - asset_class: 'us_equity' | 'us_option' | 'crypto' (default 'us_equity')\n * - shortable: if true (default), filters to assets with shortable=true and easy_to_borrow=true\n * @returns Array of AlpacaAsset objects\n * @see https://docs.alpaca.markets/reference/get-v2-assets-1\n */\n async getAssets(params?: GetAssetsParams): Promise<AlpacaAsset[]> {\n // Endpoint: GET /v2/assets\n const {\n status = 'active',\n asset_class = 'us_equity',\n shortable = true,\n }: { status: 'active' | 'inactive'; asset_class: AssetClass; shortable: boolean } = {\n status: params?.status ?? 'active',\n asset_class: params?.asset_class ?? 'us_equity',\n shortable: params?.shortable ?? true,\n };\n\n const assets: AlpacaAsset[] = await this.makeRequest(\n '/assets',\n 'GET',\n { status, asset_class },\n 'api'\n );\n\n if (!shortable) return assets;\n return assets.filter((a) => a.shortable === true && a.easy_to_borrow === true);\n }\n\n /**\n * Get a single asset by symbol or asset_id\n * @param symbolOrAssetId Symbol or asset_id\n * @returns AlpacaAsset object\n * @see https://docs.alpaca.markets/reference/get-v2-assets-symbol_or_asset_id\n */\n async getAsset(symbolOrAssetId: string): Promise<AlpacaAsset> {\n // Endpoint: GET /v2/assets/{symbol_or_asset_id}\n return this.makeRequest(`/assets/${encodeURIComponent(symbolOrAssetId)}`, 'GET', undefined, 'api');\n }\n\n // ===== OPTIONS MARKET DATA METHODS =====\n\n /**\n * Get options chain for an underlying symbol\n * Provides the latest trade, latest quote, and greeks for each contract symbol of the underlying symbol\n * @param params Options chain request parameters\n * @returns Options chain data with snapshots for each contract\n * @see https://docs.alpaca.markets/reference/optionchain\n */\n async getOptionsChain(params: OptionsChainParams): Promise<OptionsChainResponse> {\n const { underlying_symbol, ...queryParams } = params;\n return this.makeRequest(\n `/options/snapshots/${encodeURIComponent(underlying_symbol)}`,\n 'GET',\n queryParams,\n 'v1beta1'\n );\n }\n\n /**\n * Get the most recent trades for requested option contract symbols\n * @param params Latest options trades request parameters\n * @returns Latest trade data for each option contract symbol\n \n * @see https://docs.alpaca.markets/reference/optionlatesttrades\n */\n async getLatestOptionsTrades(params: LatestOptionsTradesParams): Promise<LatestOptionsTradesResponse> {\n // Remove limit and page_token as they're not supported by this endpoint\n const { limit, page_token, ...requestParams } = params;\n return this.makeRequest('/options/trades/latest', 'GET', requestParams, 'v1beta1');\n }\n\n /**\n * Get the most recent quotes for requested option contract symbols\n * @param params Latest options quotes request parameters\n * @returns Latest quote data for each option contract symbol\n \n * @see https://docs.alpaca.markets/reference/optionlatestquotes\n */\n async getLatestOptionsQuotes(params: LatestOptionsQuotesParams): Promise<LatestOptionsQuotesResponse> {\n // Remove limit and page_token as they're not supported by this endpoint\n const { limit, page_token, ...requestParams } = params;\n return this.makeRequest('/options/quotes/latest', 'GET', requestParams, 'v1beta1');\n }\n\n /**\n * Get historical OHLCV bars for option contract symbols\n * Automatically handles pagination to fetch all available data\n * @param params Historical options bars request parameters\n * @returns Historical bar data for each option contract symbol with all pages combined\n \n * @see https://docs.alpaca.markets/reference/optionbars\n */\n async getHistoricalOptionsBars(params: HistoricalOptionsBarsParams): Promise<HistoricalOptionsBarsResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allBars: { [symbol: string]: OptionBar[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalBarsCount = 0;\n let pageCount = 0;\n\n // Initialize bar arrays for each symbol\n symbols.forEach((symbol) => {\n allBars[symbol] = [];\n });\n\n log(\n `Starting historical options bars fetch for ${symbols.length} symbols (${params.timeframe}, ${\n params.start || 'no start'\n } to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: HistoricalOptionsBarsResponse = await this.makeRequest(\n '/options/bars',\n 'GET',\n requestParams,\n 'v1beta1'\n );\n\n if (!response.bars) {\n log(`No options bars data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine bars for each symbol\n let pageBarsCount = 0;\n let earliestTimestamp: Date | null = null;\n let latestTimestamp: Date | null = null;\n\n Object.entries(response.bars).forEach(([symbol, bars]) => {\n if (bars && bars.length > 0) {\n allBars[symbol] = [...allBars[symbol], ...bars];\n pageBarsCount += bars.length;\n\n // Track date range for this page\n bars.forEach((bar) => {\n const barDate = new Date(bar.t);\n if (!earliestTimestamp || barDate < earliestTimestamp) {\n earliestTimestamp = barDate;\n }\n if (!latestTimestamp || barDate > latestTimestamp) {\n latestTimestamp = barDate;\n }\n });\n }\n });\n\n totalBarsCount += pageBarsCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n // Enhanced logging with date range and progress info\n const dateRangeStr =\n earliestTimestamp && latestTimestamp\n ? `${(earliestTimestamp as Date).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${(\n latestTimestamp as Date\n ).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`\n : 'unknown range';\n\n log(\n `Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} option bars (total: ${totalBarsCount.toLocaleString()}) for ${\n symbols.length\n } symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`,\n {\n type: 'debug',\n }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping options bars pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n // Final summary\n const symbolCounts = Object.entries(allBars)\n .map(([symbol, bars]) => `${symbol}: ${bars.length}`)\n .join(', ');\n log(\n `Options bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages (${symbolCounts})`\n );\n\n return {\n bars: allBars,\n next_page_token: undefined, // Always undefined since we fetch all pages\n };\n }\n\n /**\n * Get historical trades for option contract symbols\n * Automatically handles pagination to fetch all available data\n * @param params Historical options trades request parameters\n * @returns Historical trade data for each option contract symbol with all pages combined\n \n * @see https://docs.alpaca.markets/reference/optiontrades\n */\n async getHistoricalOptionsTrades(params: HistoricalOptionsTradesParams): Promise<HistoricalOptionsTradesResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allTrades: { [symbol: string]: OptionTrade[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalTradesCount = 0;\n let pageCount = 0;\n\n // Initialize trades arrays for each symbol\n symbols.forEach((symbol) => {\n allTrades[symbol] = [];\n });\n\n log(\n `Starting historical options trades fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${\n params.end || 'no end'\n })`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: HistoricalOptionsTradesResponse = await this.makeRequest(\n '/options/trades',\n 'GET',\n requestParams,\n 'v1beta1'\n );\n\n if (!response.trades) {\n log(`No options trades data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine trades for each symbol\n let pageTradesCount = 0;\n let earliestTimestamp: Date | null = null;\n let latestTimestamp: Date | null = null;\n\n Object.entries(response.trades).forEach(([symbol, trades]) => {\n if (trades && trades.length > 0) {\n allTrades[symbol] = [...allTrades[symbol], ...trades];\n pageTradesCount += trades.length;\n\n // Track date range for this page\n trades.forEach((trade) => {\n const tradeDate = new Date(trade.t);\n if (!earliestTimestamp || tradeDate < earliestTimestamp) {\n earliestTimestamp = tradeDate;\n }\n if (!latestTimestamp || tradeDate > latestTimestamp) {\n latestTimestamp = tradeDate;\n }\n });\n }\n });\n\n totalTradesCount += pageTradesCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n // Enhanced logging with date range and progress info\n const dateRangeStr =\n earliestTimestamp && latestTimestamp\n ? `${(earliestTimestamp as Date).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${(\n latestTimestamp as Date\n ).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`\n : 'unknown range';\n\n log(\n `Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} option trades (total: ${totalTradesCount.toLocaleString()}) for ${\n symbols.length\n } symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`,\n {\n type: 'debug',\n }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping options trades pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n // Final summary\n const symbolCounts = Object.entries(allTrades)\n .map(([symbol, trades]) => `${symbol}: ${trades.length}`)\n .join(', ');\n log(\n `Options trades fetch complete: ${totalTradesCount.toLocaleString()} total trades across ${pageCount} pages (${symbolCounts})`\n );\n\n return {\n trades: allTrades,\n next_page_token: undefined, // Always undefined since we fetch all pages\n };\n }\n\n /**\n * Get snapshots for option contract symbols\n * Provides latest trade, latest quote, and greeks for each contract symbol\n * @param params Options snapshots request parameters\n * @returns Snapshot data for each option contract symbol\n \n * @see https://docs.alpaca.markets/reference/optionsnapshots\n */\n async getOptionsSnapshot(params: OptionsSnapshotsParams): Promise<OptionsSnapshotsResponse> {\n // Remove limit and page_token as they may not be supported by this endpoint\n const { limit, page_token, ...requestParams } = params;\n return this.makeRequest('/options/snapshots', 'GET', requestParams, 'v1beta1');\n }\n\n /**\n * Get condition codes for options trades or quotes\n * Returns the mapping between condition codes and their descriptions\n * @param tickType The type of tick data ('trade' or 'quote')\n * @returns Mapping of condition codes to descriptions\n \n * @see https://docs.alpaca.markets/reference/optionmetaconditions\n */\n async getOptionsConditionCodes(tickType: OptionTickType): Promise<OptionsConditionCodesResponse> {\n return this.makeRequest(`/options/meta/conditions/${tickType}`, 'GET', undefined, 'v1beta1');\n }\n\n /**\n * Get exchange codes for options\n * Returns the mapping between option exchange codes and exchange names\n * @returns Mapping of exchange codes to exchange names\n \n * @see https://docs.alpaca.markets/reference/optionmetaexchanges\n */\n async getOptionsExchangeCodes(): Promise<OptionsExchangeCodesResponse> {\n return this.makeRequest('/options/meta/exchanges', 'GET', undefined, 'v1beta1');\n }\n\n /**\n * Analyzes an array of option bars and returns a summary string\n * @param bars Array of option bars to analyze\n * @returns A string summarizing the option price data\n */\n static analyzeOptionBars(bars: OptionBar[]): string {\n if (!bars || bars.length === 0) {\n return 'No option price data available';\n }\n\n const firstBar = bars[0];\n const lastBar = bars[bars.length - 1];\n const priceChange = lastBar.c - firstBar.o;\n const percentChange = (priceChange / firstBar.o) * 100;\n\n const volumeChange = lastBar.v - firstBar.v;\n const percentVolumeChange = firstBar.v > 0 ? (volumeChange / firstBar.v) * 100 : 0;\n\n const high = Math.max(...bars.map((bar) => bar.h));\n const low = Math.min(...bars.map((bar) => bar.l));\n const totalVolume = bars.reduce((sum, bar) => sum + bar.v, 0);\n const avgVolume = totalVolume / bars.length;\n\n return (\n `Option Price: $${firstBar.o.toFixed(2)} -> $${lastBar.c.toFixed(2)} (${percentChange.toFixed(2)}%), ` +\n `Volume: ${firstBar.v.toLocaleString()} -> ${lastBar.v.toLocaleString()} (${percentVolumeChange.toFixed(2)}%), ` +\n `High: $${high.toFixed(2)}, Low: $${low.toFixed(2)}, ` +\n `Avg Volume: ${avgVolume.toLocaleString()}`\n );\n }\n\n /**\n * Formats option greeks for display\n * @param greeks Option greeks object\n * @returns Formatted string with greek values\n */\n static formatOptionGreeks(greeks: any): string {\n if (!greeks) {\n return 'No greeks data available';\n }\n\n const parts: string[] = [];\n if (greeks.delta !== undefined) parts.push(`Delta: ${greeks.delta.toFixed(4)}`);\n if (greeks.gamma !== undefined) parts.push(`Gamma: ${greeks.gamma.toFixed(4)}`);\n if (greeks.theta !== undefined) parts.push(`Theta: ${greeks.theta.toFixed(4)}`);\n if (greeks.vega !== undefined) parts.push(`Vega: ${greeks.vega.toFixed(4)}`);\n if (greeks.rho !== undefined) parts.push(`Rho: ${greeks.rho.toFixed(4)}`);\n\n return parts.length > 0 ? parts.join(', ') : 'No greeks data available';\n }\n\n /**\n * Interprets condition codes using the provided condition codes mapping\n * @param conditionCodes Array of condition codes from trade or quote\n * @param conditionCodesMap Mapping of condition codes to descriptions\n * @returns Formatted string with condition descriptions\n */\n static interpretConditionCodes(conditionCodes: string[], conditionCodesMap: OptionsConditionCodesResponse): string {\n if (!conditionCodes || conditionCodes.length === 0) {\n return 'No conditions';\n }\n\n const descriptions = conditionCodes\n .map((code) => conditionCodesMap[code] || `Unknown (${code})`)\n .filter((desc) => desc !== undefined);\n\n return descriptions.length > 0 ? descriptions.join(', ') : 'No condition descriptions available';\n }\n\n /**\n * Gets the exchange name from exchange code using the provided exchange codes mapping\n * @param exchangeCode Exchange code from trade or quote\n * @param exchangeCodesMap Mapping of exchange codes to names\n * @returns Exchange name or formatted unknown exchange\n */\n static getExchangeName(exchangeCode: string, exchangeCodesMap: OptionsExchangeCodesResponse): string {\n return exchangeCodesMap[exchangeCode] || `Unknown Exchange (${exchangeCode})`;\n }\n\n /**\n * Fetches news articles from Alpaca API for a symbol, paginating through all results.\n * @param symbol The symbol to fetch news for (e.g., 'AAPL')\n * @param params Optional parameters: start, end, limit, sort, include_content\n * @returns Array of SimpleNews articles\n */\n async fetchNews(\n symbol: string,\n params?: {\n start?: Date | string;\n end?: Date | string;\n limit?: number;\n sort?: 'asc' | 'desc';\n include_content?: boolean;\n }\n ): Promise<SimpleNews[]> {\n const defaultParams = {\n start: new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: new Date(),\n limit: 10,\n sort: 'desc' as const,\n include_content: true,\n };\n const mergedParams = { ...defaultParams, ...params };\n let newsArticles: SimpleNews[] = [];\n let pageToken: string | null = null;\n let hasMorePages = true;\n let fetchedCount = 0;\n const maxLimit = mergedParams.limit;\n\n // Utility to clean content\n function cleanContent(content: string | undefined): string | undefined {\n if (!content) return undefined;\n // Remove excessive whitespace, newlines, and trim\n return content.replace(/\\s+/g, ' ').trim();\n }\n\n while (hasMorePages) {\n const queryParams: URLSearchParams = new URLSearchParams({\n ...(mergedParams.start && { start: new Date(mergedParams.start).toISOString() }),\n ...(mergedParams.end && { end: new Date(mergedParams.end).toISOString() }),\n ...(symbol && { symbols: symbol }),\n ...(mergedParams.limit && { limit: Math.min(50, maxLimit - fetchedCount).toString() }),\n ...(mergedParams.sort && { sort: mergedParams.sort }),\n ...(mergedParams.include_content !== undefined\n ? { include_content: mergedParams.include_content.toString() }\n : {}),\n ...(pageToken && { page_token: pageToken }),\n });\n const url: string = `${this.v1beta1url}/news?${queryParams}`;\n log(`Fetching news from: ${url}`, { type: 'debug', symbol });\n const response: Response = await fetch(url, {\n method: 'GET',\n headers: this.headers,\n });\n if (!response.ok) {\n const errorText = await response.text();\n log(`Alpaca news API error (${response.status}): ${errorText}`, { type: 'error', symbol });\n throw new Error(`Alpaca news API error (${response.status}): ${errorText}`);\n }\n const data: { news: AlpacaNewsArticle[]; next_page_token: string | null } = await response.json();\n if (!data.news || !Array.isArray(data.news)) {\n log(`No news data found in Alpaca response for ${symbol}`, { type: 'warn', symbol });\n break;\n }\n const transformedNews: SimpleNews[] = data.news.map((article: AlpacaNewsArticle) => ({\n symbols: article.symbols,\n title: article.headline,\n summary: cleanContent(article.summary) ?? '',\n content: article.content ? cleanContent(article.content) : undefined,\n url: article.url,\n source: article.source,\n author: article.author,\n date: article.updated_at || article.created_at,\n updatedDate: article.updated_at || article.created_at,\n sentiment: 0,\n }));\n newsArticles = newsArticles.concat(transformedNews);\n fetchedCount = newsArticles.length;\n pageToken = data.next_page_token || null;\n hasMorePages = !!pageToken && (!maxLimit || fetchedCount < maxLimit);\n log(\n `Fetched ${transformedNews.length} news articles (total: ${fetchedCount}) for ${symbol}. More pages: ${hasMorePages}`,\n { type: 'debug', symbol }\n );\n if (maxLimit && fetchedCount >= maxLimit) {\n newsArticles = newsArticles.slice(0, maxLimit);\n break;\n }\n }\n return newsArticles;\n }\n\n // ===== CRYPTO MARKET DATA METHODS =====\n\n /**\n * Get historical OHLCV bars for crypto symbols\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for crypto historical bars request\n * @returns Historical bars data with all pages combined\n */\n async getCryptoHistoricalBars(params: CryptoHistoricalBarsParams): Promise<CryptoHistoricalBarsResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allBars: { [symbol: string]: Bar[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalBarsCount = 0;\n let pageCount = 0;\n\n // Initialize bar arrays for each symbol\n symbols.forEach((symbol) => {\n allBars[symbol] = [];\n });\n\n log(\n `Starting crypto historical bars fetch for ${symbols.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n symbols: symbolsStr,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: CryptoHistoricalBarsResponse = await this.makeRequest(\n '/crypto/us/bars',\n 'GET',\n requestParams,\n 'v1beta3'\n );\n\n if (!response.bars) {\n log(`No crypto bars data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine bars for each symbol\n let pageBarsCount = 0;\n Object.entries(response.bars).forEach(([symbol, bars]) => {\n if (bars && bars.length > 0) {\n allBars[symbol] = [...allBars[symbol], ...bars];\n pageBarsCount += bars.length;\n }\n });\n\n totalBarsCount += pageBarsCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n log(\n `Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} crypto bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping crypto bars pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n log(\n `Crypto historical bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages`\n );\n\n return {\n bars: allBars,\n next_page_token: null, // Always null since we fetch all pages\n };\n }\n\n /**\n * Get the most recent minute bar for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest bar data for each symbol\n */\n async getCryptoLatestBars(symbols: string[]): Promise<CryptoLatestBarsResponse> {\n return this.makeRequest('/crypto/us/latest/bars', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get historical quotes for crypto symbols\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for crypto historical quotes request\n * @returns Historical quotes data with all pages combined\n */\n async getCryptoHistoricalQuotes(params: CryptoHistoricalQuotesParams): Promise<CryptoHistoricalQuotesResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allQuotes: { [symbol: string]: CryptoQuote[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalQuotesCount = 0;\n let pageCount = 0;\n\n // Initialize quotes arrays for each symbol\n symbols.forEach((symbol) => {\n allQuotes[symbol] = [];\n });\n\n log(\n `Starting crypto historical quotes fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n symbols: symbolsStr,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: CryptoHistoricalQuotesResponse = await this.makeRequest(\n '/crypto/us/quotes',\n 'GET',\n requestParams,\n 'v1beta3'\n );\n\n if (!response.quotes) {\n log(`No crypto quotes data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine quotes for each symbol\n let pageQuotesCount = 0;\n Object.entries(response.quotes).forEach(([symbol, quotes]) => {\n if (quotes && quotes.length > 0) {\n allQuotes[symbol] = [...allQuotes[symbol], ...quotes];\n pageQuotesCount += quotes.length;\n }\n });\n\n totalQuotesCount += pageQuotesCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n log(\n `Page ${pageCount}: Fetched ${pageQuotesCount.toLocaleString()} crypto quotes (total: ${totalQuotesCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping crypto quotes pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n log(\n `Crypto historical quotes fetch complete: ${totalQuotesCount.toLocaleString()} total quotes across ${pageCount} pages`\n );\n\n return {\n quotes: allQuotes,\n next_page_token: null, // Always null since we fetch all pages\n };\n }\n\n /**\n * Get the most recent quotes for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest quote data for each symbol\n */\n async getCryptoLatestQuotes(symbols: string[]): Promise<CryptoLatestQuotesResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoLatestQuotes, returning empty response', { type: 'warn' });\n return { quotes: {} };\n }\n\n return this.makeRequest('/crypto/us/latest/quotes', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get historical trades for crypto symbols\n * Automatically handles pagination to fetch all available data\n * @param params Parameters for crypto historical trades request\n * @returns Historical trades data with all pages combined\n */\n async getCryptoHistoricalTrades(params: CryptoHistoricalTradesParams): Promise<CryptoHistoricalTradesResponse> {\n const symbols = params.symbols;\n const symbolsStr = symbols.join(',');\n let allTrades: { [symbol: string]: CryptoTrade[] } = {};\n let pageToken: string | null = null;\n let hasMorePages = true;\n let totalTradesCount = 0;\n let pageCount = 0;\n\n // Initialize trades arrays for each symbol\n symbols.forEach((symbol) => {\n allTrades[symbol] = [];\n });\n\n log(\n `Starting crypto historical trades fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`\n );\n\n while (hasMorePages) {\n pageCount++;\n const requestParams = {\n ...params,\n symbols: symbolsStr,\n ...(pageToken && { page_token: pageToken }),\n };\n\n const response: CryptoHistoricalTradesResponse = await this.makeRequest(\n '/crypto/us/trades',\n 'GET',\n requestParams,\n 'v1beta3'\n );\n\n if (!response.trades) {\n log(`No crypto trades data found in response for ${symbols.length} symbols`, { type: 'warn' });\n break;\n }\n\n // Combine trades for each symbol\n let pageTradesCount = 0;\n Object.entries(response.trades).forEach(([symbol, trades]) => {\n if (trades && trades.length > 0) {\n allTrades[symbol] = [...allTrades[symbol], ...trades];\n pageTradesCount += trades.length;\n }\n });\n\n totalTradesCount += pageTradesCount;\n pageToken = response.next_page_token || null;\n hasMorePages = !!pageToken;\n\n log(\n `Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} crypto trades (total: ${totalTradesCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' }\n );\n\n // Prevent infinite loops\n if (pageCount > 1000) {\n log(`Stopping crypto trades pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });\n break;\n }\n }\n\n log(\n `Crypto historical trades fetch complete: ${totalTradesCount.toLocaleString()} total trades across ${pageCount} pages`\n );\n\n return {\n trades: allTrades,\n next_page_token: null, // Always null since we fetch all pages\n };\n }\n\n /**\n * Get the most recent trades for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest trade data for each symbol\n */\n async getCryptoLatestTrades(symbols: string[]): Promise<CryptoLatestTradesResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoLatestTrades, returning empty response', { type: 'warn' });\n return { trades: {} };\n }\n\n return this.makeRequest('/crypto/us/latest/trades', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get snapshots for crypto symbols\n * Returns the latest trade, latest quote, latest minute bar, latest daily bar, and previous daily bar data\n * @param symbols Array of crypto symbols to query\n * @returns Snapshot data for each symbol\n */\n async getCryptoSnapshots(symbols: string[]): Promise<CryptoSnapshotsResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoSnapshots, returning empty response', { type: 'warn' });\n return { snapshots: {} };\n }\n\n return this.makeRequest('/crypto/us/snapshots', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Get the latest orderbook for requested crypto symbols\n * @param symbols Array of crypto symbols to query\n * @returns Latest orderbook data for each symbol\n */\n async getCryptoLatestOrderbooks(symbols: string[]): Promise<CryptoLatestOrderbooksResponse> {\n if (!symbols || symbols.length === 0) {\n log('No symbols provided to getCryptoLatestOrderbooks, returning empty response', { type: 'warn' });\n return { orderbooks: {} };\n }\n\n return this.makeRequest('/crypto/us/latest/orderbooks', 'GET', { symbols: symbols.join(',') }, 'v1beta3');\n }\n\n /**\n * Analyzes an array of crypto bars and returns a summary string\n * @param bars Array of crypto bars to analyze\n * @returns A string summarizing the crypto price data\n */\n static analyzeCryptoBars(bars: Bar[]): string {\n if (!bars || bars.length === 0) {\n return 'No crypto price data available';\n }\n\n const firstBar = bars[0];\n const lastBar = bars[bars.length - 1];\n const priceChange = lastBar.c - firstBar.o;\n const percentChange = (priceChange / firstBar.o) * 100;\n\n const volumeChange = lastBar.v - firstBar.v;\n const percentVolumeChange = firstBar.v > 0 ? (volumeChange / firstBar.v) * 100 : 0;\n\n const high = Math.max(...bars.map((bar) => bar.h));\n const low = Math.min(...bars.map((bar) => bar.l));\n const totalVolume = bars.reduce((sum, bar) => sum + bar.v, 0);\n const avgVolume = totalVolume / bars.length;\n\n return (\n `Crypto Price: $${firstBar.o.toFixed(6)} -> $${lastBar.c.toFixed(6)} (${percentChange.toFixed(2)}%), ` +\n `Volume: ${firstBar.v.toLocaleString()} -> ${lastBar.v.toLocaleString()} (${percentVolumeChange.toFixed(2)}%), ` +\n `High: $${high.toFixed(6)}, Low: $${low.toFixed(6)}, ` +\n `Avg Volume: ${avgVolume.toLocaleString()}`\n );\n }\n}\n\n// Export the singleton instance\nexport const marketDataAPI = AlpacaMarketDataAPI.getInstance();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["year", "month", "day", "closeHour", "closeMinute", "isMarketDay", "import_openai", "OpenAI", "OpenAI", "openai", "import_openai", "openai", "OpenAI", "import_openai", "openai", "OpenAI", "import_openai", "OpenAI", "usageModel", "formatNumber", "import_ws", "log", "WebSocket", "WebSocket"]
|
|
7
7
|
}
|