@sudowealth/schwab-api
Version:
TypeScript client for Charles Schwab API with OAuth support, market data, trading functionality, and complete type safety
205 lines (204 loc) • 8.18 kB
JavaScript
import { z } from 'zod';
import { BaseInstrumentSchema } from '../../schemas/base-instrument.schema.js';
import { mergeShapes } from '../../utils/schema-utils.js';
// Enum for projection parameter
export const InstrumentProjectionEnum = z.enum([
'symbol-search',
'symbol-regex',
'desc-search',
'desc-regex',
'search',
'fundamental',
]);
// Enum for AssetType specifically used in market-data/instruments
export const InstrumentAssetTypeEnum = z.enum([
'BOND',
'EQUITY',
'ETF',
'EXTENDED',
'FOREX',
'FUTURE',
'FUTURE_OPTION',
'FUNDAMENTAL',
'INDEX',
'INDICATOR',
'MUTUAL_FUND',
'OPTION',
'UNKNOWN',
]);
// Market-data specific InstrumentInfo Schema that extends the base schema
const InstrumentInfoSchema = BaseInstrumentSchema.pick({
symbol: true,
description: true,
cusip: true,
exchange: true,
}).extend({
assetType: InstrumentAssetTypeEnum,
});
// Schema for Fundamental Data
const FundamentalDataSchema = z.object({
symbol: z.string(),
high52: z.number().optional(),
low52: z.number().optional(),
dividendAmount: z.number().optional(),
dividendYield: z.number().optional(),
dividendDate: z.string().optional(),
peRatio: z.number().optional(),
pegRatio: z.number().optional(),
pbRatio: z.number().optional(),
pcRatio: z.number().optional(),
prRatio: z.number().optional(),
marketCap: z.number().optional(),
mark: z.number().optional(),
netChange: z.number().optional(),
volatility: z.number().optional(),
beta: z.number().optional(),
bidPrice: z.number().optional(),
askPrice: z.number().optional(),
lastPrice: z.number().optional(),
openPrice: z.number().optional(),
closePrice: z.number().optional(),
netPercentChangeInDouble: z.number().optional(),
netChangeInDouble: z.number().optional(),
bidSize: z.number().int().optional(),
askSize: z.number().int().optional(),
highPrice: z.number().optional(),
lowPrice: z.number().optional(),
lastSize: z.number().int().optional(),
quoteTimeInLong: z.number().int().optional(),
tradeTimeInLong: z.number().int().optional(),
lastTradeTime: z.string().datetime({ offset: true }).optional(),
grossMarginTTM: z.number().optional(),
grossMarginMRQ: z.number().optional(),
netProfitMarginTTM: z.number().optional(),
netProfitMarginMRQ: z.number().optional(),
operatingMarginTTM: z.number().optional(),
operatingMarginMRQ: z.number().optional(),
revenuePerShareTTM: z.number().optional(),
revenueTTM: z.number().optional(),
roa: z.number().optional(),
roe: z.number().optional(),
roi: z.number().optional(),
epsTTM: z.number().optional(),
epsChangePercentTTM: z.number().optional(),
epsChangeYear: z.number().optional(),
epsChangePercentYear: z.number().optional(),
revChangeYear: z.number().optional(),
revChangeTTM: z.number().optional(),
revChangeIn: z.number().optional(),
sharesOutstanding: z.number().optional(),
marketCapFloat: z.number().optional(),
bookValuePerShare: z.number().optional(),
shortIntToFloat: z.number().optional(),
shortIntDayToCover: z.number().optional(),
dividendPayAmount: z.number().optional(),
dividendGrowthRate3Year: z.number().optional(),
dividendPayDate: z.string().optional(),
betaText: z.string().optional(),
avg10DaysVolume: z.number().int().optional(),
avg1DayVolume: z.number().int().optional(),
avg3MonthVolume: z.number().int().optional(),
avg1YearVolume: z.number().int().optional(),
vol1DayAvg: z.number().int().optional(),
vol10DayAvg: z.number().int().optional(),
vol3MonthAvg: z.number().int().optional(),
week52HighDate: z.string().optional(),
week52LowDate: z.string().optional(),
divYield: z.number().optional(),
divAmount: z.number().optional(),
divFreq: z.number().int().optional(),
divExDate: z.string().optional(),
corpActionDate: z.string().optional(),
lastTradingDay: z.string().optional(),
nextEarningDate: z.string().optional(),
nextDividendPayDate: z.string().optional(),
nextDividendDate: z.string().optional(),
lastDividendDate: z.string().optional(),
fundStrategy: z.string().optional(),
fundFamily: z.string().optional(),
fundLeverage: z.string().optional(),
fundType: z.string().optional(),
});
// Specific Instrument Types
const FundamentalInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.FUNDAMENTAL),
fundamental: FundamentalDataSchema,
});
const BondInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.BOND),
bondFactor: z.string().optional(),
bondMultiplier: z.string().optional(),
bondPrice: z.number().optional(),
});
const EquityInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.EQUITY),
});
const ETFInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.ETF),
});
const ForexInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.FOREX),
});
const FutureInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.FUTURE),
});
const FutureOptionInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.FUTURE_OPTION),
});
const IndexInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.INDEX),
});
const IndicatorInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.INDICATOR),
});
const MutualFundInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.MUTUAL_FUND),
});
const OptionInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.OPTION),
});
const UnknownInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.UNKNOWN),
});
const ExtendedInstrumentSchema = InstrumentInfoSchema.extend({
assetType: z.literal(InstrumentAssetTypeEnum.Enum.EXTENDED),
});
// Discriminated Union for any Instrument type
const InstrumentSchema = z.discriminatedUnion('assetType', [
FundamentalInstrumentSchema,
BondInstrumentSchema,
EquityInstrumentSchema,
ETFInstrumentSchema,
ForexInstrumentSchema,
FutureInstrumentSchema,
FutureOptionInstrumentSchema,
IndexInstrumentSchema,
IndicatorInstrumentSchema,
MutualFundInstrumentSchema,
OptionInstrumentSchema,
UnknownInstrumentSchema,
ExtendedInstrumentSchema,
]);
// Path Parameters Schema for GET /instruments (no path params)
export const GetInstrumentsPathParams = z.object({});
// Query Parameters Schema for GET /instruments
export const GetInstrumentsQueryParams = z.object({
symbol: z.string().describe('Symbol of a security'),
projection: InstrumentProjectionEnum.describe(`Search by: ${InstrumentProjectionEnum.options.join(', ')}`),
});
// Request Params Schema for GET /instruments (merged path + query params)
export const GetInstrumentsParams = z.object(mergeShapes(GetInstrumentsQueryParams.shape, GetInstrumentsPathParams.shape));
// Response Schema for /instruments
export const GetInstrumentsResponse = z.object({
instruments: z.array(InstrumentSchema),
});
// Path Parameters Schema for GET /instruments/{cusip_id}
export const GetInstrumentByCusipPathParams = z.object({
cusip_id: z.string().describe('CUSIP of a security'),
});
// Query Parameters Schema for GET /instruments/{cusip_id} (no query params)
export const GetInstrumentByCusipQueryParams = z.object({});
// Request Params Schema for GET /instruments/{cusip_id} (merged path + query params)
export const GetInstrumentByCusipParams = z.object(mergeShapes(GetInstrumentByCusipQueryParams.shape, GetInstrumentByCusipPathParams.shape));
// Response Body Schema for /instruments/{cusip_id}
export const GetInstrumentByCusipResponse = GetInstrumentsResponse;