diff --git a/README.md b/README.md index a7a2941..58e20aa 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,29 @@ You can also search for tickers of particular dataset const tickers = await client.getTickerList("tesla", "job_listings"); ``` +### Stock price API + +You can get stock price for specific ticker. + +```js +const priceData = await client.getStockPrice("nasdaq:aapl"); +``` + +You can also get price for crypto coins. + +```js +const priceData = await client.getStockPrice("blockchain:eos"); +``` + +You can specify history range. + +```js +const priceData = await client.getStockPrice("nasdaq:aapl", { + startDate: "2021-11-01", + endDate: "2021-12-31", +}); +``` + ### Query Initialize `Query` with client object or API credentials. diff --git a/package.json b/package.json index b682ef3..e7f5201 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@thinknum/client-js", - "version": "0.1.0", + "version": "0.1.1", "description": "An API client for Thinknum Alternative Data written in Typescript", "main": "dist/index.js", "module": "dist/index.m.js", diff --git a/src/client.ts b/src/client.ts index 59b73ae..8c2ff73 100644 --- a/src/client.ts +++ b/src/client.ts @@ -4,9 +4,11 @@ import {version} from "../package.json"; import { IDatasetListResponse, IDatasetMetadataResponse, + IStockOverlayFetchResponse, ITickersResponse, } from "./dataTypes/response"; import {Paths} from "./paths"; +import {validateRangeDateFormat} from "./utils"; export interface IClientCredentials { clientId: string; @@ -151,4 +153,47 @@ export class Client { return data.queries[searchQuery]; }); } + + /* Stock API + -------------------------------------------------------------------------*/ + + public async getStockPrice(ticker: string, range?: {startDate: string; endDate: string}) { + if (!ticker || ticker.trim().length === 0) { + return Promise.reject(new Error("Missing or invalid ticker")); + } + + if (range) { + const hasStartDate = range.startDate && range.startDate.length > 0; + const hasEndDate = range.endDate && range.endDate.length > 0; + + if (!hasStartDate || !hasEndDate) { + return Promise.reject( + new Error("Both startDate and endDate are required when specifying range."), + ); + } + + if (!validateRangeDateFormat(range.startDate)) { + return Promise.reject(new Error("Invalid startDate format. Please use YYYY-MM-DD format.")); + } + + if (!validateRangeDateFormat(range.endDate)) { + return Promise.reject(new Error("Invalid endDate format. Please use YYYY-MM-DD format.")); + } + } + + const data: {start_date?: string; end_date?: string} = {}; + if (range?.startDate) { + data.start_date = range.startDate; + } + if (range?.endDate) { + data.end_date = range.endDate; + } + + return this.requestData(Paths.stock(ticker.trim()), { + method: "POST", + body: JSON.stringify(data), + }).then((data) => { + return data.results; + }); + } } diff --git a/src/dataTypes/response.ts b/src/dataTypes/response.ts index e1ba1f5..faaab9e 100644 --- a/src/dataTypes/response.ts +++ b/src/dataTypes/response.ts @@ -3,6 +3,7 @@ import {IQuerySort, QueryFormat} from "./common"; import {ICompanyWithEntities} from "./datasetCompaniesEntities"; import {QueryOption, QueryRow} from "./datasetQueries"; import {DatasetField, IDatasetPreset, IFunctionsMetadata} from "./datasets"; +import {IStockOverlayData} from "./stock"; export interface IDatasetListResponse { datasets: IDataset[]; @@ -63,3 +64,8 @@ export interface ITableFetchQueryResponse extends IFetchQueryResponse { group_fields: DatasetField[]; sort_fields: IQuerySort[]; } + +export interface IStockOverlayFetchResponse { + count: number; + results: IStockOverlayData; +} diff --git a/src/dataTypes/stock.ts b/src/dataTypes/stock.ts new file mode 100644 index 0000000..b9bb1a1 --- /dev/null +++ b/src/dataTypes/stock.ts @@ -0,0 +1,6 @@ +export interface IStockOverlayDataChunk { + date: string; + price: number; +} + +export type IStockOverlayData = Array; diff --git a/src/paths.ts b/src/paths.ts index 0158ea4..9dabdcc 100644 --- a/src/paths.ts +++ b/src/paths.ts @@ -10,6 +10,10 @@ export class Paths { return this.BASE_URL + `/datasets/${datasetId}/tickers/`; } static tickers = this.BASE_URL + "/tickers/"; + static stock(ticker: string) { + return this.BASE_URL + "/companies/stock/" + ticker; + } + static query(datasetId: string) { return this.BASE_URL + `/datasets/${datasetId}/query/`; } diff --git a/src/utils.ts b/src/utils.ts index 0d7f188..3064bbf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,9 @@ export function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } + +const dashFormatRegex = /(\d{4})-(\d{2})-(\d{2})$/; + +export function validateRangeDateFormat(date: string) { + return dashFormatRegex.test(date); +}