Skip to content

Commit e618d1c

Browse files
kevinypfanclaude
andcommitted
feat(rest): add corporate actions API endpoints
Add three new REST API endpoints under /v1.0/stock/corporate-actions/: - capital-changes: 資本變動(減資、面額變更、ETF分割合併) - dividends: 股利資料 - listing-applicants: 上市櫃申請 Features: - Discriminated union types for capital-changes based on actionType - Support for optional query params: start_date, end_date, sort - All raw fields are optional for flexibility Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 151cfa3 commit e618d1c

5 files changed

Lines changed: 273 additions & 0 deletions

File tree

‎src/rest/stock/client.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import { RestStockTechnicalRsiParams, rsi } from './technical/rsi';
1515
import { RestStockTechnicalKdjParams, kdj } from './technical/kdj';
1616
import { RestStockTechnicalMacdParams, macd } from './technical/macd';
1717
import { RestStockTechnicalBbParams, bb } from './technical/bb';
18+
import { RestStockCorporateActionsCapitalChangesParams, capitalChanges } from './corporate-actions/capital-changes';
19+
import { RestStockCorporateActionsDividendsParams, dividends } from './corporate-actions/dividends';
20+
import { RestStockCorporateActionsListingApplicantsParams, listingApplicants } from './corporate-actions/listing-applicants';
1821

1922
export class RestStockClient extends RestClient {
2023
get intraday() {
@@ -56,4 +59,13 @@ export class RestStockClient extends RestClient {
5659
bb: (params: RestStockTechnicalBbParams) => bb(request, params),
5760
};
5861
}
62+
63+
get corporateActions() {
64+
const request = this.request;
65+
return {
66+
capitalChanges: (params?: RestStockCorporateActionsCapitalChangesParams) => capitalChanges(request, params),
67+
dividends: (params?: RestStockCorporateActionsDividendsParams) => dividends(request, params),
68+
listingApplicants: (params?: RestStockCorporateActionsListingApplicantsParams) => listingApplicants(request, params),
69+
};
70+
}
5971
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { RestClientRequest } from '../../client';
2+
3+
export interface RestStockCorporateActionsCapitalChangesParams {
4+
start_date?: string;
5+
end_date?: string;
6+
sort?: 'asc' | 'desc';
7+
}
8+
9+
export interface CapitalReductionRaw {
10+
previousClose?: number;
11+
referencePrice?: number;
12+
limitUpPrice?: number;
13+
limitDownPrice?: number;
14+
openingReferencePrice?: number;
15+
exrightReferencePrice?: number;
16+
reason?: string;
17+
sharesPerThousand?: number;
18+
refundPerShare?: number;
19+
cashIncreaseRatioAfterReduction?: number;
20+
subscriptionPrice?: number;
21+
}
22+
23+
export interface ParValueChangeRaw {
24+
previousClose?: number;
25+
referencePrice?: number;
26+
limitUpPrice?: number;
27+
limitDownPrice?: number;
28+
openingReferencePrice?: number;
29+
splitRatio?: number;
30+
parValueBefore?: number;
31+
parValueAfter?: number;
32+
}
33+
34+
export interface EtfSplitOrMergeRaw {
35+
previousClose?: number;
36+
referencePrice?: number;
37+
limitUpPrice?: number;
38+
limitDownPrice?: number;
39+
openingReferencePrice?: number;
40+
splitRatio?: number;
41+
splitType?: string;
42+
}
43+
44+
export interface CapitalReductionChange {
45+
symbol: string;
46+
name: string;
47+
actionType: 'capital_reduction';
48+
resumeDate: string;
49+
haltDate: string;
50+
exchange: string;
51+
raw: CapitalReductionRaw;
52+
}
53+
54+
export interface ParValueChange {
55+
symbol: string;
56+
name: string;
57+
actionType: 'par_value_change';
58+
resumeDate: string;
59+
haltDate: string;
60+
exchange: string;
61+
raw: ParValueChangeRaw;
62+
}
63+
64+
export interface EtfSplitOrMergeChange {
65+
symbol: string;
66+
name: string;
67+
actionType: 'etf_split_or_merge';
68+
resumeDate: string;
69+
haltDate: string;
70+
exchange: string;
71+
raw: EtfSplitOrMergeRaw;
72+
}
73+
74+
export type CapitalChange = CapitalReductionChange | ParValueChange | EtfSplitOrMergeChange;
75+
76+
export interface RestStockCorporateActionsCapitalChangesResponse {
77+
start_date: string;
78+
end_date: string;
79+
sort: string;
80+
data: CapitalChange[];
81+
}
82+
83+
export const capitalChanges = (request: RestClientRequest, params?: RestStockCorporateActionsCapitalChangesParams) => {
84+
return request('corporate-actions/capital-changes', params ?? {}) as Promise<RestStockCorporateActionsCapitalChangesResponse>;
85+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { RestClientRequest } from '../../client';
2+
3+
export interface RestStockCorporateActionsDividendsParams {
4+
start_date?: string;
5+
end_date?: string;
6+
sort?: 'asc' | 'desc';
7+
}
8+
9+
export interface Dividend {
10+
date: string;
11+
exchange: string | null;
12+
symbol: string;
13+
name: string | null;
14+
previousClose: number | null;
15+
referencePrice: number | null;
16+
dividend: number | null;
17+
dividendType: string | null;
18+
limitUpPrice: number | null;
19+
limitDownPrice: number | null;
20+
openingReferencePrice: number | null;
21+
exdividendReferencePrice: number | null;
22+
cashDividend: number | null;
23+
stockDividendShares: number | null;
24+
}
25+
26+
export interface RestStockCorporateActionsDividendsResponse {
27+
start_date: string;
28+
end_date: string;
29+
sort: string;
30+
data: Dividend[];
31+
}
32+
33+
export const dividends = (request: RestClientRequest, params?: RestStockCorporateActionsDividendsParams) => {
34+
return request('corporate-actions/dividends', params ?? {}) as Promise<RestStockCorporateActionsDividendsResponse>;
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { RestClientRequest } from '../../client';
2+
3+
export interface RestStockCorporateActionsListingApplicantsParams {
4+
start_date?: string;
5+
end_date?: string;
6+
sort?: 'asc' | 'desc';
7+
}
8+
9+
export interface ListingApplicant {
10+
symbol: string;
11+
name: string;
12+
exchange: string;
13+
applicationDate: string;
14+
chairman: string;
15+
capitalAtApplication: number | null;
16+
reviewCommitteeDate: string | null;
17+
boardApprovalDate: string | null;
18+
contractApprovalDate: string | null;
19+
listedDate: string | null;
20+
underwriter: string | null;
21+
underwritingPrice: number | null;
22+
remarks: string;
23+
}
24+
25+
export interface RestStockCorporateActionsListingApplicantsResponse {
26+
start_date: string;
27+
end_date: string;
28+
sort: string;
29+
data: ListingApplicant[];
30+
}
31+
32+
export const listingApplicants = (request: RestClientRequest, params?: RestStockCorporateActionsListingApplicantsParams) => {
33+
return request('corporate-actions/listing-applicants', params ?? {}) as Promise<RestStockCorporateActionsListingApplicantsResponse>;
34+
}

‎test/rest-client.spec.ts‎

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,113 @@ describe('RestClient', () => {
507507
});
508508
});
509509
});
510+
511+
describe('.corporateActions', () => {
512+
it('should contain stock corporate actions api endpoints', () => {
513+
const client = new RestClient({ apiKey: 'api-key' });
514+
const stock = client.stock as RestStockClient;
515+
expect(stock.corporateActions).toBeDefined();
516+
expect(stock.corporateActions).toHaveProperty('capitalChanges');
517+
expect(stock.corporateActions).toHaveProperty('dividends');
518+
expect(stock.corporateActions).toHaveProperty('listingApplicants');
519+
});
520+
521+
describe('.capitalChanges()', () => {
522+
it('should request with api key', async () => {
523+
const client = new RestClient({ apiKey: 'api-key' });
524+
const stock = client.stock as RestStockClient;
525+
await stock.corporateActions.capitalChanges({ start_date: '2025-01-01', end_date: '2025-12-31', sort: 'asc' });
526+
expect(fetch).toBeCalledWith(
527+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/capital-changes?end_date=2025-12-31&sort=asc&start_date=2025-01-01',
528+
{ headers: { 'X-API-KEY': 'api-key' } },
529+
);
530+
});
531+
532+
it('should request with bearer token', async () => {
533+
const client = new RestClient({ bearerToken: 'bearer-token' });
534+
const stock = client.stock as RestStockClient;
535+
await stock.corporateActions.capitalChanges({ start_date: '2025-01-01', end_date: '2025-12-31', sort: 'asc' });
536+
expect(fetch).toBeCalledWith(
537+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/capital-changes?end_date=2025-12-31&sort=asc&start_date=2025-01-01',
538+
{ headers: { 'Authorization': 'Bearer bearer-token' } },
539+
);
540+
});
541+
542+
it('should request without params', async () => {
543+
const client = new RestClient({ apiKey: 'api-key' });
544+
const stock = client.stock as RestStockClient;
545+
await stock.corporateActions.capitalChanges();
546+
expect(fetch).toBeCalledWith(
547+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/capital-changes',
548+
{ headers: { 'X-API-KEY': 'api-key' } },
549+
);
550+
});
551+
});
552+
553+
describe('.dividends()', () => {
554+
it('should request with api key', async () => {
555+
const client = new RestClient({ apiKey: 'api-key' });
556+
const stock = client.stock as RestStockClient;
557+
await stock.corporateActions.dividends({ start_date: '2025-01-01', end_date: '2025-12-31', sort: 'desc' });
558+
expect(fetch).toBeCalledWith(
559+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/dividends?end_date=2025-12-31&sort=desc&start_date=2025-01-01',
560+
{ headers: { 'X-API-KEY': 'api-key' } },
561+
);
562+
});
563+
564+
it('should request with bearer token', async () => {
565+
const client = new RestClient({ bearerToken: 'bearer-token' });
566+
const stock = client.stock as RestStockClient;
567+
await stock.corporateActions.dividends({ start_date: '2025-01-01', end_date: '2025-12-31', sort: 'desc' });
568+
expect(fetch).toBeCalledWith(
569+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/dividends?end_date=2025-12-31&sort=desc&start_date=2025-01-01',
570+
{ headers: { 'Authorization': 'Bearer bearer-token' } },
571+
);
572+
});
573+
574+
it('should request without params', async () => {
575+
const client = new RestClient({ apiKey: 'api-key' });
576+
const stock = client.stock as RestStockClient;
577+
await stock.corporateActions.dividends();
578+
expect(fetch).toBeCalledWith(
579+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/dividends',
580+
{ headers: { 'X-API-KEY': 'api-key' } },
581+
);
582+
});
583+
});
584+
585+
describe('.listingApplicants()', () => {
586+
it('should request with api key', async () => {
587+
const client = new RestClient({ apiKey: 'api-key' });
588+
const stock = client.stock as RestStockClient;
589+
await stock.corporateActions.listingApplicants({ start_date: '2025-01-01', end_date: '2025-12-31', sort: 'asc' });
590+
expect(fetch).toBeCalledWith(
591+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/listing-applicants?end_date=2025-12-31&sort=asc&start_date=2025-01-01',
592+
{ headers: { 'X-API-KEY': 'api-key' } },
593+
);
594+
});
595+
596+
it('should request with bearer token', async () => {
597+
const client = new RestClient({ bearerToken: 'bearer-token' });
598+
const stock = client.stock as RestStockClient;
599+
await stock.corporateActions.listingApplicants({ start_date: '2025-01-01', end_date: '2025-12-31', sort: 'asc' });
600+
expect(fetch).toBeCalledWith(
601+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/listing-applicants?end_date=2025-12-31&sort=asc&start_date=2025-01-01',
602+
{ headers: { 'Authorization': 'Bearer bearer-token' } },
603+
);
604+
});
605+
606+
it('should request without params', async () => {
607+
const client = new RestClient({ apiKey: 'api-key' });
608+
const stock = client.stock as RestStockClient;
609+
await stock.corporateActions.listingApplicants();
610+
expect(fetch).toBeCalledWith(
611+
'https://api.fugle.tw/marketdata/v1.0/stock/corporate-actions/listing-applicants',
612+
{ headers: { 'X-API-KEY': 'api-key' } },
613+
);
614+
});
615+
});
616+
});
510617
});
511618

512619
describe('.futopt', () => {

0 commit comments

Comments
 (0)