diff --git a/README.md b/README.md index c861651..060c33b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Build locally with `npm run build` in this directory. Keep the API key on your s import { TidelightClient } from "@tidelight/sdk"; const client = new TidelightClient({ apiKey: process.env.TIDELIGHT_API_KEY! }); -const page = await client.listTokenizedEquities({ limit: 20 }); +const page = await client.listTokenizedEquities({ limit: 20, underlyingTicker: "AAPL" }); for (const instrument of page.data) console.log(instrument.symbol, instrument.underlying_ticker); for await (const instrument of client.tokenizedEquities({ limit: 50 })) { diff --git a/src/index.ts b/src/index.ts index 0be73dc..2042731 100644 --- a/src/index.ts +++ b/src/index.ts @@ -79,14 +79,17 @@ export class TidelightClient { this.transport = options.fetch ?? fetch; } - async listTokenizedEquities(options: { limit?: number; cursor?: string; signal?: AbortSignal } = {}): Promise { + async listTokenizedEquities(options: { limit?: number; cursor?: string; underlyingTicker?: string; signal?: AbortSignal } = {}): Promise { const limit = options.limit ?? 20; if (!Number.isInteger(limit) || limit < 1 || limit > 100) throw new RangeError("limit must be 1 to 100."); if (options.cursor !== undefined && !/^[A-Z0-9]{2,32}$/.test(options.cursor)) throw new TypeError("Invalid instrument cursor."); + const underlyingTicker = options.underlyingTicker?.toUpperCase(); + if (underlyingTicker !== undefined && !/^[A-Z][A-Z0-9.]{0,9}$/.test(underlyingTicker)) throw new TypeError("Invalid underlyingTicker."); const url = new URL(`${this.baseUrl}/market/instruments`); url.searchParams.set("kind", "rtoken"); url.searchParams.set("limit", String(limit)); if (options.cursor) url.searchParams.set("cursor", options.cursor); + if (underlyingTicker) url.searchParams.set("underlying_ticker", underlyingTicker); for (let attempt = 0; ; attempt++) { const controller = new AbortController(); const onAbort = () => controller.abort(); diff --git a/tests/client.test.mjs b/tests/client.test.mjs index fa7867c..e037d94 100644 --- a/tests/client.test.mjs +++ b/tests/client.test.mjs @@ -5,6 +5,17 @@ import { TidelightApiError, TidelightClient } from "../dist/index.js"; const key = `tl_test_${"a".repeat(43)}`; const jobId = "01234567-89ab-4cde-8fab-0123456789ab"; +test("filters market instruments by normalized underlying ticker", async () => { + let requestUrl = ""; + const client = new TidelightClient({ apiKey: key, fetch: async url => { + requestUrl = String(url); + return Response.json({ data: [], next_cursor: null, generated_at: 1, request_id: "market-filter" }); + } }); + await client.listTokenizedEquities({ limit: 1, underlyingTicker: "aapl" }); + assert.match(requestUrl, /underlying_ticker=AAPL/); + await assert.rejects(client.listTokenizedEquities({ underlyingTicker: "AAPL?" }), TypeError); +}); + test("starts, polls, and cancels an asynchronous research job", async () => { const calls = []; const client = new TidelightClient({ apiKey: key, fetch: async (url, init) => {