From fb886dbca4b1d812637cb4586b8f03f6ef1bce19 Mon Sep 17 00:00:00 2001 From: Chun-Kai Wang Date: Sat, 5 Oct 2024 20:21:04 +0800 Subject: [PATCH] feat: add REST endpoints for stock technical API --- src/rest/stock/client.ts | 16 ++++ src/rest/stock/technical/bb.ts | 28 +++++++ src/rest/stock/technical/kdj.ts | 30 ++++++++ src/rest/stock/technical/macd.ts | 29 ++++++++ src/rest/stock/technical/rsi.ts | 26 +++++++ src/rest/stock/technical/sma.ts | 26 +++++++ test/rest-client.spec.ts | 123 +++++++++++++++++++++++++++++++ 7 files changed, 278 insertions(+) create mode 100644 src/rest/stock/technical/bb.ts create mode 100644 src/rest/stock/technical/kdj.ts create mode 100644 src/rest/stock/technical/macd.ts create mode 100644 src/rest/stock/technical/rsi.ts create mode 100644 src/rest/stock/technical/sma.ts diff --git a/src/rest/stock/client.ts b/src/rest/stock/client.ts index 649c955..59b1dfa 100644 --- a/src/rest/stock/client.ts +++ b/src/rest/stock/client.ts @@ -10,6 +10,11 @@ import { RestStockHistoricalStatsParams, stats } from './historical/stats'; import { RestStockSnapshotQuotesParams, quotes } from './snapshot/quotes'; import { RestStockSnapshotMoversParams, movers } from './snapshot/movers'; import { RestStockSnapshotActivesParams, actives } from './snapshot/actives'; +import { RestStockTechnicalSmaParams, sma } from './technical/sma'; +import { RestStockTechnicalRsiParams, rsi } from './technical/rsi'; +import { RestStockTechnicalKdjParams, kdj } from './technical/kdj'; +import { RestStockTechnicalMacdParams, macd } from './technical/macd'; +import { RestStockTechnicalBbParams, bb } from './technical/bb'; export class RestStockClient extends RestClient { get intraday() { @@ -40,4 +45,15 @@ export class RestStockClient extends RestClient { actives: (params: RestStockSnapshotActivesParams) => actives(request, params), }; } + + get technical() { + const request = this.request; + return { + sma: (params: RestStockTechnicalSmaParams) => sma(request, params), + rsi: (params: RestStockTechnicalRsiParams) => rsi(request, params), + kdj: (params: RestStockTechnicalKdjParams) => kdj(request, params), + macd: (params: RestStockTechnicalMacdParams) => macd(request, params), + bb: (params: RestStockTechnicalBbParams) => bb(request, params), + }; + } } diff --git a/src/rest/stock/technical/bb.ts b/src/rest/stock/technical/bb.ts new file mode 100644 index 0000000..8ed848c --- /dev/null +++ b/src/rest/stock/technical/bb.ts @@ -0,0 +1,28 @@ +import { RestClientRequest } from '../../client'; + +export interface RestStockTechnicalBbParams { + symbol: string; + from?: string; + to?: string; + timeframe?: 'D' | 'W' | 'M' | '1' | '3' | '5' | '10' | '15' | '30' | '60'; + period: number; +} + +export interface RestStockTechnicalBbResponse { + symbol: string; + type: string; + exchange: string; + market: string; + timeframe: string; + data: Array<{ + date: string; + upper: number; + middle: number; + lower: number; + }>; +} + +export const bb = (request: RestClientRequest, params: RestStockTechnicalBbParams) => { + const { symbol, ...options } = params; + return request(`technical/bb/${symbol}`, options) as Promise; +} diff --git a/src/rest/stock/technical/kdj.ts b/src/rest/stock/technical/kdj.ts new file mode 100644 index 0000000..4cff8e6 --- /dev/null +++ b/src/rest/stock/technical/kdj.ts @@ -0,0 +1,30 @@ +import { RestClientRequest } from '../../client'; + +export interface RestStockTechnicalKdjParams { + symbol: string; + from?: string; + to?: string; + timeframe?: 'D' | 'W' | 'M' | '1' | '3' | '5' | '10' | '15' | '30' | '60'; + rPeriod: number; + kPeriod: number; + dPeriod: number; +} + +export interface RestStockTechnicalKdjResponse { + symbol: string; + type: string; + exchange: string; + market: string; + timeframe: string; + data: Array<{ + date: string; + k: number; + d: number; + j: number; + }>; +} + +export const kdj = (request: RestClientRequest, params: RestStockTechnicalKdjParams) => { + const { symbol, ...options } = params; + return request(`technical/kdj/${symbol}`, options) as Promise; +} diff --git a/src/rest/stock/technical/macd.ts b/src/rest/stock/technical/macd.ts new file mode 100644 index 0000000..9fed8df --- /dev/null +++ b/src/rest/stock/technical/macd.ts @@ -0,0 +1,29 @@ +import { RestClientRequest } from '../../client'; + +export interface RestStockTechnicalMacdParams { + symbol: string; + from?: string; + to?: string; + timeframe?: 'D' | 'W' | 'M' | '1' | '3' | '5' | '10' | '15' | '30' | '60'; + fast: number; + slow: number; + signal: number; +} + +export interface RestStockTechnicalMacdResponse { + symbol: string; + type: string; + exchange: string; + market: string; + timeframe: string; + data: Array<{ + date: string; + macdLine: number; + signalLine: number; + }>; +} + +export const macd = (request: RestClientRequest, params: RestStockTechnicalMacdParams) => { + const { symbol, ...options } = params; + return request(`technical/macd/${symbol}`, options) as Promise; +} diff --git a/src/rest/stock/technical/rsi.ts b/src/rest/stock/technical/rsi.ts new file mode 100644 index 0000000..ae2bb44 --- /dev/null +++ b/src/rest/stock/technical/rsi.ts @@ -0,0 +1,26 @@ +import { RestClientRequest } from '../../client'; + +export interface RestStockTechnicalRsiParams { + symbol: string; + from?: string; + to?: string; + timeframe?: 'D' | 'W' | 'M' | '1' | '3' | '5' | '10' | '15' | '30' | '60'; + period: number; +} + +export interface RestStockTechnicalRsiResponse { + symbol: string; + type: string; + exchange: string; + market: string; + timeframe: string; + data: Array<{ + date: string; + rsi: number; + }>; +} + +export const rsi = (request: RestClientRequest, params: RestStockTechnicalRsiParams) => { + const { symbol, ...options } = params; + return request(`technical/rsi/${symbol}`, options) as Promise; +} diff --git a/src/rest/stock/technical/sma.ts b/src/rest/stock/technical/sma.ts new file mode 100644 index 0000000..0775e0c --- /dev/null +++ b/src/rest/stock/technical/sma.ts @@ -0,0 +1,26 @@ +import { RestClientRequest } from '../../client'; + +export interface RestStockTechnicalSmaParams { + symbol: string; + from?: string; + to?: string; + timeframe?: 'D' | 'W' | 'M' | '1' | '3' | '5' | '10' | '15' | '30' | '60'; + period: number; +} + +export interface RestStockTechnicalSmaResponse { + symbol: string; + type: string; + exchange: string; + market: string; + timeframe: string; + data: Array<{ + date: string; + sma: number; + }>; +} + +export const sma = (request: RestClientRequest, params: RestStockTechnicalSmaParams) => { + const { symbol, ...options } = params; + return request(`technical/sma/${symbol}`, options) as Promise; +} diff --git a/test/rest-client.spec.ts b/test/rest-client.spec.ts index b322eee..ac2be9f 100644 --- a/test/rest-client.spec.ts +++ b/test/rest-client.spec.ts @@ -316,6 +316,129 @@ describe('RestClient', () => { }); }); }); + + describe('.technical', () => { + it('should contain stock technical api endpoints', () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + expect(stock.technical).toBeDefined(); + expect(stock.technical).toHaveProperty('sma'); + expect(stock.technical).toHaveProperty('rsi'); + expect(stock.technical).toHaveProperty('kdj'); + expect(stock.technical).toHaveProperty('macd'); + expect(stock.technical).toHaveProperty('bb'); + }); + + describe('.sma()', () => { + it('should request with api key', async () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + await stock.technical.sma({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', period: 5 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/sma/2330?from=2024-01-01&period=5&timeframe=D&to=2024-12-31', + { 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.technical.sma({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', period: 5 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/sma/2330?from=2024-01-01&period=5&timeframe=D&to=2024-12-31', + { headers: { 'Authorization': 'Bearer bearer-token' } }, + ); + }); + }); + + describe('.rsi()', () => { + it('should request with api key', async () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + await stock.technical.rsi({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', period: 6 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/rsi/2330?from=2024-01-01&period=6&timeframe=D&to=2024-12-31', + { 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.technical.rsi({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', period: 6 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/rsi/2330?from=2024-01-01&period=6&timeframe=D&to=2024-12-31', + { headers: { 'Authorization': 'Bearer bearer-token' } }, + ); + }); + }); + + describe('.kdj()', () => { + it('should request with api key', async () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + await stock.technical.kdj({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', rPeriod: 14, kPeriod: 9, dPeriod: 3 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/kdj/2330?dPeriod=3&from=2024-01-01&kPeriod=9&rPeriod=14&timeframe=D&to=2024-12-31', + { 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.technical.kdj({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', rPeriod: 14, kPeriod: 9, dPeriod: 3 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/kdj/2330?dPeriod=3&from=2024-01-01&kPeriod=9&rPeriod=14&timeframe=D&to=2024-12-31', + { headers: { 'Authorization': 'Bearer bearer-token' } }, + ); + }); + }); + + describe('.macd()', () => { + it('should request with api key', async () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + await stock.technical.macd({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', fast: 12, slow: 26, signal: 9 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/macd/2330?fast=12&from=2024-01-01&signal=9&slow=26&timeframe=D&to=2024-12-31', + { 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.technical.macd({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', fast: 12, slow: 26, signal: 9 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/macd/2330?fast=12&from=2024-01-01&signal=9&slow=26&timeframe=D&to=2024-12-31', + { headers: { 'Authorization': 'Bearer bearer-token' } }, + ); + }); + }); + + describe('.bb()', () => { + it('should request with api key', async () => { + const client = new RestClient({ apiKey: 'api-key' }); + const stock = client.stock as RestStockClient; + await stock.technical.bb({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', period: 20 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/bb/2330?from=2024-01-01&period=20&timeframe=D&to=2024-12-31', + { 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.technical.bb({ symbol: '2330', from: '2024-01-01', to: '2024-12-31', timeframe: 'D', period: 20 }); + expect(fetch).toBeCalledWith( + 'https://api.fugle.tw/marketdata/v1.0/stock/technical/bb/2330?from=2024-01-01&period=20&timeframe=D&to=2024-12-31', + { headers: { 'Authorization': 'Bearer bearer-token' } }, + ); + }); + }); + }); }); describe('.futopt', () => {