From ff8ba919cb52487aa9dd2e936ce0f841c75a20d0 Mon Sep 17 00:00:00 2001 From: iKoles-dev <59211303+iKoles-dev@users.noreply.github.com> Date: Tue, 12 May 2026 05:49:59 +0300 Subject: [PATCH] Add user fee rate endpoint --- README.md | 2 +- .../services/account.service.spec.ts | 64 +++++++++++++++++++ src/bingx-client/services/account.service.ts | 7 ++ .../endpoints/bingx-user-fee-rate-endpoint.ts | 47 ++++++++++++++ src/bingx/endpoints/index.ts | 1 + 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/bingx-client/services/account.service.spec.ts create mode 100644 src/bingx/endpoints/bingx-user-fee-rate-endpoint.ts diff --git a/README.md b/README.md index 6dd246f..8bb1df9 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ stream.latestTradeDetail$.subscribe((v) => {}) - [x] Perpetual Swap Positions - [ ] Get Account Profit and Loss Fund Flow - [ ] Export fund flow - - [ ] User fee rate + - [x] User fee rate * Trade Interface - [ ] Trade order test - [x] Trade order diff --git a/src/bingx-client/services/account.service.spec.ts b/src/bingx-client/services/account.service.spec.ts new file mode 100644 index 0000000..6da93b1 --- /dev/null +++ b/src/bingx-client/services/account.service.spec.ts @@ -0,0 +1,64 @@ +import { AccountInterface } from 'bingx-api/bingx/account/account.interface'; +import { SignatureInterface } from 'bingx-api/bingx/account/signature.interface'; +import { SignatureParametersInterface } from 'bingx-api/bingx/account/signature-parameters.interface'; +import { BingxUserFeeRateEndpoint } from 'bingx-api/bingx/endpoints/bingx-user-fee-rate-endpoint'; +import { RequestExecutorInterface } from 'bingx-api/bingx/request-executor/request-executor.interface'; +import { AccountService } from 'bingx-api/bingx-client/services/account.service'; + +class TestAccount implements AccountInterface { + getApiKey(): string { + return 'test-api-key'; + } + + sign(parameters: SignatureParametersInterface): SignatureInterface { + return { + toString: () => JSON.stringify(parameters.asRecord()), + secretKey: () => 'test-secret-key', + }; + } +} + +describe('AccountService', () => { + let dateNowSpy: jest.SpyInstance; + + beforeEach(() => { + dateNowSpy = jest.spyOn(Date, 'now').mockReturnValue(1_714_000_000_000); + }); + + afterEach(() => { + dateNowSpy.mockRestore(); + }); + + it('describes the user fee rate endpoint request shape', () => { + const endpoint = new BingxUserFeeRateEndpoint(new TestAccount(), 5000); + + expect(endpoint.method()).toBe('get'); + expect(endpoint.path()).toBe('/openApi/swap/v2/user/commissionRate'); + expect(endpoint.apiKey().asHeader()).toEqual({ + 'X-BX-APIKEY': 'test-api-key', + }); + expect(endpoint.parameters().asRecord()).toEqual({ + recvWindow: '5000', + timestamp: '1714000000000', + }); + }); + + it('executes the user fee rate endpoint through account service', async () => { + const account = new TestAccount(); + const requestExecutor: RequestExecutorInterface = { + execute: jest.fn(async (endpoint) => endpoint as never), + }; + const service = new AccountService(requestExecutor); + + const endpoint = await service.getUserFeeRate(account, 5000); + + expect(requestExecutor.execute).toHaveBeenCalledTimes(1); + expect(endpoint).toBeInstanceOf(BingxUserFeeRateEndpoint); + expect( + (endpoint as unknown as BingxUserFeeRateEndpoint).parameters().asRecord(), + ).toEqual({ + recvWindow: '5000', + timestamp: '1714000000000', + }); + }); +}); diff --git a/src/bingx-client/services/account.service.ts b/src/bingx-client/services/account.service.ts index d6d9a03..9391734 100644 --- a/src/bingx-client/services/account.service.ts +++ b/src/bingx-client/services/account.service.ts @@ -2,6 +2,7 @@ import { RequestExecutorInterface } from 'bingx-api/bingx/request-executor/reque import { AccountInterface } from 'bingx-api/bingx/account/account.interface'; import { BingxGetPerpetualSwapAccountAssetEndpoint } from 'bingx-api/bingx/endpoints/bingx-get-perpetual-swap-account-asset-endpoint'; import { BingxPerpetualSwapPositionsEndpoint } from 'bingx-api/bingx/endpoints/bingx-perpetual-swap-positions-endpoint'; +import { BingxUserFeeRateEndpoint } from 'bingx-api/bingx/endpoints/bingx-user-fee-rate-endpoint'; export class AccountService { constructor(private readonly requestExecutor: RequestExecutorInterface) {} @@ -17,4 +18,10 @@ export class AccountService { new BingxPerpetualSwapPositionsEndpoint(symbol, account), ); } + + public getUserFeeRate(account: AccountInterface, recvWindow?: number) { + return this.requestExecutor.execute( + new BingxUserFeeRateEndpoint(account, recvWindow), + ); + } } diff --git a/src/bingx/endpoints/bingx-user-fee-rate-endpoint.ts b/src/bingx/endpoints/bingx-user-fee-rate-endpoint.ts new file mode 100644 index 0000000..555e558 --- /dev/null +++ b/src/bingx/endpoints/bingx-user-fee-rate-endpoint.ts @@ -0,0 +1,47 @@ +import { + AccountInterface, + BingxResponse, + DefaultSignatureParameters, + EndpointInterface, + SignatureParametersInterface, +} from 'bingx-api/bingx'; +import { Endpoint } from 'bingx-api/bingx/endpoints/endpoint'; + +export interface BingxUserFeeRateData { + commission: { + takerCommissionRate: number | string; + makerCommissionRate: number | string; + }; +} + +export class BingxUserFeeRateEndpoint + extends Endpoint> + implements EndpointInterface> +{ + constructor( + account: AccountInterface, + private readonly recvWindow?: number, + ) { + super(account); + } + + method(): 'get' | 'post' | 'put' | 'patch' | 'delete' { + return 'get'; + } + + parameters(): SignatureParametersInterface { + return new DefaultSignatureParameters( + this.recvWindow === undefined + ? {} + : { + recvWindow: this.recvWindow.toString(10), + }, + ); + } + + path(): string { + return '/openApi/swap/v2/user/commissionRate'; + } + + readonly t!: BingxResponse; +} diff --git a/src/bingx/endpoints/index.ts b/src/bingx/endpoints/index.ts index 6866f8b..0a4a55f 100644 --- a/src/bingx/endpoints/index.ts +++ b/src/bingx/endpoints/index.ts @@ -8,6 +8,7 @@ export * from './bingx-perpetual-swap-positions-endpoint'; export * from './bingx-request.interface'; export * from './bingx-response.interface'; export * from './bingx-trade-order-endpoint'; +export * from './bingx-user-fee-rate-endpoint'; export * from './endpoint.interface'; export * from './endpoint'; export * from './bingx-user-history-orders-endpoint';