diff --git a/README.md b/README.md index 6dd246f..cdd0346 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ stream.latestTradeDetail$.subscribe((v) => {}) - [ ] Switch Leverage - [ ] User's Force Orders - [x] User's History Orders - - [ ] Adjust isolated margin + - [x] Adjust isolated margin - [ ] Query historical transaction orders * Listen Key - [x] Generate Listen Key diff --git a/src/bingx-client/services/trade.service.spec.ts b/src/bingx-client/services/trade.service.spec.ts new file mode 100644 index 0000000..1b53a3b --- /dev/null +++ b/src/bingx-client/services/trade.service.spec.ts @@ -0,0 +1,81 @@ +import { AccountInterface } from 'bingx-api/bingx/account/account.interface'; +import { BingxAdjustIsolatedMarginEndpoint } from 'bingx-api/bingx/endpoints/bingx-adjust-isolated-margin-endpoint'; +import { EndpointInterface } from 'bingx-api/bingx/endpoints/endpoint.interface'; +import { OrderPositionSideEnum } from 'bingx-api/bingx/enums/order-position-side.enum'; +import { RequestExecutorInterface } from 'bingx-api/bingx/request-executor/request-executor.interface'; +import { TradeService } from 'bingx-api/bingx-client/services/trade.service'; + +class TestRequestExecutor implements RequestExecutorInterface { + public endpoint?: EndpointInterface; + + execute(endpoint: EndpointInterface): Promise { + this.endpoint = endpoint; + return Promise.resolve({} as T); + } +} + +const account: AccountInterface = { + getApiKey: () => 'api-key', + sign: () => ({ + toString: () => 'signature', + secretKey: () => 'secret-key', + }), +}; + +describe('TradeService', () => { + describe('adjustIsolatedMargin', () => { + it('dispatches the adjust isolated margin endpoint', async () => { + const executor = new TestRequestExecutor(); + const service = new TradeService(executor); + + await service.adjustIsolatedMargin( + { + symbol: 'BTC-USDT', + amount: '25.5', + type: 1, + positionSide: OrderPositionSideEnum.LONG, + positionId: '123456789', + recvWindow: '5000', + }, + account, + ); + + const endpoint = executor.endpoint as BingxAdjustIsolatedMarginEndpoint; + const parameters = endpoint.parameters().asRecord(); + + expect(endpoint).toBeInstanceOf(BingxAdjustIsolatedMarginEndpoint); + expect(endpoint.method()).toBe('post'); + expect(endpoint.path()).toBe('/openApi/swap/v2/trade/positionMargin'); + expect(parameters).toMatchObject({ + symbol: 'BTC-USDT', + amount: '25.5', + type: '1', + positionSide: OrderPositionSideEnum.LONG, + positionId: '123456789', + recvWindow: '5000', + }); + expect(parameters.timestamp).toBeDefined(); + }); + + it('omits optional parameters when they are not provided', async () => { + const endpoint = new BingxAdjustIsolatedMarginEndpoint( + { + symbol: 'ETH-USDT', + amount: 10, + type: 2, + }, + account, + ); + const parameters = endpoint.parameters().asRecord(); + + expect(parameters).toMatchObject({ + symbol: 'ETH-USDT', + amount: '10', + type: '2', + }); + expect(parameters.positionSide).toBeUndefined(); + expect(parameters.positionId).toBeUndefined(); + expect(parameters.recvWindow).toBeUndefined(); + }); + }); +}); diff --git a/src/bingx-client/services/trade.service.ts b/src/bingx-client/services/trade.service.ts index 65fa5bd..03b82ee 100644 --- a/src/bingx-client/services/trade.service.ts +++ b/src/bingx-client/services/trade.service.ts @@ -12,6 +12,8 @@ import { BingxSwitchLeverageEndpoint } from 'bingx-api/bingx/endpoints/bingx-swi import { OrderPositionSideEnum } from 'bingx-api/bingx'; import { BingxUserHistoryOrdersEndpoint } from 'bingx-api/bingx/endpoints/bingx-user-history-orders-endpoint'; import { BingxCancelOrderEndpoint } from 'bingx-api/bingx/endpoints/bingx-cancel-order-endpoint'; +import { BingxAdjustIsolatedMarginEndpoint } from 'bingx-api/bingx/endpoints/bingx-adjust-isolated-margin-endpoint'; +import { BingxAdjustIsolatedMarginInterface } from 'bingx-api/bingx/interfaces/adjust-isolated-margin.interface'; export class TradeService { constructor(private readonly requestExecutor: RequestExecutorInterface) {} @@ -94,4 +96,13 @@ export class TradeService { new BingxSwitchLeverageEndpoint(symbol, leverage, side, account), ); } + + public adjustIsolatedMargin( + options: BingxAdjustIsolatedMarginInterface, + account: AccountInterface, + ) { + return this.requestExecutor.execute( + new BingxAdjustIsolatedMarginEndpoint(options, account), + ); + } } diff --git a/src/bingx/endpoints/bingx-adjust-isolated-margin-endpoint.ts b/src/bingx/endpoints/bingx-adjust-isolated-margin-endpoint.ts new file mode 100644 index 0000000..50791ad --- /dev/null +++ b/src/bingx/endpoints/bingx-adjust-isolated-margin-endpoint.ts @@ -0,0 +1,57 @@ +import { AccountInterface } from 'bingx-api/bingx/account/account.interface'; +import { DefaultSignatureParameters } from 'bingx-api/bingx/account/default-signature-parameters'; +import { SignatureParametersInterface } from 'bingx-api/bingx/account/signature-parameters.interface'; +import { Endpoint } from 'bingx-api/bingx/endpoints/endpoint'; +import { EndpointInterface } from 'bingx-api/bingx/endpoints/endpoint.interface'; +import { BingxResponse } from 'bingx-api/bingx/interfaces/bingx-response'; +import { + BingxAdjustIsolatedMarginInterface, + IsolatedMarginAdjustmentType, +} from 'bingx-api/bingx/interfaces/adjust-isolated-margin.interface'; + +export interface BingxAdjustIsolatedMarginResponseInterface { + amount: string | number; + type: IsolatedMarginAdjustmentType; + positionId?: string | number; +} + +export class BingxAdjustIsolatedMarginEndpoint< + R = BingxAdjustIsolatedMarginResponseInterface, + > + extends Endpoint + implements EndpointInterface> +{ + constructor( + private readonly options: BingxAdjustIsolatedMarginInterface, + account: AccountInterface, + ) { + super(account); + } + + readonly t!: BingxResponse; + + method(): 'get' | 'post' | 'put' | 'patch' | 'delete' { + return 'post'; + } + + parameters(): SignatureParametersInterface { + return new DefaultSignatureParameters({ + symbol: this.options.symbol, + amount: this.options.amount.toString(), + type: this.options.type.toString(10), + ...(this.options.positionSide === undefined + ? {} + : { positionSide: this.options.positionSide }), + ...(this.options.positionId === undefined + ? {} + : { positionId: this.options.positionId.toString() }), + ...(this.options.recvWindow === undefined + ? {} + : { recvWindow: this.options.recvWindow.toString() }), + }); + } + + path(): string { + return '/openApi/swap/v2/trade/positionMargin'; + } +} diff --git a/src/bingx/endpoints/index.ts b/src/bingx/endpoints/index.ts index 6866f8b..dd9907a 100644 --- a/src/bingx/endpoints/index.ts +++ b/src/bingx/endpoints/index.ts @@ -13,3 +13,4 @@ export * from './endpoint'; export * from './bingx-user-history-orders-endpoint'; export * from './bingx-user-history-orders-response'; export * from './bingx-cancel-order-endpoint'; +export * from './bingx-adjust-isolated-margin-endpoint'; diff --git a/src/bingx/interfaces/adjust-isolated-margin.interface.ts b/src/bingx/interfaces/adjust-isolated-margin.interface.ts new file mode 100644 index 0000000..68d54c0 --- /dev/null +++ b/src/bingx/interfaces/adjust-isolated-margin.interface.ts @@ -0,0 +1,12 @@ +import { OrderPositionSideEnum } from 'bingx-api/bingx/enums/order-position-side.enum'; + +export type IsolatedMarginAdjustmentType = 1 | 2; + +export interface BingxAdjustIsolatedMarginInterface { + symbol: string; + amount: string | number; + type: IsolatedMarginAdjustmentType; + positionSide?: OrderPositionSideEnum; + positionId?: string | number; + recvWindow?: string | number; +} diff --git a/src/bingx/interfaces/index.ts b/src/bingx/interfaces/index.ts index 96a6ad9..fc6f5ac 100644 --- a/src/bingx/interfaces/index.ts +++ b/src/bingx/interfaces/index.ts @@ -1,3 +1,4 @@ +export * from './adjust-isolated-margin.interface'; export * from './bingx-order.interface'; export * from './bingx-response'; export * from './cancel-all-orders.response'; diff --git a/src/bingx/interfaces/websocket-event.ts b/src/bingx/interfaces/websocket-event.ts index a414299..3be37b3 100644 --- a/src/bingx/interfaces/websocket-event.ts +++ b/src/bingx/interfaces/websocket-event.ts @@ -1,4 +1,3 @@ -import { OrderTypeEnum } from 'bingx-api/bingx/enums/order-type.enum'; import { OrderSideEnum } from 'bingx-api/bingx/enums/order-side.enum'; import { OrderStatusEnum } from 'bingx-api/bingx/enums/order-status.enum'; import { OrderPositionSideEnum } from 'bingx-api/bingx/enums/order-position-side.enum';