@ctgexchange/sdk 0.1.2
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.
- package/LICENSE +201 -0
- package/README.md +129 -0
- package/dist/index.cjs +576 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +467 -0
- package/dist/index.d.ts +467 -0
- package/dist/index.js +529 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Types for CTG.EXCHANGE API payloads.
|
|
5
|
+
*
|
|
6
|
+
* The API's **decimal contract**: every monetary value — `price`, `qty`,
|
|
7
|
+
* `volume`, fee amounts — is a JSON **string** (`"3500.55"`), never a
|
|
8
|
+
* number. This SDK keeps those fields as `string`: that is lossless and
|
|
9
|
+
* leaves the choice of big-decimal library to you. Never `Number()`
|
|
10
|
+
* them blindly. Basis-point fields, counters, ids and epoch timestamps
|
|
11
|
+
* are real `number`s; `created_at` is an RFC 3339 `string`.
|
|
12
|
+
*/
|
|
13
|
+
/** A trading pair plus its order filters. All money fields are strings. */
|
|
14
|
+
interface SymbolInfo {
|
|
15
|
+
symbol: string;
|
|
16
|
+
base_asset: string;
|
|
17
|
+
quote_asset: string;
|
|
18
|
+
price_scale: number;
|
|
19
|
+
qty_scale: number;
|
|
20
|
+
quote_asset_scale: number;
|
|
21
|
+
tick_size: string;
|
|
22
|
+
step_size: string;
|
|
23
|
+
min_price: string;
|
|
24
|
+
max_price: string;
|
|
25
|
+
min_qty: string;
|
|
26
|
+
max_qty: string;
|
|
27
|
+
min_notional: string;
|
|
28
|
+
}
|
|
29
|
+
/** A 24h rolling ticker. */
|
|
30
|
+
interface Ticker {
|
|
31
|
+
symbol: string;
|
|
32
|
+
price: string;
|
|
33
|
+
open: string;
|
|
34
|
+
high: string;
|
|
35
|
+
low: string;
|
|
36
|
+
close: string;
|
|
37
|
+
/** Base-asset volume. */
|
|
38
|
+
volume: string;
|
|
39
|
+
trades: number;
|
|
40
|
+
change_bps: number;
|
|
41
|
+
/** Epoch timestamp. */
|
|
42
|
+
ts: number;
|
|
43
|
+
}
|
|
44
|
+
/** A single OHLC candle. */
|
|
45
|
+
interface Candle {
|
|
46
|
+
open: string;
|
|
47
|
+
high: string;
|
|
48
|
+
low: string;
|
|
49
|
+
close: string;
|
|
50
|
+
volume: string;
|
|
51
|
+
open_time: number;
|
|
52
|
+
close_time: number;
|
|
53
|
+
trades: number;
|
|
54
|
+
}
|
|
55
|
+
/** One price level of an order book. */
|
|
56
|
+
interface BookLevel {
|
|
57
|
+
price: string;
|
|
58
|
+
qty: string;
|
|
59
|
+
}
|
|
60
|
+
/** A full order book snapshot. */
|
|
61
|
+
interface OrderBook {
|
|
62
|
+
symbol: string;
|
|
63
|
+
last_update_id: number;
|
|
64
|
+
bids: BookLevel[];
|
|
65
|
+
asks: BookLevel[];
|
|
66
|
+
}
|
|
67
|
+
/** A per-asset balance. */
|
|
68
|
+
interface Balance {
|
|
69
|
+
asset: string;
|
|
70
|
+
available: string;
|
|
71
|
+
reserved: string;
|
|
72
|
+
}
|
|
73
|
+
type OrderSide = "buy" | "sell";
|
|
74
|
+
type OrderType = "limit" | "market";
|
|
75
|
+
type OrderStatus = "new" | "open" | "partially_filled" | "filled" | "canceled" | "expired" | "rejected";
|
|
76
|
+
type TimeInForce = "GTC" | "IOC" | "FOK" | "POST_ONLY";
|
|
77
|
+
/** Fraction of a charged fee credited to a referrer. */
|
|
78
|
+
interface FeeRebate {
|
|
79
|
+
/** Referrer wallet address. */
|
|
80
|
+
account_id?: string;
|
|
81
|
+
/** Share of the fee in basis points. */
|
|
82
|
+
fraction_bps?: number;
|
|
83
|
+
}
|
|
84
|
+
/** An order. */
|
|
85
|
+
interface Order {
|
|
86
|
+
/** Canonical server id (UUIDv7). */
|
|
87
|
+
id: string;
|
|
88
|
+
/** Client-supplied idempotency key. */
|
|
89
|
+
client_order_id?: string;
|
|
90
|
+
/** Owner wallet address. */
|
|
91
|
+
uid?: string;
|
|
92
|
+
symbol: string;
|
|
93
|
+
side: OrderSide;
|
|
94
|
+
type: OrderType;
|
|
95
|
+
time_in_force?: TimeInForce;
|
|
96
|
+
status: OrderStatus;
|
|
97
|
+
price: string;
|
|
98
|
+
avg_execution_price?: string;
|
|
99
|
+
qty: string;
|
|
100
|
+
filled_qty: string;
|
|
101
|
+
remaining_qty: string;
|
|
102
|
+
/** Total fee paid, a decimal string in the scale of `fee_asset`. */
|
|
103
|
+
fee_amount?: string;
|
|
104
|
+
fee_asset?: string;
|
|
105
|
+
/** Per-order taker fee override in bps; 0 = global default. */
|
|
106
|
+
taker_fee_bps?: number;
|
|
107
|
+
/** Per-order maker fee override in bps; 0 = global default. */
|
|
108
|
+
maker_fee_bps?: number;
|
|
109
|
+
rebate?: FeeRebate;
|
|
110
|
+
created_at: string;
|
|
111
|
+
updated_at?: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A matched trade. Both sides' addresses, order ids and fees are
|
|
115
|
+
* exposed — see "matcher transparency".
|
|
116
|
+
*/
|
|
117
|
+
interface Trade {
|
|
118
|
+
id: string;
|
|
119
|
+
symbol: string;
|
|
120
|
+
price: string;
|
|
121
|
+
qty: string;
|
|
122
|
+
/** Side of the taker (aggressor) order. */
|
|
123
|
+
aggressor_side?: OrderSide;
|
|
124
|
+
maker_order_id?: string;
|
|
125
|
+
taker_order_id?: string;
|
|
126
|
+
buy_order_id?: string;
|
|
127
|
+
sell_order_id?: string;
|
|
128
|
+
/** Buyer wallet address. */
|
|
129
|
+
buy_uid?: string;
|
|
130
|
+
/** Seller wallet address. */
|
|
131
|
+
sell_uid?: string;
|
|
132
|
+
/** Effective buyer fee in bps; omitted when 0. */
|
|
133
|
+
buy_fee_bps?: number;
|
|
134
|
+
/** Effective seller fee in bps; omitted when 0. */
|
|
135
|
+
sell_fee_bps?: number;
|
|
136
|
+
buy_rebate?: FeeRebate;
|
|
137
|
+
sell_rebate?: FeeRebate;
|
|
138
|
+
buy_fee_amount?: string;
|
|
139
|
+
buy_fee_asset?: string;
|
|
140
|
+
sell_fee_amount?: string;
|
|
141
|
+
sell_fee_asset?: string;
|
|
142
|
+
created_at?: string;
|
|
143
|
+
}
|
|
144
|
+
/** A referral rebate entry. */
|
|
145
|
+
interface Rebate {
|
|
146
|
+
referrer_account: string;
|
|
147
|
+
fraction_bps: number;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A fee / rebate snapshot. A `null` integer means no override applies —
|
|
151
|
+
* the platform default is then in effect.
|
|
152
|
+
*/
|
|
153
|
+
interface UserFees {
|
|
154
|
+
taker_fee_bps: number | null;
|
|
155
|
+
maker_fee_bps: number | null;
|
|
156
|
+
rebate: Rebate | null;
|
|
157
|
+
}
|
|
158
|
+
/** The result of placing an order: the order plus any immediate fills. */
|
|
159
|
+
interface PlaceOrderResult {
|
|
160
|
+
order: Order;
|
|
161
|
+
trades: Trade[];
|
|
162
|
+
}
|
|
163
|
+
/** Parameters for placing an order. */
|
|
164
|
+
interface PlaceOrderParams {
|
|
165
|
+
side: OrderSide;
|
|
166
|
+
type: OrderType;
|
|
167
|
+
/** Decimal string (recommended) or number. */
|
|
168
|
+
price?: string | number;
|
|
169
|
+
/** Decimal string (recommended) or number. */
|
|
170
|
+
qty?: string | number;
|
|
171
|
+
/** Optional idempotency key; one is generated when omitted. */
|
|
172
|
+
clientOrderId?: string;
|
|
173
|
+
}
|
|
174
|
+
/** Parameters for modifying an order — send both for the API to accept. */
|
|
175
|
+
interface ModifyOrderParams {
|
|
176
|
+
newPrice?: string | number;
|
|
177
|
+
newQty?: string | number;
|
|
178
|
+
}
|
|
179
|
+
/** A parsed server WebSocket message: a `snapshot` or an `update`. */
|
|
180
|
+
interface StreamMessage {
|
|
181
|
+
type: "snapshot" | "update";
|
|
182
|
+
channel: string;
|
|
183
|
+
symbol?: string;
|
|
184
|
+
data: unknown;
|
|
185
|
+
/** The full raw frame. */
|
|
186
|
+
raw: Record<string, unknown>;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* REST client for the CTG.EXCHANGE API.
|
|
191
|
+
*
|
|
192
|
+
* Covers the whole `/api/v1` REST surface: public market data plus the
|
|
193
|
+
* private, API-key-signed account and order endpoints.
|
|
194
|
+
*
|
|
195
|
+
* const client = new Client({ apiKey, apiSecret });
|
|
196
|
+
* const book = await client.getOrderBook("CTGUSDT");
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
declare const DEFAULT_BASE_URL = "https://api.ctg.exchange";
|
|
200
|
+
/** A `fetch`-compatible function — injectable for testing. */
|
|
201
|
+
type FetchLike = (url: string, init: RequestInit) => Promise<Response>;
|
|
202
|
+
interface ClientOptions {
|
|
203
|
+
/** Key id (`ak_...`). Required only for private endpoints. */
|
|
204
|
+
apiKey?: string;
|
|
205
|
+
/** Key secret (`sk_...`). Required only for private endpoints. */
|
|
206
|
+
apiSecret?: string;
|
|
207
|
+
/** REST base URL. Defaults to production. */
|
|
208
|
+
baseUrl?: string;
|
|
209
|
+
/** Per-request timeout in milliseconds. Default 10000. */
|
|
210
|
+
timeoutMs?: number;
|
|
211
|
+
/** How many times to retry a `429`, honouring `Retry-After`. Default 0. */
|
|
212
|
+
maxRetries?: number;
|
|
213
|
+
/** A `fetch` implementation. Defaults to the global `fetch`. */
|
|
214
|
+
fetch?: FetchLike;
|
|
215
|
+
}
|
|
216
|
+
/** A REST client for the CTG.EXCHANGE API. */
|
|
217
|
+
declare class Client {
|
|
218
|
+
private readonly apiKey?;
|
|
219
|
+
private readonly apiSecret?;
|
|
220
|
+
private readonly baseUrl;
|
|
221
|
+
private readonly timeoutMs;
|
|
222
|
+
private readonly maxRetries;
|
|
223
|
+
private readonly fetchImpl;
|
|
224
|
+
constructor(options?: ClientOptions);
|
|
225
|
+
private buildRequestUri;
|
|
226
|
+
private request;
|
|
227
|
+
/** All trading symbols with their order filters. */
|
|
228
|
+
getSymbols(): Promise<SymbolInfo[]>;
|
|
229
|
+
/** 24h ticker for every symbol. */
|
|
230
|
+
getTickers(): Promise<Ticker[]>;
|
|
231
|
+
/** Current order book for `symbol`. */
|
|
232
|
+
getOrderBook(symbol: string): Promise<OrderBook>;
|
|
233
|
+
/** 24h ticker for `symbol`. */
|
|
234
|
+
getTicker(symbol: string): Promise<Ticker>;
|
|
235
|
+
/**
|
|
236
|
+
* Candles for `symbol` at `interval` (`1m` / `5m` / `15m` / `1h` /
|
|
237
|
+
* `4h` / `1d`).
|
|
238
|
+
*
|
|
239
|
+
* Omit `from` / `to` for the latest `limit` candles. Pass `from` /
|
|
240
|
+
* `to` (Unix ms) to select a historical window `[from, to)` for
|
|
241
|
+
* scrollback.
|
|
242
|
+
*/
|
|
243
|
+
getCandles(symbol: string, interval?: string, opts?: {
|
|
244
|
+
limit?: number;
|
|
245
|
+
from?: number;
|
|
246
|
+
to?: number;
|
|
247
|
+
}): Promise<Candle[]>;
|
|
248
|
+
/** Recent public trade prints for `symbol`. */
|
|
249
|
+
getTrades(symbol: string, limit?: number): Promise<Trade[]>;
|
|
250
|
+
/** Per-asset balances for the API key's owner (scope: read). */
|
|
251
|
+
getBalances(): Promise<Balance[]>;
|
|
252
|
+
/** Fee/rebate snapshot for the API key's owner (scope: read). */
|
|
253
|
+
getFees(): Promise<UserFees>;
|
|
254
|
+
/**
|
|
255
|
+
* Place an order (scope: trade).
|
|
256
|
+
*
|
|
257
|
+
* A `clientOrderId` is generated when you do not supply one — it lets
|
|
258
|
+
* the engine de-dup on safe retries.
|
|
259
|
+
*/
|
|
260
|
+
placeOrder(symbol: string, params: PlaceOrderParams): Promise<PlaceOrderResult>;
|
|
261
|
+
/** List the owner's orders for `symbol` (scope: read). */
|
|
262
|
+
getOrders(symbol: string, opts?: {
|
|
263
|
+
status?: OrderStatus;
|
|
264
|
+
limit?: number;
|
|
265
|
+
offset?: number;
|
|
266
|
+
}): Promise<Order[]>;
|
|
267
|
+
/**
|
|
268
|
+
* List every open order across all symbols (scope: read).
|
|
269
|
+
*
|
|
270
|
+
* Each `Order` carries its own `symbol`; decimal fields are converted
|
|
271
|
+
* per that order's scales. For closed-order history use `getOrders`
|
|
272
|
+
* per symbol.
|
|
273
|
+
*/
|
|
274
|
+
getOpenOrders(): Promise<Order[]>;
|
|
275
|
+
/** Get one order by its canonical server id (scope: read). */
|
|
276
|
+
getOrder(symbol: string, orderId: string): Promise<Order>;
|
|
277
|
+
/** Cancel one order (scope: trade). */
|
|
278
|
+
cancelOrder(symbol: string, orderId: string): Promise<Order>;
|
|
279
|
+
/** Cancel every open order for `symbol` (scope: trade). */
|
|
280
|
+
cancelAllOrders(symbol: string): Promise<Order[]>;
|
|
281
|
+
/**
|
|
282
|
+
* Modify a resting order's price and quantity (scope: trade).
|
|
283
|
+
*
|
|
284
|
+
* The API expects the full new state — pass both `newPrice` and
|
|
285
|
+
* `newQty`.
|
|
286
|
+
*/
|
|
287
|
+
modifyOrder(symbol: string, orderId: string, params: ModifyOrderParams): Promise<Order>;
|
|
288
|
+
/** The owner's trade history for `symbol` (scope: read). */
|
|
289
|
+
getMyTrades(symbol: string, opts?: {
|
|
290
|
+
limit?: number;
|
|
291
|
+
offset?: number;
|
|
292
|
+
}): Promise<Trade[]>;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* WebSocket clients for the CTG.EXCHANGE streams.
|
|
297
|
+
*
|
|
298
|
+
* - {@link MarketDataStream} — public market data, no auth.
|
|
299
|
+
* - {@link UserStream} — the caller's private `orders` / `trades` /
|
|
300
|
+
* `balances`, authenticated in-band with a signed first frame.
|
|
301
|
+
*
|
|
302
|
+
* Both auto-reconnect by default and re-send their subscriptions on
|
|
303
|
+
* every (re)connect, so a dropped socket is transparent to the
|
|
304
|
+
* consumer:
|
|
305
|
+
*
|
|
306
|
+
* const stream = new MarketDataStream({ channels: ["trades@CTGUSDT"] });
|
|
307
|
+
* for await (const msg of stream) {
|
|
308
|
+
* console.log(msg.channel, msg.type, msg.data);
|
|
309
|
+
* }
|
|
310
|
+
*/
|
|
311
|
+
|
|
312
|
+
declare const DEFAULT_WS_BASE_URL = "wss://api.ctg.exchange";
|
|
313
|
+
/**
|
|
314
|
+
* Parse a raw frame into a {@link StreamMessage}, or `null` for control
|
|
315
|
+
* frames (auth replies, subscribe acks) — only data frames are surfaced.
|
|
316
|
+
*/
|
|
317
|
+
declare function parseFrame(raw: string): StreamMessage | null;
|
|
318
|
+
interface StreamOptions {
|
|
319
|
+
/** WebSocket base URL. Defaults to production. */
|
|
320
|
+
baseUrl?: string;
|
|
321
|
+
/** Channels to subscribe to on every (re)connect. */
|
|
322
|
+
channels?: Iterable<string>;
|
|
323
|
+
/** Auto-reconnect on a dropped socket. Default `true`. */
|
|
324
|
+
reconnect?: boolean;
|
|
325
|
+
/** Delay before a reconnect attempt, in milliseconds. Default 2000. */
|
|
326
|
+
reconnectDelayMs?: number;
|
|
327
|
+
}
|
|
328
|
+
/** Shared connect / subscribe / reconnect machinery. */
|
|
329
|
+
declare abstract class BaseStream implements AsyncIterable<StreamMessage> {
|
|
330
|
+
private readonly url;
|
|
331
|
+
private readonly channels;
|
|
332
|
+
private reconnect;
|
|
333
|
+
private readonly reconnectDelayMs;
|
|
334
|
+
private ws;
|
|
335
|
+
private closed;
|
|
336
|
+
private queue;
|
|
337
|
+
private socketEnded;
|
|
338
|
+
private resolveNext;
|
|
339
|
+
protected constructor(path: string, options: StreamOptions);
|
|
340
|
+
/** No-op for the public stream; overridden by {@link UserStream}. */
|
|
341
|
+
protected authenticate(_ws: WebSocket): Promise<void>;
|
|
342
|
+
/** Close the socket and stop reconnecting. */
|
|
343
|
+
close(): void;
|
|
344
|
+
/** Add channels (e.g. `orderbook@CTGUSDT`). Kept across reconnects. */
|
|
345
|
+
subscribe(channels: string | Iterable<string>): void;
|
|
346
|
+
/** Drop channels. */
|
|
347
|
+
unsubscribe(channels: string | Iterable<string>): void;
|
|
348
|
+
private send;
|
|
349
|
+
private wake;
|
|
350
|
+
private open;
|
|
351
|
+
private nextMessage;
|
|
352
|
+
[Symbol.asyncIterator](): AsyncGenerator<StreamMessage>;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Public market-data stream — `orderbook` / `ticker` / `candles` /
|
|
356
|
+
* `trades`. No authentication.
|
|
357
|
+
*/
|
|
358
|
+
declare class MarketDataStream extends BaseStream {
|
|
359
|
+
constructor(options?: StreamOptions);
|
|
360
|
+
}
|
|
361
|
+
interface UserStreamOptions extends StreamOptions {
|
|
362
|
+
/** Key id (`ak_...`). */
|
|
363
|
+
apiKey: string;
|
|
364
|
+
/** Key secret (`sk_...`). */
|
|
365
|
+
apiSecret: string;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Private stream — the caller's `orders` / `trades` / `balances`.
|
|
369
|
+
* Authenticates in-band with a signed first frame.
|
|
370
|
+
*/
|
|
371
|
+
declare class UserStream extends BaseStream {
|
|
372
|
+
private readonly apiKey;
|
|
373
|
+
private readonly apiSecret;
|
|
374
|
+
constructor(options: UserStreamOptions);
|
|
375
|
+
protected authenticate(ws: WebSocket): Promise<void>;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Typed errors for the CTG.EXCHANGE SDK.
|
|
380
|
+
*
|
|
381
|
+
* Every non-2xx REST response is thrown as an {@link ApiError} subclass
|
|
382
|
+
* chosen by status code. The exchange returns a JSON error body
|
|
383
|
+
* `{ error, message, request_id }` — `requestId` is surfaced on the
|
|
384
|
+
* error; quote it when reporting a problem.
|
|
385
|
+
*/
|
|
386
|
+
/** Base class for every error thrown by this SDK. */
|
|
387
|
+
declare class CtgExchangeError extends Error {
|
|
388
|
+
constructor(message: string);
|
|
389
|
+
}
|
|
390
|
+
/** A non-2xx HTTP response from the API. */
|
|
391
|
+
declare class ApiError extends CtgExchangeError {
|
|
392
|
+
readonly statusCode: number;
|
|
393
|
+
readonly apiError?: string;
|
|
394
|
+
readonly apiMessage?: string;
|
|
395
|
+
readonly requestId?: string;
|
|
396
|
+
constructor(statusCode: number, apiError?: string, apiMessage?: string, requestId?: string);
|
|
397
|
+
}
|
|
398
|
+
/** 400 — the request was malformed. */
|
|
399
|
+
declare class BadRequestError extends ApiError {
|
|
400
|
+
}
|
|
401
|
+
/** 401 — missing, expired, unknown or wrong-signature API key. */
|
|
402
|
+
declare class AuthenticationError extends ApiError {
|
|
403
|
+
}
|
|
404
|
+
/** 403 — the key lacks the required scope, or the IP is off-allowlist. */
|
|
405
|
+
declare class PermissionDeniedError extends ApiError {
|
|
406
|
+
}
|
|
407
|
+
/** 404 — unknown symbol or order. */
|
|
408
|
+
declare class NotFoundError extends ApiError {
|
|
409
|
+
}
|
|
410
|
+
/** 429 — per-key or per-IP rate limit exceeded. */
|
|
411
|
+
declare class RateLimitError extends ApiError {
|
|
412
|
+
/** The `Retry-After` header value in seconds, when the server sent one. */
|
|
413
|
+
readonly retryAfter?: number;
|
|
414
|
+
constructor(statusCode: number, apiError?: string, apiMessage?: string, requestId?: string, retryAfter?: number);
|
|
415
|
+
}
|
|
416
|
+
/** 5xx — the API failed to handle a well-formed request. */
|
|
417
|
+
declare class ServerError extends ApiError {
|
|
418
|
+
}
|
|
419
|
+
interface ErrorBody {
|
|
420
|
+
error?: string;
|
|
421
|
+
message?: string;
|
|
422
|
+
request_id?: string;
|
|
423
|
+
}
|
|
424
|
+
/** Map an HTTP status + JSON error body to the right error instance. */
|
|
425
|
+
declare function errorFromResponse(statusCode: number, body: ErrorBody | undefined, retryAfter?: number): ApiError;
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* HMAC-SHA256 request signing for the CTG.EXCHANGE API.
|
|
429
|
+
*
|
|
430
|
+
* Two signing schemes share one key secret:
|
|
431
|
+
*
|
|
432
|
+
* REST — the canonical string is four newline-joined fields:
|
|
433
|
+
*
|
|
434
|
+
* <ts>\n<METHOD>\n<request-uri>\n<hex sha256 of body>
|
|
435
|
+
*
|
|
436
|
+
* WebSocket — the in-band auth frame signs the string `ws-auth\n<ts>`.
|
|
437
|
+
*
|
|
438
|
+
* Both produce a lowercase-hex HMAC-SHA256 keyed by the API key secret.
|
|
439
|
+
*/
|
|
440
|
+
/** Hex SHA-256 of a request body. `sha256("")` for an empty body. */
|
|
441
|
+
declare function sha256Hex(body: string): string;
|
|
442
|
+
/**
|
|
443
|
+
* Build the four-field canonical string a REST signature covers.
|
|
444
|
+
*
|
|
445
|
+
* `requestUri` is the path plus query string exactly as sent on the
|
|
446
|
+
* request line, e.g. `/api/v1/me/orders/CTGUSDT?limit=50`.
|
|
447
|
+
*/
|
|
448
|
+
declare function restCanonicalString(ts: number | string, method: string, requestUri: string, body?: string): string;
|
|
449
|
+
/** Lowercase-hex HMAC-SHA256 of the REST canonical string. */
|
|
450
|
+
declare function signRest(secret: string, ts: number | string, method: string, requestUri: string, body?: string): string;
|
|
451
|
+
/**
|
|
452
|
+
* The three signed headers a private REST request must carry.
|
|
453
|
+
*
|
|
454
|
+
* `ts` defaults to the current Unix time in seconds; the server rejects
|
|
455
|
+
* timestamps outside its signature window (default 30s), so keep the
|
|
456
|
+
* local clock in sync.
|
|
457
|
+
*/
|
|
458
|
+
declare function restHeaders(keyId: string, secret: string, method: string, requestUri: string, body?: string, ts?: number): Record<string, string>;
|
|
459
|
+
/** Lowercase-hex HMAC-SHA256 over `ws-auth\n<ts>`. */
|
|
460
|
+
declare function signWsAuth(secret: string, ts: number | string): string;
|
|
461
|
+
/** The signed `auth` frame to send first on the private WebSocket stream. */
|
|
462
|
+
declare function wsAuthMessage(keyId: string, secret: string, ts?: number): {
|
|
463
|
+
op: "auth";
|
|
464
|
+
args: [string, number, string];
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
export { ApiError, AuthenticationError, BadRequestError, type Balance, type BookLevel, type Candle, Client, type ClientOptions, CtgExchangeError, DEFAULT_BASE_URL, DEFAULT_WS_BASE_URL, type FeeRebate, type FetchLike, MarketDataStream, type ModifyOrderParams, NotFoundError, type Order, type OrderBook, type OrderSide, type OrderStatus, type OrderType, PermissionDeniedError, type PlaceOrderParams, type PlaceOrderResult, RateLimitError, type Rebate, ServerError, type StreamMessage, type StreamOptions, type SymbolInfo, type Ticker, type TimeInForce, type Trade, type UserFees, UserStream, type UserStreamOptions, errorFromResponse, parseFrame, restCanonicalString, restHeaders, sha256Hex, signRest, signWsAuth, wsAuthMessage };
|