@zebpay_rajesh/zebpay-mcp-server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @zebpay_rajesh/zebpay-mcp-server might be problematic. Click here for more details.

Files changed (120) hide show
  1. package/.env.example +14 -0
  2. package/README.md +223 -0
  3. package/dist/__tests__/errors.test.d.ts +5 -0
  4. package/dist/__tests__/errors.test.js +147 -0
  5. package/dist/__tests__/errors.test.js.map +1 -0
  6. package/dist/__tests__/prompts.test.d.ts +1 -0
  7. package/dist/__tests__/prompts.test.js +73 -0
  8. package/dist/__tests__/prompts.test.js.map +1 -0
  9. package/dist/__tests__/resources.test.d.ts +1 -0
  10. package/dist/__tests__/resources.test.js +79 -0
  11. package/dist/__tests__/resources.test.js.map +1 -0
  12. package/dist/__tests__/validation.test.d.ts +15 -0
  13. package/dist/__tests__/validation.test.js +64 -0
  14. package/dist/__tests__/validation.test.js.map +1 -0
  15. package/dist/config.d.ts +19 -0
  16. package/dist/config.js +81 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/http/httpClient.d.ts +40 -0
  19. package/dist/http/httpClient.js +341 -0
  20. package/dist/http/httpClient.js.map +1 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +60 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/mcp/errors.d.ts +21 -0
  25. package/dist/mcp/errors.js +214 -0
  26. package/dist/mcp/errors.js.map +1 -0
  27. package/dist/mcp/logging.d.ts +21 -0
  28. package/dist/mcp/logging.js +241 -0
  29. package/dist/mcp/logging.js.map +1 -0
  30. package/dist/mcp/prompts.d.ts +9 -0
  31. package/dist/mcp/prompts.js +165 -0
  32. package/dist/mcp/prompts.js.map +1 -0
  33. package/dist/mcp/resources.d.ts +9 -0
  34. package/dist/mcp/resources.js +125 -0
  35. package/dist/mcp/resources.js.map +1 -0
  36. package/dist/mcp/tools_futures.d.ts +5 -0
  37. package/dist/mcp/tools_futures.js +694 -0
  38. package/dist/mcp/tools_futures.js.map +1 -0
  39. package/dist/mcp/tools_spot.d.ts +11 -0
  40. package/dist/mcp/tools_spot.js +2225 -0
  41. package/dist/mcp/tools_spot.js.map +1 -0
  42. package/dist/private/FuturesClient.d.ts +57 -0
  43. package/dist/private/FuturesClient.js +181 -0
  44. package/dist/private/FuturesClient.js.map +1 -0
  45. package/dist/private/SpotClient.d.ts +44 -0
  46. package/dist/private/SpotClient.js +201 -0
  47. package/dist/private/SpotClient.js.map +1 -0
  48. package/dist/private/ZebpayAPI.d.ts +19 -0
  49. package/dist/private/ZebpayAPI.js +172 -0
  50. package/dist/private/ZebpayAPI.js.map +1 -0
  51. package/dist/public/PublicClient.d.ts +79 -0
  52. package/dist/public/PublicClient.js +283 -0
  53. package/dist/public/PublicClient.js.map +1 -0
  54. package/dist/public/PublicFuturesClient.d.ts +27 -0
  55. package/dist/public/PublicFuturesClient.js +187 -0
  56. package/dist/public/PublicFuturesClient.js.map +1 -0
  57. package/dist/security/credentials.d.ts +42 -0
  58. package/dist/security/credentials.js +80 -0
  59. package/dist/security/credentials.js.map +1 -0
  60. package/dist/security/signing.d.ts +33 -0
  61. package/dist/security/signing.js +56 -0
  62. package/dist/security/signing.js.map +1 -0
  63. package/dist/types/responses.d.ts +130 -0
  64. package/dist/types/responses.js +6 -0
  65. package/dist/types/responses.js.map +1 -0
  66. package/dist/utils/cache.d.ts +29 -0
  67. package/dist/utils/cache.js +72 -0
  68. package/dist/utils/cache.js.map +1 -0
  69. package/dist/utils/fileLogger.d.ts +10 -0
  70. package/dist/utils/fileLogger.js +81 -0
  71. package/dist/utils/fileLogger.js.map +1 -0
  72. package/dist/utils/metrics.d.ts +35 -0
  73. package/dist/utils/metrics.js +94 -0
  74. package/dist/utils/metrics.js.map +1 -0
  75. package/dist/utils/responseFormatter.d.ts +93 -0
  76. package/dist/utils/responseFormatter.js +268 -0
  77. package/dist/utils/responseFormatter.js.map +1 -0
  78. package/dist/validation/schemas.d.ts +70 -0
  79. package/dist/validation/schemas.js +48 -0
  80. package/dist/validation/schemas.js.map +1 -0
  81. package/dist/validation/validators.d.ts +28 -0
  82. package/dist/validation/validators.js +129 -0
  83. package/dist/validation/validators.js.map +1 -0
  84. package/docs/LOGGING.md +371 -0
  85. package/docs/zebpay-ai-trading-beginner.png +0 -0
  86. package/mcp-config.json.example +20 -0
  87. package/package.json +54 -0
  88. package/scripts/README.md +103 -0
  89. package/scripts/clear-logs.js +52 -0
  90. package/scripts/log-stats.js +264 -0
  91. package/scripts/log-viewer.js +288 -0
  92. package/server.json +31 -0
  93. package/src/__tests__/errors.test.ts +180 -0
  94. package/src/__tests__/prompts.test.ts +89 -0
  95. package/src/__tests__/resources.test.ts +95 -0
  96. package/src/__tests__/validation.test.ts +88 -0
  97. package/src/config.ts +108 -0
  98. package/src/http/httpClient.ts +398 -0
  99. package/src/index.ts +71 -0
  100. package/src/mcp/errors.ts +262 -0
  101. package/src/mcp/logging.ts +284 -0
  102. package/src/mcp/prompts.ts +206 -0
  103. package/src/mcp/resources.ts +163 -0
  104. package/src/mcp/tools_futures.ts +874 -0
  105. package/src/mcp/tools_spot.ts +2702 -0
  106. package/src/private/FuturesClient.ts +189 -0
  107. package/src/private/SpotClient.ts +250 -0
  108. package/src/private/ZebpayAPI.ts +205 -0
  109. package/src/public/PublicClient.ts +381 -0
  110. package/src/public/PublicFuturesClient.ts +228 -0
  111. package/src/security/credentials.ts +114 -0
  112. package/src/security/signing.ts +98 -0
  113. package/src/types/responses.ts +146 -0
  114. package/src/utils/cache.ts +90 -0
  115. package/src/utils/fileLogger.ts +88 -0
  116. package/src/utils/metrics.ts +135 -0
  117. package/src/utils/responseFormatter.ts +361 -0
  118. package/src/validation/schemas.ts +66 -0
  119. package/src/validation/validators.ts +189 -0
  120. package/tsconfig.json +21 -0
@@ -0,0 +1,381 @@
1
+ /*
2
+ Public client for market data and public endpoints (no authentication required).
3
+ */
4
+
5
+ import { HttpClient, HttpError } from "../http/httpClient.js";
6
+ import { AppConfig } from "../config.js";
7
+ import { tickerCache, orderBookCache, exchangeInfoCache, currenciesCache } from "../utils/cache.js";
8
+ import { convertHttpErrorToMcpError } from "../mcp/errors.js";
9
+ import { McpError } from "@modelcontextprotocol/sdk/types.js";
10
+
11
+ export interface TickerParams {
12
+ symbol: string; // Required symbol for single ticker
13
+ }
14
+
15
+ export interface OrderBookParams {
16
+ symbol: string; // Required symbol for order book
17
+ limit?: number; // Optional limit for depth (default usually 100)
18
+ }
19
+
20
+ export interface OrderBookTickerParams {
21
+ symbol: string; // Required symbol for order book ticker
22
+ }
23
+
24
+ export interface TradesParams {
25
+ symbol: string; // Required symbol for trades
26
+ limit?: number; // Optional limit for number of trades
27
+ page?: number; // Optional page number for pagination
28
+ }
29
+
30
+ export interface KlineParams {
31
+ symbol: string; // Required symbol
32
+ interval: string; // e.g., "1m", "5m", "1h", "1d"
33
+ startTime: number; // Required start timestamp
34
+ endTime: number; // Required end timestamp
35
+ limit?: number; // Optional limit
36
+ category?: string; // Optional category (e.g., "spot")
37
+ }
38
+
39
+ export interface MarketTickerParams {
40
+ symbol: string; // Required symbol for market ticker
41
+ group?: string; // Optional group parameter (e.g., "singapore")
42
+ }
43
+
44
+ export interface MarketBookParams {
45
+ symbol: string; // Required symbol for market book
46
+ converted?: number; // Optional converted parameter (0 or 1)
47
+ }
48
+
49
+ export class PublicClient {
50
+ constructor(
51
+ private readonly config: AppConfig,
52
+ private readonly http: HttpClient
53
+ ) {}
54
+
55
+ private buildUrl(path: string, queryParams?: Record<string, string>): string {
56
+ const trimmed = path.startsWith("/") ? path : `/${path}`;
57
+ let url = `${this.config.spotBaseUrl}${trimmed}`;
58
+
59
+ if (queryParams && Object.keys(queryParams).length > 0) {
60
+ const queryString = Object.entries(queryParams)
61
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
62
+ .join("&");
63
+ url += `?${queryString}`;
64
+ }
65
+
66
+ return url;
67
+ }
68
+
69
+ private buildMarketUrl(path: string, queryParams?: Record<string, string>): string {
70
+ // Market API uses configurable base URL from config
71
+ const trimmed = path.startsWith("/") ? path : `/${path}`;
72
+ let url = `${this.config.marketBaseUrl}${trimmed}`;
73
+
74
+ if (queryParams && Object.keys(queryParams).length > 0) {
75
+ const queryString = Object.entries(queryParams)
76
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
77
+ .join("&");
78
+ url += `?${queryString}`;
79
+ }
80
+
81
+ return url;
82
+ }
83
+
84
+ /**
85
+ * Helper method to handle HTTP requests with consistent error handling
86
+ */
87
+ private async handleRequest<T = unknown>(
88
+ requestFn: () => Promise<{ data: T }>
89
+ ): Promise<T> {
90
+ try {
91
+ const response = await requestFn();
92
+ return response.data;
93
+ } catch (err) {
94
+ if (err instanceof HttpError) {
95
+ // Extract error message from various possible response formats
96
+ let errorMessage = err.message || "Unknown API error";
97
+
98
+ if (err.details) {
99
+ if (typeof err.details === "string") {
100
+ errorMessage = err.details;
101
+ } else if (typeof err.details === "object") {
102
+ // Check common error response fields (in order of preference)
103
+ const details = err.details as Record<string, unknown>;
104
+ errorMessage =
105
+ (typeof details.statusDescription === "string" && details.statusDescription) ||
106
+ (typeof details.error === "string" && details.error) ||
107
+ (typeof details.message === "string" && details.message) ||
108
+ (typeof details.msg === "string" && details.msg) ||
109
+ (typeof details.errorMessage === "string" && details.errorMessage) ||
110
+ errorMessage;
111
+ }
112
+ }
113
+
114
+ throw convertHttpErrorToMcpError(err.status, errorMessage, err.details);
115
+ }
116
+ // Re-throw MCP errors as-is
117
+ if (err instanceof McpError) {
118
+ throw err;
119
+ }
120
+ // Re-throw other errors
121
+ throw err;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Get all tickers from Zebpay API.
127
+ * Endpoint: GET /api/v2/market/allTickers
128
+ */
129
+ async getAllTickers(): Promise<unknown> {
130
+ const cacheKey = "allTickers";
131
+ const cached = tickerCache.get(cacheKey);
132
+ if (cached) {
133
+ return cached;
134
+ }
135
+
136
+ const path = "/market/allTickers";
137
+ const url = this.buildUrl(path);
138
+ const data = await this.handleRequest(() =>
139
+ this.http.request({
140
+ method: "GET",
141
+ url,
142
+ timeoutMs: this.config.timeoutMs,
143
+ retryCount: this.config.retryCount,
144
+ })
145
+ );
146
+
147
+ tickerCache.set(cacheKey, data);
148
+ return data;
149
+ }
150
+
151
+ /**
152
+ * Get ticker for a specific symbol from Zebpay API.
153
+ * Endpoint: GET /api/v2/market/ticker?symbol={symbol}
154
+ */
155
+ async getTicker(params: TickerParams): Promise<unknown> {
156
+ const cacheKey = `ticker:${params.symbol}`;
157
+ const cached = tickerCache.get(cacheKey);
158
+ if (cached) {
159
+ return cached;
160
+ }
161
+
162
+ const path = "/market/ticker";
163
+ const queryParams: Record<string, string> = {
164
+ symbol: params.symbol,
165
+ };
166
+
167
+ const url = this.buildUrl(path, queryParams);
168
+ const data = await this.handleRequest(() =>
169
+ this.http.request({
170
+ method: "GET",
171
+ url,
172
+ timeoutMs: this.config.timeoutMs,
173
+ retryCount: this.config.retryCount,
174
+ })
175
+ );
176
+
177
+ tickerCache.set(cacheKey, data);
178
+ return data;
179
+ }
180
+
181
+ async getOrderBook(params: OrderBookParams): Promise<unknown> {
182
+ const cacheKey = `orderbook:${params.symbol}:${params.limit || "default"}`;
183
+ const cached = orderBookCache.get(cacheKey);
184
+ if (cached) {
185
+ return cached;
186
+ }
187
+
188
+ const path = "/market/orderbook";
189
+ const queryParams: Record<string, string> = {
190
+ symbol: params.symbol,
191
+ };
192
+ if (params.limit !== undefined) {
193
+ queryParams.limit = params.limit.toString();
194
+ }
195
+
196
+ const url = this.buildUrl(path, queryParams);
197
+ const data = await this.handleRequest(() =>
198
+ this.http.request({
199
+ method: "GET",
200
+ url,
201
+ timeoutMs: this.config.timeoutMs,
202
+ retryCount: this.config.retryCount,
203
+ })
204
+ );
205
+
206
+ orderBookCache.set(cacheKey, data);
207
+ return data;
208
+ }
209
+
210
+ /**
211
+ * Get order book ticker for a specific symbol from Zebpay API.
212
+ * Endpoint: GET /api/v2/market/orderbook/ticker?symbol={symbol}
213
+ */
214
+ async getOrderBookTicker(params: OrderBookTickerParams): Promise<unknown> {
215
+ const path = "/market/orderbook/ticker";
216
+ const queryParams: Record<string, string> = {
217
+ symbol: params.symbol,
218
+ };
219
+
220
+ const url = this.buildUrl(path, queryParams);
221
+ return this.handleRequest(() =>
222
+ this.http.request({
223
+ method: "GET",
224
+ url,
225
+ timeoutMs: this.config.timeoutMs,
226
+ retryCount: this.config.retryCount,
227
+ })
228
+ );
229
+ }
230
+
231
+ async getTrades(params: TradesParams): Promise<unknown> {
232
+ const path = "/market/trades";
233
+ const queryParams: Record<string, string> = {
234
+ symbol: params.symbol,
235
+ };
236
+ if (params.limit !== undefined) {
237
+ queryParams.limit = params.limit.toString();
238
+ }
239
+ if (params.page !== undefined) {
240
+ queryParams.page = params.page.toString();
241
+ }
242
+
243
+ const url = this.buildUrl(path, queryParams);
244
+ return this.handleRequest(() =>
245
+ this.http.request({
246
+ method: "GET",
247
+ url,
248
+ timeoutMs: this.config.timeoutMs,
249
+ retryCount: this.config.retryCount,
250
+ })
251
+ );
252
+ }
253
+
254
+ async getKlines(params: KlineParams): Promise<unknown> {
255
+ const path = "/market/klines";
256
+ const queryParams: Record<string, string> = {
257
+ symbol: params.symbol,
258
+ interval: params.interval,
259
+ startTime: params.startTime.toString(),
260
+ endTime: params.endTime.toString(),
261
+ };
262
+ if (params.limit !== undefined) {
263
+ queryParams.limit = params.limit.toString();
264
+ }
265
+ if (params.category !== undefined) {
266
+ queryParams.category = params.category;
267
+ }
268
+
269
+ const url = this.buildUrl(path, queryParams);
270
+ return this.handleRequest(() =>
271
+ this.http.request({
272
+ method: "GET",
273
+ url,
274
+ timeoutMs: this.config.timeoutMs,
275
+ retryCount: this.config.retryCount,
276
+ })
277
+ );
278
+ }
279
+
280
+ async getExchangeInfo(): Promise<unknown> {
281
+ const cacheKey = "exchangeInfo";
282
+ const cached = exchangeInfoCache.get(cacheKey);
283
+ if (cached) {
284
+ return cached;
285
+ }
286
+
287
+ const path = "/ex/exchangeInfo";
288
+ const url = this.buildUrl(path);
289
+ const data = await this.handleRequest(() =>
290
+ this.http.request({
291
+ method: "GET",
292
+ url,
293
+ timeoutMs: this.config.timeoutMs,
294
+ retryCount: this.config.retryCount,
295
+ })
296
+ );
297
+
298
+ exchangeInfoCache.set(cacheKey, data);
299
+ return data;
300
+ }
301
+
302
+ async getCurrencies(): Promise<unknown> {
303
+ const cacheKey = "currencies";
304
+ const cached = currenciesCache.get(cacheKey);
305
+ if (cached) {
306
+ return cached;
307
+ }
308
+
309
+ const path = "/ex/currencies";
310
+ const url = this.buildUrl(path);
311
+ const data = await this.handleRequest(() =>
312
+ this.http.request({
313
+ method: "GET",
314
+ url,
315
+ timeoutMs: this.config.timeoutMs,
316
+ retryCount: this.config.retryCount,
317
+ })
318
+ );
319
+
320
+ currenciesCache.set(cacheKey, data);
321
+ return data;
322
+ }
323
+
324
+ /**
325
+ * Get market information from Zebpay market API.
326
+ * Endpoint: GET /api/v1/market
327
+ */
328
+ async getMarket(): Promise<unknown> {
329
+ const path = "";
330
+ const url = this.buildMarketUrl(path);
331
+ return this.handleRequest(() =>
332
+ this.http.request({
333
+ method: "GET",
334
+ url,
335
+ timeoutMs: this.config.timeoutMs,
336
+ retryCount: this.config.retryCount,
337
+ })
338
+ );
339
+ }
340
+
341
+ /**
342
+ * Get ticker for a specific symbol from Zebpay market API.
343
+ * Endpoint: GET /api/v1/market/{symbol}/ticker
344
+ */
345
+ async getMarketTicker(params: MarketTickerParams): Promise<unknown> {
346
+ const path = `/${params.symbol}/ticker`;
347
+ const queryParams: Record<string, string> | undefined = params.group
348
+ ? { group: params.group }
349
+ : undefined;
350
+ const url = this.buildMarketUrl(path, queryParams);
351
+ return this.handleRequest(() =>
352
+ this.http.request({
353
+ method: "GET",
354
+ url,
355
+ timeoutMs: this.config.timeoutMs,
356
+ retryCount: this.config.retryCount,
357
+ })
358
+ );
359
+ }
360
+
361
+ /**
362
+ * Get order book for a specific symbol from Zebpay market API.
363
+ * Endpoint: GET /api/v1/market/{symbol}/book
364
+ */
365
+ async getMarketBook(params: MarketBookParams): Promise<unknown> {
366
+ const path = `/${params.symbol}/book`;
367
+ const queryParams: Record<string, string> | undefined = params.converted !== undefined
368
+ ? { converted: params.converted.toString() }
369
+ : undefined;
370
+ const url = this.buildMarketUrl(path, queryParams);
371
+ return this.handleRequest(() =>
372
+ this.http.request({
373
+ method: "GET",
374
+ url,
375
+ timeoutMs: this.config.timeoutMs,
376
+ retryCount: this.config.retryCount,
377
+ })
378
+ );
379
+ }
380
+ }
381
+
@@ -0,0 +1,228 @@
1
+ /*
2
+ Public futures client for market data (no authentication required).
3
+ */
4
+
5
+ import { HttpClient, HttpError } from "../http/httpClient.js";
6
+ import { AppConfig } from "../config.js";
7
+ import { tickerCache, orderBookCache, exchangeInfoCache } from "../utils/cache.js";
8
+ import { convertHttpErrorToMcpError } from "../mcp/errors.js";
9
+ import { McpError } from "@modelcontextprotocol/sdk/types.js";
10
+
11
+ export interface FuturesSymbolParams {
12
+ symbol: string; // e.g., "BTCUSDT"
13
+ }
14
+
15
+ export interface FuturesOrderBookParams {
16
+ symbol: string; // e.g., "BTCUSDT"
17
+ limit?: number; // optional depth, if supported by API in future
18
+ }
19
+
20
+ export class PublicFuturesClient {
21
+ constructor(
22
+ private readonly config: AppConfig,
23
+ private readonly http: HttpClient
24
+ ) {}
25
+
26
+ private buildUrl(path: string, queryParams?: Record<string, string>): string {
27
+ const trimmed = path.startsWith("/") ? path : `/${path}`;
28
+ let url = `${this.config.futuresBaseUrl}${trimmed}`;
29
+
30
+ if (queryParams && Object.keys(queryParams).length > 0) {
31
+ const queryString = Object.entries(queryParams)
32
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
33
+ .join("&");
34
+ url += `?${queryString}`;
35
+ }
36
+
37
+ return url;
38
+ }
39
+
40
+ private buildRootUrl(path: string): string {
41
+ // Some endpoints (like healthCheckStatus) live at the root host, not under /api/v1
42
+ const base = this.config.futuresBaseUrl.replace(/\/api\/v1\/?$/, "");
43
+ const trimmed = path.startsWith("/") ? path : `/${path}`;
44
+ return `${base}${trimmed}`;
45
+ }
46
+
47
+ private async handleRequest<T = unknown>(
48
+ requestFn: () => Promise<{ data: T }>
49
+ ): Promise<T> {
50
+ try {
51
+ const response = await requestFn();
52
+ return response.data;
53
+ } catch (err) {
54
+ if (err instanceof HttpError) {
55
+ let errorMessage = err.message || "Unknown API error";
56
+ if (err.details) {
57
+ if (typeof err.details === "string") {
58
+ errorMessage = err.details;
59
+ } else if (typeof err.details === "object") {
60
+ const details = err.details as Record<string, unknown>;
61
+ errorMessage =
62
+ (typeof details.statusDescription === "string" && details.statusDescription) ||
63
+ (typeof details.error === "string" && details.error) ||
64
+ (typeof details.message === "string" && details.message) ||
65
+ (typeof details.msg === "string" && details.msg) ||
66
+ (typeof details.errorMessage === "string" && details.errorMessage) ||
67
+ errorMessage;
68
+ }
69
+ }
70
+ throw convertHttpErrorToMcpError(err.status, errorMessage, err.details);
71
+ }
72
+ if (err instanceof McpError) {
73
+ throw err;
74
+ }
75
+ throw err;
76
+ }
77
+ }
78
+
79
+ // GET /healthCheckStatus (root host)
80
+ async getHealthCheckStatus(): Promise<unknown> {
81
+ const url = this.buildRootUrl("/healthCheckStatus");
82
+ return this.handleRequest(() =>
83
+ this.http.request({
84
+ method: "GET",
85
+ url,
86
+ timeoutMs: this.config.timeoutMs,
87
+ retryCount: this.config.retryCount,
88
+ })
89
+ );
90
+ }
91
+
92
+ // GET /api/v1/market/markets
93
+ async getMarkets(): Promise<unknown> {
94
+ const cacheKey = "futures:markets";
95
+ const cached = tickerCache.get(cacheKey);
96
+ if (cached) return cached;
97
+
98
+ const url = this.buildUrl("/market/markets");
99
+ const data = await this.handleRequest(() =>
100
+ this.http.request({
101
+ method: "GET",
102
+ url,
103
+ timeoutMs: this.config.timeoutMs,
104
+ retryCount: this.config.retryCount,
105
+ })
106
+ );
107
+ tickerCache.set(cacheKey, data);
108
+ return data;
109
+ }
110
+
111
+ // GET /api/v1/market/marketInfo
112
+ async getMarketInfo(): Promise<unknown> {
113
+ const cacheKey = "futures:marketInfo";
114
+ const cached = tickerCache.get(cacheKey);
115
+ if (cached) return cached;
116
+
117
+ const url = this.buildUrl("/market/marketInfo");
118
+ const data = await this.handleRequest(() =>
119
+ this.http.request({
120
+ method: "GET",
121
+ url,
122
+ timeoutMs: this.config.timeoutMs,
123
+ retryCount: this.config.retryCount,
124
+ })
125
+ );
126
+ tickerCache.set(cacheKey, data);
127
+ return data;
128
+ }
129
+
130
+ // GET /api/v1/market/orderBook?symbol=BTCUSDT
131
+ async getOrderBook(params: FuturesOrderBookParams): Promise<unknown> {
132
+ const symbol = params.symbol.trim().toUpperCase();
133
+ const cacheKey = `futures:orderbook:${symbol}:${params.limit ?? "default"}`;
134
+ const cached = orderBookCache.get(cacheKey);
135
+ if (cached) return cached;
136
+
137
+ const query: Record<string, string> = { symbol };
138
+ if (params.limit !== undefined) query.limit = String(params.limit);
139
+ const url = this.buildUrl("/market/orderBook", query);
140
+ const data = await this.handleRequest(() =>
141
+ this.http.request({
142
+ method: "GET",
143
+ url,
144
+ timeoutMs: this.config.timeoutMs,
145
+ retryCount: this.config.retryCount,
146
+ })
147
+ );
148
+ orderBookCache.set(cacheKey, data);
149
+ return data;
150
+ }
151
+
152
+ // GET /api/v1/market/ticker24Hr?symbol=BTCUSDT
153
+ async getTicker24Hr(params: FuturesSymbolParams): Promise<unknown> {
154
+ const symbol = params.symbol.trim().toUpperCase();
155
+ const cacheKey = `futures:ticker24h:${symbol}`;
156
+ const cached = tickerCache.get(cacheKey);
157
+ if (cached) return cached;
158
+
159
+ const url = this.buildUrl("/market/ticker24Hr", { symbol });
160
+ const data = await this.handleRequest(() =>
161
+ this.http.request({
162
+ method: "GET",
163
+ url,
164
+ timeoutMs: this.config.timeoutMs,
165
+ retryCount: this.config.retryCount,
166
+ })
167
+ );
168
+ tickerCache.set(cacheKey, data);
169
+ return data;
170
+ }
171
+
172
+ // GET /api/v1/market/aggTrade?symbol=BTCUSDT
173
+ async getAggregateTrades(params: FuturesSymbolParams & { limit?: number }): Promise<unknown> {
174
+ const symbol = params.symbol.trim().toUpperCase();
175
+ const query: Record<string, string> = { symbol };
176
+ if (params.limit !== undefined) query.limit = String(params.limit);
177
+
178
+ const url = this.buildUrl("/market/aggTrade", query);
179
+ return this.handleRequest(() =>
180
+ this.http.request({
181
+ method: "GET",
182
+ url,
183
+ timeoutMs: this.config.timeoutMs,
184
+ retryCount: this.config.retryCount,
185
+ })
186
+ );
187
+ }
188
+
189
+ // GET /api/v1/exchange/exchangeInfo
190
+ async getExchangeInfo(): Promise<unknown> {
191
+ const cacheKey = "futures:exchangeInfo";
192
+ const cached = exchangeInfoCache.get(cacheKey);
193
+ if (cached) return cached;
194
+
195
+ const url = this.buildUrl("/exchange/exchangeInfo");
196
+ const data = await this.handleRequest(() =>
197
+ this.http.request({
198
+ method: "GET",
199
+ url,
200
+ timeoutMs: this.config.timeoutMs,
201
+ retryCount: this.config.retryCount,
202
+ })
203
+ );
204
+ exchangeInfoCache.set(cacheKey, data);
205
+ return data;
206
+ }
207
+
208
+ // GET /api/v1/exchange/pairs
209
+ async getExchangePairs(): Promise<unknown> {
210
+ const cacheKey = "futures:exchangePairs";
211
+ const cached = exchangeInfoCache.get(cacheKey);
212
+ if (cached) return cached;
213
+
214
+ const url = this.buildUrl("/exchange/pairs");
215
+ const data = await this.handleRequest(() =>
216
+ this.http.request({
217
+ method: "GET",
218
+ url,
219
+ timeoutMs: this.config.timeoutMs,
220
+ retryCount: this.config.retryCount,
221
+ })
222
+ );
223
+ exchangeInfoCache.set(cacheKey, data);
224
+ return data;
225
+ }
226
+ }
227
+
228
+