diff --git a/src/rest/stock/client.ts b/src/rest/stock/client.ts index 57d11b6..70e32ef 100644 --- a/src/rest/stock/client.ts +++ b/src/rest/stock/client.ts @@ -18,6 +18,7 @@ import { RestStockTechnicalBbParams, bb } from './technical/bb'; import { RestStockCorporateActionsCapitalChangesParams, capitalChanges } from './corporate-actions/capital-changes'; import { RestStockCorporateActionsDividendsParams, dividends } from './corporate-actions/dividends'; import { RestStockCorporateActionsListingApplicantsParams, listingApplicants } from './corporate-actions/listing-applicants'; +import { RestStockOwnershipEtfHoldingsParams, etfHoldings } from './ownership/etf-holdings'; export class RestStockClient extends RestClient { get intraday() { @@ -68,4 +69,11 @@ export class RestStockClient extends RestClient { listingApplicants: (params?: RestStockCorporateActionsListingApplicantsParams) => listingApplicants(request, params), }; } + + get ownership() { + const request = this.request; + return { + etfHoldings: (params: RestStockOwnershipEtfHoldingsParams) => etfHoldings(request, params), + }; + } } diff --git a/src/rest/stock/ownership/etf-holdings.ts b/src/rest/stock/ownership/etf-holdings.ts new file mode 100644 index 0000000..abfe7eb --- /dev/null +++ b/src/rest/stock/ownership/etf-holdings.ts @@ -0,0 +1,34 @@ +import { RestClientRequest } from '../../client'; + +export interface RestStockOwnershipEtfHoldingsParams { + symbol: string; + from?: string; + to?: string; + sort?: 'asc' | 'desc'; + code?: string; +} + +export interface RestStockOwnershipEtfHoldingsComponent { + symbol: string; + name: string; + quantity: number; + weight: number; + quantityChange?: number; + weightChange?: number; +} + +export interface RestStockOwnershipEtfHoldingsResponse { + type?: string; + exchange?: string; + market?: string; + symbol: string; + data: Array<{ + date: string; + components: RestStockOwnershipEtfHoldingsComponent[]; + }>; +} + +export const etfHoldings = (request: RestClientRequest, params: RestStockOwnershipEtfHoldingsParams) => { + const { symbol, ...options } = params; + return request(`ownership/etf-holdings/${symbol}`, options) as Promise; +} diff --git a/test/rest-client.spec.ts b/test/rest-client.spec.ts index b69c049..612461c 100644 --- a/test/rest-client.spec.ts +++ b/test/rest-client.spec.ts @@ -308,6 +308,47 @@ describe('RestClient', () => { }); }); + describe('.ownership', () => { + it('should contain stock ownership api endpoints', () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + expect(stock.ownership).toBeDefined(); + expect(stock.ownership).toHaveProperty('etfHoldings'); + }); + + describe('.etfHoldings()', () => { + it('should request with api key', async () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + await stock.ownership.etfHoldings({ symbol: '0050' }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/ownership/etf-holdings/0050', + { headers: { 'X-API-KEY': 'api-key' } }, + ); + }); + + it('should request with bearer token', async () => { + const client = new RestClient({ bearerToken: 'bearer-token' }); + const stock = client.stock as RestStockClient; + await stock.ownership.etfHoldings({ symbol: '0050' }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/ownership/etf-holdings/0050', + { headers: { 'Authorization': 'Bearer bearer-token' } }, + ); + }); + + it('should request with query params', async () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + await stock.ownership.etfHoldings({ symbol: '0050', from: '2026-05-01', to: '2026-05-21', sort: 'desc', code: '2330' }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/ownership/etf-holdings/0050?code=2330&from=2026-05-01&sort=desc&to=2026-05-21', + { headers: { 'X-API-KEY': 'api-key' } }, + ); + }); + }); + }); + describe('.snapshot', () => { it('should contain stock intraday api endpoints', () => { const client = new RestClient({ apiKey: 'api-key' });