@danielgroen/dxtrade-api 1.0.8 → 1.0.9

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/dist/index.d.mts CHANGED
@@ -33,8 +33,11 @@ declare enum TIF {
33
33
  GTD = "GTD"
34
34
  }
35
35
  declare enum WS_MESSAGE {
36
+ ACCOUNT_METRICS = "ACCOUNT_METRICS",
36
37
  ACCOUNTS = "ACCOUNTS",
37
38
  AVAILABLE_WATCHLISTS = "AVAILABLE_WATCHLISTS",
39
+ INSTRUMENTS = "INSTRUMENTS",
40
+ LIMITS = "LIMITS",
38
41
  MESSAGE = "MESSAGE",
39
42
  ORDERS = "ORDERS",
40
43
  POSITIONS = "POSITIONS",
@@ -162,17 +165,18 @@ interface WsPayload {
162
165
  type: string;
163
166
  }
164
167
 
165
- declare namespace Symbol {
166
- interface Suggestion {
167
- id: number;
168
- name: string;
169
- [key: string]: unknown;
170
- }
171
- interface Info {
172
- maxVolume: number;
173
- minVolume: number;
174
- volumeStep: number;
175
- lotSize: number;
168
+ declare namespace Account {
169
+ interface Metrics {
170
+ availableFunds: number;
171
+ marginCallLevel: number | string;
172
+ riskLevel: number;
173
+ openPl: number;
174
+ cashBalance: number;
175
+ equity: number;
176
+ conversionRate: number;
177
+ initialMargin: number;
178
+ availableBalance: number;
179
+ reverseRiskLevel: number | string;
176
180
  [key: string]: unknown;
177
181
  }
178
182
  }
@@ -190,6 +194,72 @@ declare namespace Assessments {
190
194
  }
191
195
  }
192
196
 
197
+ declare namespace Instrument {
198
+ interface Info {
199
+ id: number;
200
+ symbol: string;
201
+ description: string;
202
+ type: string;
203
+ subtype: string;
204
+ currency: string;
205
+ currencyPrecision: number;
206
+ precision: number;
207
+ pipsSize: number;
208
+ quantityIncrement: number;
209
+ quantityPrecision: number;
210
+ priceIncrement: number;
211
+ version: number;
212
+ priceIncrementsTO: {
213
+ priceIncrements: number[];
214
+ pricePrecisions: number[];
215
+ bondFraction: boolean;
216
+ };
217
+ lotSize: number;
218
+ baseCurrency: string | null;
219
+ lotName: string | null;
220
+ multiplier: number;
221
+ open: boolean;
222
+ expiration: string | null;
223
+ firstNoticeDate: string | null;
224
+ lastTradeDate: string | null;
225
+ underlying: string | null;
226
+ mmy: string | null;
227
+ optionParametersTO: unknown;
228
+ unitName: string | null;
229
+ additionalFields: unknown;
230
+ additionalObject: unknown;
231
+ currencyParametersTO: unknown;
232
+ tradingHours: string;
233
+ }
234
+ }
235
+
236
+ declare namespace Symbol {
237
+ interface Suggestion {
238
+ id: number;
239
+ name: string;
240
+ [key: string]: unknown;
241
+ }
242
+ interface Info {
243
+ maxVolume: number;
244
+ minVolume: number;
245
+ volumeStep: number;
246
+ lotSize: number;
247
+ [key: string]: unknown;
248
+ }
249
+ interface Limits {
250
+ symbol: string;
251
+ instrumentId: number;
252
+ limitStopDistanceType: string;
253
+ limitStopDistance: number;
254
+ limitStopDistanceInPercentOfSpread: number;
255
+ minOrderSize: number;
256
+ minOrderSizeBypass: boolean;
257
+ maxOrderSize: number;
258
+ minOrderIncrement: number;
259
+ limitType: string;
260
+ }
261
+ }
262
+
193
263
  declare class DxtradeClient {
194
264
  private _ctx;
195
265
  constructor(config: DxtradeConfig);
@@ -199,7 +269,10 @@ declare class DxtradeClient {
199
269
  connect(): Promise<void>;
200
270
  getSymbolSuggestions(text: string): Promise<Symbol.Suggestion[]>;
201
271
  getSymbolInfo(symbol: string): Promise<Symbol.Info>;
272
+ getSymbolLimits(): Promise<Symbol.Limits[]>;
202
273
  submitOrder(params: Order.SubmitParams): Promise<Order.Update>;
274
+ getAccountMetrics(): Promise<Account.Metrics>;
275
+ getInstruments(params?: Partial<Instrument.Info>): Promise<Instrument.Info[]>;
203
276
  getAssessments(params: Assessments.Params): Promise<Assessments.Response>;
204
277
  }
205
278
 
package/dist/index.d.ts CHANGED
@@ -33,8 +33,11 @@ declare enum TIF {
33
33
  GTD = "GTD"
34
34
  }
35
35
  declare enum WS_MESSAGE {
36
+ ACCOUNT_METRICS = "ACCOUNT_METRICS",
36
37
  ACCOUNTS = "ACCOUNTS",
37
38
  AVAILABLE_WATCHLISTS = "AVAILABLE_WATCHLISTS",
39
+ INSTRUMENTS = "INSTRUMENTS",
40
+ LIMITS = "LIMITS",
38
41
  MESSAGE = "MESSAGE",
39
42
  ORDERS = "ORDERS",
40
43
  POSITIONS = "POSITIONS",
@@ -162,17 +165,18 @@ interface WsPayload {
162
165
  type: string;
163
166
  }
164
167
 
165
- declare namespace Symbol {
166
- interface Suggestion {
167
- id: number;
168
- name: string;
169
- [key: string]: unknown;
170
- }
171
- interface Info {
172
- maxVolume: number;
173
- minVolume: number;
174
- volumeStep: number;
175
- lotSize: number;
168
+ declare namespace Account {
169
+ interface Metrics {
170
+ availableFunds: number;
171
+ marginCallLevel: number | string;
172
+ riskLevel: number;
173
+ openPl: number;
174
+ cashBalance: number;
175
+ equity: number;
176
+ conversionRate: number;
177
+ initialMargin: number;
178
+ availableBalance: number;
179
+ reverseRiskLevel: number | string;
176
180
  [key: string]: unknown;
177
181
  }
178
182
  }
@@ -190,6 +194,72 @@ declare namespace Assessments {
190
194
  }
191
195
  }
192
196
 
197
+ declare namespace Instrument {
198
+ interface Info {
199
+ id: number;
200
+ symbol: string;
201
+ description: string;
202
+ type: string;
203
+ subtype: string;
204
+ currency: string;
205
+ currencyPrecision: number;
206
+ precision: number;
207
+ pipsSize: number;
208
+ quantityIncrement: number;
209
+ quantityPrecision: number;
210
+ priceIncrement: number;
211
+ version: number;
212
+ priceIncrementsTO: {
213
+ priceIncrements: number[];
214
+ pricePrecisions: number[];
215
+ bondFraction: boolean;
216
+ };
217
+ lotSize: number;
218
+ baseCurrency: string | null;
219
+ lotName: string | null;
220
+ multiplier: number;
221
+ open: boolean;
222
+ expiration: string | null;
223
+ firstNoticeDate: string | null;
224
+ lastTradeDate: string | null;
225
+ underlying: string | null;
226
+ mmy: string | null;
227
+ optionParametersTO: unknown;
228
+ unitName: string | null;
229
+ additionalFields: unknown;
230
+ additionalObject: unknown;
231
+ currencyParametersTO: unknown;
232
+ tradingHours: string;
233
+ }
234
+ }
235
+
236
+ declare namespace Symbol {
237
+ interface Suggestion {
238
+ id: number;
239
+ name: string;
240
+ [key: string]: unknown;
241
+ }
242
+ interface Info {
243
+ maxVolume: number;
244
+ minVolume: number;
245
+ volumeStep: number;
246
+ lotSize: number;
247
+ [key: string]: unknown;
248
+ }
249
+ interface Limits {
250
+ symbol: string;
251
+ instrumentId: number;
252
+ limitStopDistanceType: string;
253
+ limitStopDistance: number;
254
+ limitStopDistanceInPercentOfSpread: number;
255
+ minOrderSize: number;
256
+ minOrderSizeBypass: boolean;
257
+ maxOrderSize: number;
258
+ minOrderIncrement: number;
259
+ limitType: string;
260
+ }
261
+ }
262
+
193
263
  declare class DxtradeClient {
194
264
  private _ctx;
195
265
  constructor(config: DxtradeConfig);
@@ -199,7 +269,10 @@ declare class DxtradeClient {
199
269
  connect(): Promise<void>;
200
270
  getSymbolSuggestions(text: string): Promise<Symbol.Suggestion[]>;
201
271
  getSymbolInfo(symbol: string): Promise<Symbol.Info>;
272
+ getSymbolLimits(): Promise<Symbol.Limits[]>;
202
273
  submitOrder(params: Order.SubmitParams): Promise<Order.Update>;
274
+ getAccountMetrics(): Promise<Account.Metrics>;
275
+ getInstruments(params?: Partial<Instrument.Info>): Promise<Instrument.Info[]>;
203
276
  getAssessments(params: Assessments.Params): Promise<Assessments.Response>;
204
277
  }
205
278
 
package/dist/index.js CHANGED
@@ -93,8 +93,11 @@ var TIF = /* @__PURE__ */ ((TIF2) => {
93
93
  return TIF2;
94
94
  })(TIF || {});
95
95
  var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
96
+ WS_MESSAGE2["ACCOUNT_METRICS"] = "ACCOUNT_METRICS";
96
97
  WS_MESSAGE2["ACCOUNTS"] = "ACCOUNTS";
97
98
  WS_MESSAGE2["AVAILABLE_WATCHLISTS"] = "AVAILABLE_WATCHLISTS";
99
+ WS_MESSAGE2["INSTRUMENTS"] = "INSTRUMENTS";
100
+ WS_MESSAGE2["LIMITS"] = "LIMITS";
98
101
  WS_MESSAGE2["MESSAGE"] = "MESSAGE";
99
102
  WS_MESSAGE2["ORDERS"] = "ORDERS";
100
103
  WS_MESSAGE2["POSITIONS"] = "POSITIONS";
@@ -115,7 +118,7 @@ var DxtradeError = class extends Error {
115
118
  }
116
119
  };
117
120
 
118
- // src/domains/session/session.ts
121
+ // src/domains/account/account.ts
119
122
  var import_ws = __toESM(require("ws"));
120
123
 
121
124
  // src/utils/cookies.ts
@@ -203,115 +206,113 @@ function parseWsData(data) {
203
206
  }
204
207
  }
205
208
 
206
- // src/domains/session/session.ts
207
- function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
209
+ // src/domains/account/account.ts
210
+ async function getAccountMetrics(ctx, timeout = 3e4) {
211
+ ctx.ensureSession();
212
+ const wsUrl = endpoints.websocket(ctx.baseUrl);
213
+ const cookieStr = Cookies.serialize(ctx.cookies);
208
214
  return new Promise((resolve, reject) => {
209
215
  const ws = new import_ws.default(wsUrl, { headers: { Cookie: cookieStr } });
210
216
  const timer = setTimeout(() => {
211
217
  ws.close();
212
- reject(new Error("[dxtrade-api] Handshake timed out"));
218
+ reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT", "Account metrics timed out"));
213
219
  }, timeout);
214
220
  ws.on("message", (data) => {
215
221
  const msg = parseWsData(data);
216
- if (shouldLog(msg, debug)) debugLog(msg);
222
+ if (shouldLog(msg, ctx.debug)) debugLog(msg);
217
223
  if (typeof msg === "string") return;
218
- if (msg.type === "POSITIONS" /* POSITIONS */) {
224
+ if (msg.type === "ACCOUNT_METRICS" /* ACCOUNT_METRICS */) {
219
225
  clearTimeout(timer);
220
226
  ws.close();
221
- resolve();
227
+ const body = msg.body;
228
+ resolve(body.allMetrics);
222
229
  }
223
230
  });
224
231
  ws.on("error", (error) => {
225
232
  clearTimeout(timer);
226
233
  ws.close();
227
- reject(new Error(`[dxtrade-api] WebSocket handshake error: ${error.message}`));
234
+ reject(new DxtradeError("ACCOUNT_METRICS_ERROR", `Account metrics error: ${error.message}`));
228
235
  });
229
236
  });
230
237
  }
231
- async function login(ctx) {
238
+
239
+ // src/domains/assessments/assessments.ts
240
+ async function getAssessments(ctx, params) {
241
+ ctx.ensureSession();
232
242
  try {
233
243
  const response = await retryRequest(
234
244
  {
235
245
  method: "POST",
236
- url: endpoints.login(ctx.baseUrl),
246
+ url: endpoints.assessments(ctx.baseUrl),
237
247
  data: {
238
- username: ctx.config.username,
239
- password: ctx.config.password,
240
- domain: ctx.config.broker
248
+ from: params.from,
249
+ instrument: params.instrument,
250
+ subtype: params.subtype ?? null,
251
+ to: params.to
241
252
  },
242
- headers: { "Content-Type": "application/json" }
243
- },
244
- ctx.retries
245
- );
246
- if (response.status === 200) {
247
- const setCookies = response.headers["set-cookie"] ?? [];
248
- const incoming = Cookies.parse(setCookies);
249
- ctx.cookies = Cookies.merge(ctx.cookies, incoming);
250
- ctx.callbacks.onLogin?.();
251
- } else {
252
- ctx.throwError("LOGIN_FAILED", `Login failed: ${response.status}`);
253
- }
254
- } catch (error) {
255
- if (error instanceof DxtradeError) throw error;
256
- const message = error instanceof Error ? error.message : "Unknown error";
257
- ctx.throwError("LOGIN_ERROR", `Login error: ${message}`);
258
- }
259
- }
260
- async function fetchCsrf(ctx) {
261
- try {
262
- const cookieStr = Cookies.serialize(ctx.cookies);
263
- const response = await retryRequest(
264
- {
265
- method: "GET",
266
- url: ctx.baseUrl,
267
- headers: { ...cookieOnlyHeaders(cookieStr), Referer: ctx.baseUrl }
268
- },
269
- ctx.retries
270
- );
271
- const csrfMatch = response.data?.match(/name="csrf" content="([^"]+)"/);
272
- if (csrfMatch) {
273
- ctx.csrf = csrfMatch[1];
274
- } else {
275
- ctx.throwError("CSRF_NOT_FOUND", "CSRF token not found");
276
- }
277
- } catch (error) {
278
- if (error instanceof DxtradeError) throw error;
279
- const message = error instanceof Error ? error.message : "Unknown error";
280
- ctx.throwError("CSRF_ERROR", `CSRF fetch error: ${message}`);
281
- }
282
- }
283
- async function switchAccount(ctx, accountId) {
284
- ctx.ensureSession();
285
- try {
286
- await retryRequest(
287
- {
288
- method: "POST",
289
- url: endpoints.switchAccount(ctx.baseUrl, accountId),
290
253
  headers: authHeaders(ctx.csrf, Cookies.serialize(ctx.cookies))
291
254
  },
292
255
  ctx.retries
293
256
  );
294
- ctx.callbacks.onAccountSwitch?.(accountId);
257
+ return response.data;
295
258
  } catch (error) {
296
259
  if (error instanceof DxtradeError) throw error;
297
260
  const message = error instanceof Error ? error.message : "Unknown error";
298
- ctx.throwError("ACCOUNT_SWITCH_ERROR", `Error switching account: ${message}`);
261
+ ctx.throwError("ASSESSMENTS_ERROR", `Error fetching assessments: ${message}`);
299
262
  }
300
263
  }
301
- async function connect(ctx) {
302
- await login(ctx);
303
- await fetchCsrf(ctx);
304
- if (ctx.debug) clearDebugLog();
264
+
265
+ // src/domains/instrument/instrument.ts
266
+ var import_ws2 = __toESM(require("ws"));
267
+ async function getInstruments(ctx, params = {}, timeout = 3e4) {
268
+ ctx.ensureSession();
305
269
  const wsUrl = endpoints.websocket(ctx.baseUrl);
306
270
  const cookieStr = Cookies.serialize(ctx.cookies);
307
- await waitForHandshake(wsUrl, cookieStr, 3e4, ctx.debug);
308
- if (ctx.config.accountId) {
309
- await switchAccount(ctx, ctx.config.accountId);
310
- await waitForHandshake(endpoints.websocket(ctx.baseUrl), Cookies.serialize(ctx.cookies), 3e4, ctx.debug);
311
- }
271
+ return new Promise((resolve, reject) => {
272
+ const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
273
+ const timer = setTimeout(() => {
274
+ ws.close();
275
+ reject(new DxtradeError("INSTRUMENTS_TIMEOUT", "Instruments request timed out"));
276
+ }, timeout);
277
+ let instruments = [];
278
+ let settleTimer = null;
279
+ ws.on("message", (data) => {
280
+ const msg = parseWsData(data);
281
+ if (shouldLog(msg, ctx.debug)) debugLog(msg);
282
+ if (typeof msg === "string") return;
283
+ if (msg.type === "INSTRUMENTS" /* INSTRUMENTS */) {
284
+ instruments.push(...msg.body);
285
+ if (settleTimer) clearTimeout(settleTimer);
286
+ settleTimer = setTimeout(() => {
287
+ clearTimeout(timer);
288
+ ws.close();
289
+ resolve(
290
+ instruments.filter((instrument) => {
291
+ for (const key in params) {
292
+ if (params[key] !== instrument[key]) {
293
+ return false;
294
+ }
295
+ }
296
+ return true;
297
+ })
298
+ );
299
+ }, 0);
300
+ }
301
+ });
302
+ ws.on("error", (error) => {
303
+ clearTimeout(timer);
304
+ ws.close();
305
+ reject(new DxtradeError("INSTRUMENTS_ERROR", `Instruments error: ${error.message}`));
306
+ });
307
+ });
312
308
  }
313
309
 
310
+ // src/domains/order/order.ts
311
+ var import_crypto = __toESM(require("crypto"));
312
+ var import_ws4 = __toESM(require("ws"));
313
+
314
314
  // src/domains/symbol/symbol.ts
315
+ var import_ws3 = __toESM(require("ws"));
315
316
  async function getSymbolSuggestions(ctx, text) {
316
317
  ctx.ensureSession();
317
318
  try {
@@ -358,12 +359,45 @@ async function getSymbolInfo(ctx, symbol) {
358
359
  ctx.throwError("SYMBOL_INFO_ERROR", `Error getting symbol info: ${message}`);
359
360
  }
360
361
  }
362
+ async function getSymbolLimits(ctx, timeout = 3e4) {
363
+ ctx.ensureSession();
364
+ const wsUrl = endpoints.websocket(ctx.baseUrl);
365
+ const cookieStr = Cookies.serialize(ctx.cookies);
366
+ return new Promise((resolve, reject) => {
367
+ const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
368
+ const timer = setTimeout(() => {
369
+ ws.close();
370
+ reject(new DxtradeError("LIMITS_TIMEOUT", "Symbol limits request timed out"));
371
+ }, timeout);
372
+ let limits = [];
373
+ let settleTimer = null;
374
+ ws.on("message", (data) => {
375
+ const msg = parseWsData(data);
376
+ if (shouldLog(msg, ctx.debug)) debugLog(msg);
377
+ if (typeof msg === "string") return;
378
+ if (msg.type === "LIMITS" /* LIMITS */) {
379
+ const batch = msg.body;
380
+ if (batch.length === 0) return;
381
+ limits.push(...batch);
382
+ if (settleTimer) clearTimeout(settleTimer);
383
+ settleTimer = setTimeout(() => {
384
+ clearTimeout(timer);
385
+ ws.close();
386
+ resolve(limits);
387
+ }, 0);
388
+ }
389
+ });
390
+ ws.on("error", (error) => {
391
+ clearTimeout(timer);
392
+ ws.close();
393
+ reject(new DxtradeError("LIMITS_ERROR", `Symbol limits error: ${error.message}`));
394
+ });
395
+ });
396
+ }
361
397
 
362
398
  // src/domains/order/order.ts
363
- var import_crypto = __toESM(require("crypto"));
364
- var import_ws2 = __toESM(require("ws"));
365
399
  function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
366
- const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
400
+ const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
367
401
  let settled = false;
368
402
  const ready = new Promise((resolve) => {
369
403
  ws.on("open", resolve);
@@ -521,29 +555,112 @@ async function submitOrder(ctx, params) {
521
555
  }
522
556
  }
523
557
 
524
- // src/domains/assessments/assessments.ts
525
- async function getAssessments(ctx, params) {
526
- ctx.ensureSession();
558
+ // src/domains/session/session.ts
559
+ var import_ws5 = __toESM(require("ws"));
560
+ function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
561
+ return new Promise((resolve, reject) => {
562
+ const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
563
+ const timer = setTimeout(() => {
564
+ ws.close();
565
+ reject(new Error("[dxtrade-api] Handshake timed out"));
566
+ }, timeout);
567
+ ws.on("message", (data) => {
568
+ const msg = parseWsData(data);
569
+ if (shouldLog(msg, debug)) debugLog(msg);
570
+ if (typeof msg === "string") return;
571
+ if (msg.type === "POSITIONS" /* POSITIONS */) {
572
+ clearTimeout(timer);
573
+ ws.close();
574
+ resolve();
575
+ }
576
+ });
577
+ ws.on("error", (error) => {
578
+ clearTimeout(timer);
579
+ ws.close();
580
+ reject(new Error(`[dxtrade-api] WebSocket handshake error: ${error.message}`));
581
+ });
582
+ });
583
+ }
584
+ async function login(ctx) {
527
585
  try {
528
586
  const response = await retryRequest(
529
587
  {
530
588
  method: "POST",
531
- url: endpoints.assessments(ctx.baseUrl),
589
+ url: endpoints.login(ctx.baseUrl),
532
590
  data: {
533
- from: params.from,
534
- instrument: params.instrument,
535
- subtype: params.subtype ?? null,
536
- to: params.to
591
+ username: ctx.config.username,
592
+ password: ctx.config.password,
593
+ domain: ctx.config.broker
537
594
  },
595
+ headers: { "Content-Type": "application/json" }
596
+ },
597
+ ctx.retries
598
+ );
599
+ if (response.status === 200) {
600
+ const setCookies = response.headers["set-cookie"] ?? [];
601
+ const incoming = Cookies.parse(setCookies);
602
+ ctx.cookies = Cookies.merge(ctx.cookies, incoming);
603
+ ctx.callbacks.onLogin?.();
604
+ } else {
605
+ ctx.throwError("LOGIN_FAILED", `Login failed: ${response.status}`);
606
+ }
607
+ } catch (error) {
608
+ if (error instanceof DxtradeError) throw error;
609
+ const message = error instanceof Error ? error.message : "Unknown error";
610
+ ctx.throwError("LOGIN_ERROR", `Login error: ${message}`);
611
+ }
612
+ }
613
+ async function fetchCsrf(ctx) {
614
+ try {
615
+ const cookieStr = Cookies.serialize(ctx.cookies);
616
+ const response = await retryRequest(
617
+ {
618
+ method: "GET",
619
+ url: ctx.baseUrl,
620
+ headers: { ...cookieOnlyHeaders(cookieStr), Referer: ctx.baseUrl }
621
+ },
622
+ ctx.retries
623
+ );
624
+ const csrfMatch = response.data?.match(/name="csrf" content="([^"]+)"/);
625
+ if (csrfMatch) {
626
+ ctx.csrf = csrfMatch[1];
627
+ } else {
628
+ ctx.throwError("CSRF_NOT_FOUND", "CSRF token not found");
629
+ }
630
+ } catch (error) {
631
+ if (error instanceof DxtradeError) throw error;
632
+ const message = error instanceof Error ? error.message : "Unknown error";
633
+ ctx.throwError("CSRF_ERROR", `CSRF fetch error: ${message}`);
634
+ }
635
+ }
636
+ async function switchAccount(ctx, accountId) {
637
+ ctx.ensureSession();
638
+ try {
639
+ await retryRequest(
640
+ {
641
+ method: "POST",
642
+ url: endpoints.switchAccount(ctx.baseUrl, accountId),
538
643
  headers: authHeaders(ctx.csrf, Cookies.serialize(ctx.cookies))
539
644
  },
540
645
  ctx.retries
541
646
  );
542
- return response.data;
647
+ ctx.callbacks.onAccountSwitch?.(accountId);
543
648
  } catch (error) {
544
649
  if (error instanceof DxtradeError) throw error;
545
650
  const message = error instanceof Error ? error.message : "Unknown error";
546
- ctx.throwError("ASSESSMENTS_ERROR", `Error fetching assessments: ${message}`);
651
+ ctx.throwError("ACCOUNT_SWITCH_ERROR", `Error switching account: ${message}`);
652
+ }
653
+ }
654
+ async function connect(ctx) {
655
+ await login(ctx);
656
+ await fetchCsrf(ctx);
657
+ if (ctx.debug) clearDebugLog();
658
+ const wsUrl = endpoints.websocket(ctx.baseUrl);
659
+ const cookieStr = Cookies.serialize(ctx.cookies);
660
+ await waitForHandshake(wsUrl, cookieStr, 3e4, ctx.debug);
661
+ if (ctx.config.accountId) {
662
+ await switchAccount(ctx, ctx.config.accountId);
663
+ await waitForHandshake(endpoints.websocket(ctx.baseUrl), Cookies.serialize(ctx.cookies), 3e4, ctx.debug);
547
664
  }
548
665
  }
549
666
 
@@ -590,9 +707,18 @@ var DxtradeClient = class {
590
707
  async getSymbolInfo(symbol) {
591
708
  return getSymbolInfo(this._ctx, symbol);
592
709
  }
710
+ async getSymbolLimits() {
711
+ return getSymbolLimits(this._ctx);
712
+ }
593
713
  async submitOrder(params) {
594
714
  return submitOrder(this._ctx, params);
595
715
  }
716
+ async getAccountMetrics() {
717
+ return getAccountMetrics(this._ctx);
718
+ }
719
+ async getInstruments(params = {}) {
720
+ return getInstruments(this._ctx, params);
721
+ }
596
722
  async getAssessments(params) {
597
723
  return getAssessments(this._ctx, params);
598
724
  }