UNPKG

@yash101/schwab-api-client

Version:

A TypeScript client library for interacting with the Charles Schwab Brokerage APIs.

285 lines 12.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataApi = void 0; const assert_1 = __importDefault(require("assert")); const Assert_1 = require("./util/Assert"); const dataapi_types_1 = require("./api-types/dataapi.types"); const CONTENT_TYPE = 'Content-Type'; const APPLICATION_JSON = 'application/json'; const APPLICATION_FORM_URLENCODED = 'application/x-www-form-urlencoded'; const GET = 'GET'; class DataApi { tokens; apiOptions; async doApiFetch(path, method, { queryParams, body = null, headers = {}, } = {}) { (0, assert_1.default)(this.tokens.getAccessToken(), 'Access token is required'); (0, Assert_1.assert_warn)(this.apiOptions.getBaseUri(), 'Recommended to specify base URL'); const url = new URL(path, this.apiOptions.getBaseUri() || 'https://api.schwabapi.com'); const mimeType = headers[CONTENT_TYPE] || APPLICATION_JSON; queryParams?.forEach((value, key) => url.searchParams.append(key, value)); const options = { method, headers: { ...headers, Authorization: this.tokens.getAuthHeader(), Accept: APPLICATION_JSON, }, }; if (body) { if (typeof body !== 'string') { switch (mimeType) { case 'application/json': body = JSON.stringify(body); break; case 'application/x-www-form-urlencoded': body = new URLSearchParams(body).toString(); break; default: body = JSON.stringify(body); break; } } options.body = body; options.headers[CONTENT_TYPE] = mimeType; } try { return await fetch(url, options); } catch (e) { throw new Error(`Error fetching data: ${e.message}`); } } constructor(tokens, apiOptions) { this.tokens = tokens; this.apiOptions = apiOptions; } setTokens(tokens) { this.tokens = tokens; } setApiOptions(apiOptions) { this.apiOptions = apiOptions; } async getQuotes(request) { (0, assert_1.default)(request.symbols, 'Symbols are required'); (0, assert_1.default)(request.symbols.length > 0, 'At least one symbol is required'); const path = '/marketdata/v1/quotes'; const queryParams = new URLSearchParams({ symbols: request.symbols.join(','), indicative: request.indicative ? 'true' : 'false', }); if (request.fields) { queryParams.append('fields', request.fields.join(',')); } const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getSingleQuote(request) { (0, assert_1.default)(request.symbol, 'Symbols are required'); (0, assert_1.default)(request.symbol.length === 1, 'Only one symbol is allowed'); const path = `/marketdata/v1/${request.symbol}/quotes`; const queryParams = new URLSearchParams({ symbols: request.symbol, }); if (request.fields) { queryParams.append('fields', request.fields.join(',')); } const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getOptionChains(request) { (0, assert_1.default)(request.symbol, 'Symbol is required'); if (request.fromDate instanceof Date) { request.fromDate = request.fromDate.toISOString(); } if (request.toDate instanceof Date) { request.toDate = request.toDate.toISOString(); } const path = `/marketdata/v1/chains`; const queryParams = new URLSearchParams(); for (const [key, value] of Object.entries(request)) { if (value !== undefined && value !== null) { if (value instanceof Date) { queryParams.append(key, value.toISOString()); } else if (typeof value === 'boolean') { queryParams.append(key, value ? 'true' : 'false'); } else { queryParams.append(key, value.toString()); } } } const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getOptionExpirationChain(request) { (0, assert_1.default)(typeof request === 'string', 'Symbol is required'); (0, assert_1.default)(request.length > 0, 'Symbol is required'); const path = `/marketdata/v1/expirationchain`; const queryParams = new URLSearchParams({ symbol: request, }); const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getPriceHistory(request, validate = true) { // Validate the request (0, assert_1.default)(request.symbol, 'Symbol is required'); if (validate) { const validPeriods = { [dataapi_types_1.PeriodTypeEnum.DAY]: [1, 2, 3, 4, 5, 10], [dataapi_types_1.PeriodTypeEnum.MONTH]: [1, 2, 3, 6], [dataapi_types_1.PeriodTypeEnum.YEAR]: [1, 2, 3, 5, 10, 15, 20], [dataapi_types_1.PeriodTypeEnum.YTD]: [1], }; if (request.periodType && request.period) { (0, assert_1.default)(validPeriods[request.periodType], `Invalid period type: ${request.periodType}`); (0, assert_1.default)(validPeriods[request.periodType].includes(request.period), `Invalid period: ${request.period} for period type: ${request.periodType}`); } const validFrequencyTypes = { [dataapi_types_1.PeriodTypeEnum.DAY]: [dataapi_types_1.FrequencyTypeEnum.MINUTE], [dataapi_types_1.PeriodTypeEnum.MONTH]: [ dataapi_types_1.FrequencyTypeEnum.DAILY, dataapi_types_1.FrequencyTypeEnum.WEEKLY ], [dataapi_types_1.PeriodTypeEnum.YEAR]: [ dataapi_types_1.FrequencyTypeEnum.DAILY, dataapi_types_1.FrequencyTypeEnum.WEEKLY, dataapi_types_1.FrequencyTypeEnum.MONTHLY ], [dataapi_types_1.PeriodTypeEnum.YTD]: [dataapi_types_1.FrequencyTypeEnum.DAILY, dataapi_types_1.FrequencyTypeEnum.WEEKLY, dataapi_types_1.FrequencyTypeEnum.MONTHLY], }; if (request.frequencyType && request.frequency) { (0, assert_1.default)(validFrequencyTypes[request.periodType || dataapi_types_1.PeriodTypeEnum.DAY], `Invalid frequency type: ${request.frequencyType}`); (0, assert_1.default)(validFrequencyTypes[request.periodType || dataapi_types_1.PeriodTypeEnum.DAY] .includes(request.frequencyType), `Invalid frequency: ${request.frequency} for frequency type: ${request.frequencyType}`); } const validFrequencies = { [dataapi_types_1.FrequencyTypeEnum.MINUTE]: [1, 5, 10, 15, 30], [dataapi_types_1.FrequencyTypeEnum.DAILY]: [1], [dataapi_types_1.FrequencyTypeEnum.WEEKLY]: [1], [dataapi_types_1.FrequencyTypeEnum.MONTHLY]: [1], }; if (request.frequencyType && request.frequency) { (0, assert_1.default)(validFrequencies[request.frequencyType], `Invalid frequency: ${request.frequency} for frequency type: ${request.frequencyType}`); (0, assert_1.default)(validFrequencies[request.frequencyType].includes(request.frequency), `Invalid frequency: ${request.frequency} for frequency type: ${request.frequencyType}`); } } const path = `/marketdata/v1/pricehistory`; const queryParams = new URLSearchParams(); for (const [key, value] of Object.entries(request)) { if (value !== undefined && value !== null) { if (value instanceof Date) { queryParams.append(key, value.toISOString()); } else if (typeof value === 'boolean') { queryParams.append(key, value ? 'true' : 'false'); } else { queryParams.append(key, value.toString()); } } } const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getMoversForIndex(request) { (0, assert_1.default)(request.symbol_id, 'Symbol ID is required'); const path = `/marketdata/v1/movers`; const queryParams = new URLSearchParams(); for (const [key, value] of Object.entries(request)) { if (value !== undefined && value !== null) { if (value instanceof Date) { queryParams.append(key, value.toISOString()); } else if (typeof value === 'boolean') { queryParams.append(key, value ? 'true' : 'false'); } else { queryParams.append(key, value.toString()); } } } const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getMarketHours(request) { (0, assert_1.default)(request.markets, 'Market is required'); (0, assert_1.default)(request.markets.length > 0, 'At least one market is required'); const path = `/marketdata/v1/markets`; const queryParams = new URLSearchParams(); if (request.date instanceof Date) { queryParams.append('date', request.date.toISOString().split('T')[0]); } else if (typeof request.date === 'string') { queryParams.append('date', request.date); } const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getSingleMarketHours(request) { (0, assert_1.default)(request.market, 'Market is required'); const path = `/marketdata/v1/markets/${request.market}`; const queryParams = new URLSearchParams(); if (request.date instanceof Date) { queryParams.append('date', request.date.toISOString().split('T')[0]); } else if (typeof request.date === 'string') { queryParams.append('date', request.date); } const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getInstruments(request) { (0, assert_1.default)(request.symbol, 'Symbol is required'); (0, assert_1.default)(request.projection, 'Projection is required'); const path = `/marketdata/v1/instruments`; const queryParams = new URLSearchParams({ symbol: request.symbol, projection: request.projection, }); const response = await this.doApiFetch(path, GET, { queryParams }); const json = await response.json(); return (response.ok) ? json : json; } async getInstrumentByCUSIPId(request) { (0, assert_1.default)(request, 'CUSIP is required'); (0, assert_1.default)(typeof request === 'string', 'CUSIP is required'); const path = `/marketdata/v1/instruments/${request}`; const response = await this.doApiFetch(path, GET); const json = await response.json(); return (response.ok) ? json : json; } } exports.DataApi = DataApi; //# sourceMappingURL=data.api.js.map