import {z} from 'zod' export type GetApiV2AccountsAccountKeysBalancesArgs = {account_keys: Array}; export type GetApiV2AccountsAccountKeysBalancesOptions = {baseUrl?: string | undefined, OAuth2AuthCode?: string | undefined, fetch?: typeof fetch | undefined}; export const accountBalancesDefinition = z.array(z.object({Alias: z.string().optional(), "BODAccountBalance (Deprecated)": z.number().optional(), BODDayTradingMarginableEquitiesBuyingPower: z.number().optional(), BODEquity: z.number().optional(), BODNetCash: z.number().optional(), BODOpenTradeEquity: z.number().optional(), BODOptionBuyingPower: z.number().optional(), BODOptionValue: z.number().optional(), BODOvernightBuyingPower: z.number().optional(), CanDayTrade: z.boolean().optional(), ClosedPositions: z.array(z.object({Currency: z.string().optional(), Profit: z.number().optional(), Symbol: z.string().optional()})).optional(), Commission: z.number().optional(), DayTradeExcess: z.number().optional(), DayTradeOpenOrderMargin: z.number().optional(), DayTrades: z.number().optional(), DayTradingQualified: z.boolean().optional(), Currency: z.string().optional(), CurrencyDetails: z.array(z.object({AccountOpenOrderInitMargin: z.number().optional(), BODAccountCashBalance: z.number().optional(), BODAccountOpenTradeEquity: z.number().optional(), BODAccountSecurities: z.number().optional(), BODCashBalance: z.number().optional(), BODOpenTradeEquity: z.number().optional(), BODSecurities: z.number().optional(), Commission: z.number().optional(), Currency: z.string().optional(), OpenOrderInitMargin: z.number().optional(), RealTimeAccountCashBalance: z.number().optional(), RealTimeAccountInitMargin: z.number().optional(), RealTimeAccountMaintenanceMargin: z.number().optional(), RealTimeAccountMarginRequirement: z.number().optional(), RealTimeAccountRealizedProfitLoss: z.number().optional(), RealTimeAccountUnrealizedProfitLoss: z.number().optional(), RealTimeCashBalance: z.number().optional(), RealTimeInitMargin: z.number().optional(), RealTimeMaintenanceMargin: z.number().optional(), RealTimeRealizedProfitLoss: z.number().optional(), RealTimeUnrealizedProfitLoss: z.number().optional(), ToAccountConversionRate: z.number().optional(), TodayRealTimeUnrealizedProfitLoss: z.number().optional()})).optional(), DisplayName: z.string().optional(), Key: z.number().optional(), MarketValue: z.number().optional(), Name: z.string().optional(), OptionApprovalLevel: z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3), z.literal(4), z.literal(5)]).optional(), OpenOrderMargin: z.number().optional(), PatternDayTrader: z.boolean().optional(), RealTimeAccountBalance: z.number().optional(), RealTimeBuyingPower: z.number().optional(), RealTimeCostOfPositions: z.number().optional(), RealTimeDayTradeMargin: z.number().optional(), RealTimeDayTradingMarginableEquitiesBuyingPower: z.number().optional(), RealTimeEquity: z.number().optional(), RealTimeInitialMargin: z.number().optional(), RealTimeOptionBuyingPower: z.number().optional(), RealTimeOptionValue: z.number().optional(), RealTimeOvernightBuyingPower: z.number().optional(), RealTimeMaintenanceMargin: z.number().optional(), RealTimeRealizedProfitLoss: z.number().optional(), RealTimeTradeEquity: z.number().optional(), RealTimeUnrealizedGains: z.number().optional(), RealTimeUnrealizedProfitLoss: z.number().optional(), SecurityOnDeposit: z.number().optional(), Status: z.enum(["A", "X", "C", "F", "I", "L", "R", "D"]).optional(), StatusDescription: z.string().optional(), TodayRealTimeTradeEquity: z.number().optional(), Type: z.enum(["C", "M", "D", "F"]).optional(), TypeDescription: z.string().optional(), UnclearedDeposit: z.number().optional(), UnsettledFund: z.number().optional()})); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Get Account Balances * * * GET /v2/accounts/{account_keys}/balances * * Also accepts auth: OAuth2-Refresh-Token */ export const getApiV2AccountsAccountKeysBalances = async (args: GetApiV2AccountsAccountKeysBalancesArgs, options?: GetApiV2AccountsAccountKeysBalancesOptions) => { const {baseUrl = "https://api.tradestation.com", fetch: fetchFn = fetch, OAuth2AuthCode} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json; charset=utf-8") if (OAuth2AuthCode !== undefined) headers.set('authorization', `Bearer ${OAuth2AuthCode}`) const url = `${baseUrl.replace(/\/+$/, '')}/v2/accounts/${encodeURIComponent(String(args.account_keys))}/balances${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(accountBalancesDefinition, await res.json()) };