Skip to content

Commit

Permalink
feat(): dynamic param type mapping for ws api topics
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagosiebler committed Jun 10, 2024
1 parent c4377a4 commit 635b33f
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 45 deletions.
1 change: 0 additions & 1 deletion examples/ws-private-perp-futures-wsapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ async function start() {
'perpFuturesUSDTV4',
'futures.order_list',
{
contract: 'BTC_USDT',
status: 'open',
},
);
Expand Down
12 changes: 8 additions & 4 deletions examples/ws-private-spot-wsapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ async function start() {
console.log(new Date(), 'authenticated!', loginResult);

/**
* For other channels, the 3rd parameter should have any parameters for the request (the payload).
* For other channels, the 3rd parameter should have any parameters for the request (the payload that goes in req_param in the docs).
*
* See WsAPIRequestsTopicMap for a topic->parameter map.
*
* Note that internal parameters such as "signature" etc are all handled automatically by the SDK.
*/
Expand All @@ -129,6 +131,8 @@ async function start() {

console.log(new Date(), 'Result:', newOrder);

client.sendWSAPIRequest('spotV4', 'spot.order_place');

/**
* Cancel spot order
*/
Expand All @@ -138,7 +142,7 @@ async function start() {
'spotV4',
'spot.order_cancel',
{
order_id: 'yourIdHere',
order_id: 'yourOrderIdHere1',
currency_pair: 'BTC_USDT',
},
);
Expand All @@ -155,11 +159,11 @@ async function start() {
'spot.order_cancel_ids',
[
{
order_id: 'yourIdHere',
id: 'yourOrderIdHere1',
currency_pair: 'BTC_USDT',
},
{
order_id: 'yourIdHere',
id: 'yourOrderIdHere2',
currency_pair: 'ETH_USDT',
},
],
Expand Down
18 changes: 6 additions & 12 deletions src/RestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import {
SubmitFuturesPriceTriggeredOrderReq,
UpdateDualModePositionLeverageReq,
UpdateDualModePositionMarginReq,
UpdateFuturesOrderReq,
} from './types/request/futures.js';
import {
GetCrossMarginAccountHistoryReq,
Expand Down Expand Up @@ -298,6 +299,7 @@ import {
DeliveryContract,
FuturesOrder,
FuturesPriceTriggeredOrder,
GetSingleOrderReq,
Order,
Position,
SpotPriceTriggeredOrder,
Expand Down Expand Up @@ -1215,11 +1217,7 @@ export class RestClient extends BaseRestClient {
* @param params Parameters for getting a single order
* @returns Promise<APIResponse<Order>>
*/
getSpotOrder(params: {
order_id: string;
currency_pair: string;
account?: 'spot' | 'margin' | 'cross_margin' | 'unified';
}): Promise<APIResponse<Order>> {
getSpotOrder(params: GetSingleOrderReq): Promise<APIResponse<Order>> {
const { order_id, ...query } = params;
return this.getPrivate(`/spot/orders/${order_id}`, query);
}
Expand Down Expand Up @@ -2378,13 +2376,9 @@ export class RestClient extends BaseRestClient {
* @param params Parameters for amending an order
* @returns Promise<APIResponse<FuturesOrder>>
*/
updateFuturesOrder(params: {
settle: 'btc' | 'usdt' | 'usd';
order_id: string;
size?: number;
price?: string;
amend_text?: string;
}): Promise<APIResponse<FuturesOrder>> {
updateFuturesOrder(
params: UpdateFuturesOrderReq,
): Promise<APIResponse<FuturesOrder>> {
const { settle, order_id, ...body } = params;
return this.putPrivate(`/futures/${settle}/orders/${order_id}`, {
body: body,
Expand Down
17 changes: 9 additions & 8 deletions src/WebsocketClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
import {
FuturesWSAPITopic,
SpotWSAPITopic,
WsAPIRequestsTopicMap,
WSAPITopic,
WsAPIWsKeyTopicMap,
} from './types/websockets/wsAPI.js';

Expand Down Expand Up @@ -713,7 +715,7 @@ export class WebsocketClient extends BaseWebsocketClient<WsKey> {
}
}

async signWSAPIRequest<TRequestParams extends object | string = object>(
async signWSAPIRequest<TRequestParams = object>(
requestEvent: WSAPIRequest<TRequestParams>,
): Promise<WSAPIRequest<TRequestParams>> {
if (!this.options.apiSecret) {
Expand Down Expand Up @@ -778,26 +780,25 @@ export class WebsocketClient extends BaseWebsocketClient<WsKey> {
*
* @param wsKey - The connection this event is for (e.g. "spotV4" | "perpFuturesUSDTV4" | "perpFuturesBTCV4" | "deliveryFuturesUSDTV4" | "deliveryFuturesBTCV4" | "optionsV4")
* @param channel - The channel this event is for (e.g. "spot.login" to authenticate)
* @param params - Any request parameters for the payload. Signature generation is automatic, only send parameters such as order ID as per the docs.
* @param params - Any request parameters for the payload (contents of req_param in the docs). Signature generation is automatic, only send parameters such as order ID as per the docs.
* @returns Promise - tries to resolve with async WS API response. Rejects if disconnected or exception is seen in async WS API response
*/
async sendWSAPIRequest<
TWSAPIResponse = object,
TRequestParams extends object | string = object,
TWSKey extends keyof WsAPIWsKeyTopicMap = keyof WsAPIWsKeyTopicMap,
TWSChannel extends string = WsAPIWsKeyTopicMap[TWSKey],
TWSChannel extends WSAPITopic = WsAPIWsKeyTopicMap[TWSKey],
TWSAPIResponse = object,
>(
wsKey: TWSKey,
channel: TWSChannel,
params?: TRequestParams,
params?: WsAPIRequestsTopicMap[TWSChannel],
): Promise<TWSAPIResponse> {
this.logger.trace(`sendWSAPIRequest(): assert "${wsKey}" is connected`);
await this.assertIsConnected(wsKey);

const signTimestamp = Date.now() + this.options.recvWindow;
const timeInSeconds = +(signTimestamp / 1000).toFixed(0);

const requestEvent: WSAPIRequest<TRequestParams> = {
const requestEvent: WSAPIRequest<WsAPIRequestsTopicMap[TWSChannel]> = {
time: timeInSeconds,
// id: timeInSeconds,
channel,
Expand All @@ -808,7 +809,7 @@ export class WebsocketClient extends BaseWebsocketClient<WsKey> {
'X-Gate-Channel-Id': CHANNEL_ID,
},
api_key: this.options.apiKey,
req_param: params ? params : '', // should this be string, not sure
req_param: params ? params : '',
timestamp: `${timeInSeconds}`,
},
};
Expand Down
9 changes: 3 additions & 6 deletions src/lib/BaseWSClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,11 @@ export abstract class BaseWebsocketClient<
return `${++this.wsApiRequestId}`;
}

protected abstract sendWSAPIRequest<
TRequestParams extends object | string = object,
TWSAPIResult = object,
>(
protected abstract sendWSAPIRequest(
wsKey: TWSKey,
channel: string,
params?: TRequestParams,
): Promise<TWSAPIResult>;
params?: object | undefined | string,
): Promise<unknown>;

/**
* Don't call directly! Use subscribe() instead!
Expand Down
8 changes: 8 additions & 0 deletions src/types/request/futures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ export interface submitFuturesBatchOrdersReq extends FuturesOrder {
settle: 'btc' | 'usdt' | 'usd';
}

export interface UpdateFuturesOrderReq {
settle: 'btc' | 'usdt' | 'usd';
order_id: string;
size?: number;
price?: string;
amend_text?: string;
}

export interface GetFuturesTradingHistoryReq {
settle: 'btc' | 'usdt' | 'usd';
contract?: string;
Expand Down
6 changes: 6 additions & 0 deletions src/types/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ export interface Order {
action_mode?: 'ACK' | 'RESULT' | 'FULL';
}

export interface GetSingleOrderReq {
order_id: string;
currency_pair: string;
account?: 'spot' | 'margin' | 'cross_margin' | 'unified';
}

export interface CancelBatchOrder {
currency_pair: string;
id: string;
Expand Down
2 changes: 1 addition & 1 deletion src/types/websockets/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface WsRequestOperationGate<
}

export interface WSAPIRequest<
TRequestParams = object | string,
TRequestParams = any,
TWSChannel extends WSAPITopic = any,
> {
time: number;
Expand Down
37 changes: 24 additions & 13 deletions src/types/websockets/wsAPI.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { WsKey } from '../../lib/websocket/websocket-util';
import { GetFuturesOrdersReq, SubmitFuturesOrderReq } from '../request/futures';
import { DeleteSpotOrderReq, SubmitSpotOrderReq } from '../request/spot';
import { CancelBatchOrder, Order } from '../shared';
import {
GetFuturesOrdersReq,
SubmitFuturesOrderReq,
UpdateFuturesOrderReq,
} from '../request/futures';
import {
DeleteSpotOrderReq,
SubmitSpotOrderReq,
UpdateSpotOrderReq,
} from '../request/spot';
import { CancelBatchOrder, GetSingleOrderReq } from '../shared';

export type SpotWSAPITopic =
| 'spot.login'
Expand Down Expand Up @@ -34,30 +42,33 @@ export interface WsAPIWsKeyTopicMap {
// announcementsV4: never;
}

export interface WsAPIRequestsTopicMap {
'spot.login': never;
export type WsAPIRequestsTopicMap = {
'spot.login': undefined;
'spot.order_place': SubmitSpotOrderReq;
'spot.order_cancel': DeleteSpotOrderReq;
'spot.order_cancel_ids': CancelBatchOrder[];
'spot.order_cancel_cp': DeleteSpotOrderReq[];
'spot.order_amend': Order;
'spot.order_status': any;
'futures.login': never;
'futures.order_place': SubmitFuturesOrderReq;
'futures.order_batch_place': SubmitFuturesOrderReq[];
'spot.order_amend': UpdateSpotOrderReq;
'spot.order_status': GetSingleOrderReq;
'futures.login': undefined;
'futures.order_place': Omit<SubmitFuturesOrderReq, 'settle'>; // doesn't seem like "settle" is needed here
'futures.order_batch_place': Omit<SubmitFuturesOrderReq, 'settle'>[];
'futures.order_cancel': {
order_id: string;
};
'futures.order_cancel_cp': {
contract: string;
side?: 'ask' | 'bid';
};
'futures.order_amend': any;
'futures.order_list': GetFuturesOrdersReq;
'futures.order_amend': Omit<UpdateFuturesOrderReq, 'settle'>;
'futures.order_list': Omit<GetFuturesOrdersReq, 'settle'>;
'futures.order_status': {
order_id: string;
};
}
};

export type WsAPIRequestParams =
WsAPIRequestsTopicMap[keyof WsAPIRequestsTopicMap];

export interface WSAPIResponseHeader<TChannel extends WSAPITopic> {
/** String timestamp as ms */
Expand Down

0 comments on commit 635b33f

Please sign in to comment.