@danielgroen/dxtrade-api 1.0.19 → 1.0.21

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.mjs CHANGED
@@ -6,7 +6,10 @@ var BROKER = {
6
6
  };
7
7
 
8
8
  // src/constants/endpoints.ts
9
- var websocketQuery = `?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.3.2-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=text/x-gwt-rpc;%20charset=UTF-8&X-atmo-protocol=true&sessionState=dx-new&guest-mode=false`;
9
+ function websocketQuery(atmosphereId) {
10
+ const trackingId = atmosphereId ?? "0";
11
+ return `?X-Atmosphere-tracking-id=${trackingId}&X-Atmosphere-Framework=2.3.2-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=text/x-gwt-rpc;%20charset=UTF-8&X-atmo-protocol=true&sessionState=dx-new&guest-mode=false`;
12
+ }
10
13
  var endpoints = {
11
14
  login: (base) => `${base}/api/auth/login`,
12
15
  switchAccount: (base, id) => `${base}/api/accounts/switch?accountId=${id}`,
@@ -15,8 +18,10 @@ var endpoints = {
15
18
  submitOrder: (base) => `${base}/api/orders/single`,
16
19
  closePosition: (base) => `${base}/api/positions/close`,
17
20
  assessments: (base) => `${base}/api/assessments`,
18
- websocket: (base) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery,
19
- tradeJournal: (base, params) => `${base}/api/tradejournal?from=${params.from}&to=${params.to}`
21
+ websocket: (base, atmosphereId) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery(atmosphereId),
22
+ tradeJournal: (base, params) => `${base}/api/tradejournal?from=${params.from}&to=${params.to}`,
23
+ subscribeInstruments: (base) => `${base}/api/instruments/subscribeInstrumentSymbols`,
24
+ charts: (base) => `${base}/api/charts`
20
25
  };
21
26
 
22
27
  // src/constants/enums.ts
@@ -42,11 +47,40 @@ var TIF = /* @__PURE__ */ ((TIF2) => {
42
47
  TIF2["GTD"] = "GTD";
43
48
  return TIF2;
44
49
  })(TIF || {});
50
+ var ERROR = /* @__PURE__ */ ((ERROR2) => {
51
+ ERROR2["NO_SESSION"] = "NO_SESSION";
52
+ ERROR2["LOGIN_FAILED"] = "LOGIN_FAILED";
53
+ ERROR2["LOGIN_ERROR"] = "LOGIN_ERROR";
54
+ ERROR2["CSRF_NOT_FOUND"] = "CSRF_NOT_FOUND";
55
+ ERROR2["CSRF_ERROR"] = "CSRF_ERROR";
56
+ ERROR2["ACCOUNT_SWITCH_ERROR"] = "ACCOUNT_SWITCH_ERROR";
57
+ ERROR2["NO_SUGGESTIONS"] = "NO_SUGGESTIONS";
58
+ ERROR2["SUGGEST_ERROR"] = "SUGGEST_ERROR";
59
+ ERROR2["NO_SYMBOL_INFO"] = "NO_SYMBOL_INFO";
60
+ ERROR2["SYMBOL_INFO_ERROR"] = "SYMBOL_INFO_ERROR";
61
+ ERROR2["INSTRUMENTS_TIMEOUT"] = "INSTRUMENTS_TIMEOUT";
62
+ ERROR2["INSTRUMENTS_ERROR"] = "INSTRUMENTS_ERROR";
63
+ ERROR2["LIMITS_TIMEOUT"] = "LIMITS_TIMEOUT";
64
+ ERROR2["LIMITS_ERROR"] = "LIMITS_ERROR";
65
+ ERROR2["OHLC_TIMEOUT"] = "OHLC_TIMEOUT";
66
+ ERROR2["OHLC_ERROR"] = "OHLC_ERROR";
67
+ ERROR2["ORDER_ERROR"] = "ORDER_ERROR";
68
+ ERROR2["POSITION_CLOSE_ERROR"] = "POSITION_CLOSE_ERROR";
69
+ ERROR2["ACCOUNT_METRICS_TIMEOUT"] = "ACCOUNT_METRICS_TIMEOUT";
70
+ ERROR2["ACCOUNT_METRICS_ERROR"] = "ACCOUNT_METRICS_ERROR";
71
+ ERROR2["ACCOUNT_POSITIONS_TIMEOUT"] = "ACCOUNT_POSITIONS_TIMEOUT";
72
+ ERROR2["ACCOUNT_POSITIONS_ERROR"] = "ACCOUNT_POSITIONS_ERROR";
73
+ ERROR2["TRADE_JOURNAL_ERROR"] = "TRADE_JOURNAL_ERROR";
74
+ ERROR2["ASSESSMENTS_ERROR"] = "ASSESSMENTS_ERROR";
75
+ return ERROR2;
76
+ })(ERROR || {});
45
77
  var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
46
78
  WS_MESSAGE2["ACCOUNT_METRICS"] = "ACCOUNT_METRICS";
47
79
  WS_MESSAGE2["ACCOUNTS"] = "ACCOUNTS";
48
80
  WS_MESSAGE2["AVAILABLE_WATCHLISTS"] = "AVAILABLE_WATCHLISTS";
81
+ WS_MESSAGE2["CHART_FEED_SUBTOPIC"] = "chartFeedSubtopic";
49
82
  WS_MESSAGE2["INSTRUMENTS"] = "INSTRUMENTS";
83
+ WS_MESSAGE2["INSTRUMENT_METRICS"] = "INSTRUMENT_METRICS";
50
84
  WS_MESSAGE2["LIMITS"] = "LIMITS";
51
85
  WS_MESSAGE2["MESSAGE"] = "MESSAGE";
52
86
  WS_MESSAGE2["ORDERS"] = "ORDERS";
@@ -54,9 +88,16 @@ var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
54
88
  WS_MESSAGE2["POSITION_CASH_TRANSFERS"] = "POSITION_CASH_TRANSFERS";
55
89
  WS_MESSAGE2["PRIVATE_LAYOUT_NAMES"] = "PRIVATE_LAYOUT_NAMES";
56
90
  WS_MESSAGE2["SHARED_PROPERTIES_MESSAGE"] = "SHARED_PROPERTIES_MESSAGE";
91
+ WS_MESSAGE2["TRADE_STATUSES"] = "TRADE_STATUSES";
57
92
  WS_MESSAGE2["USER_LOGIN_INFO"] = "USER_LOGIN_INFO";
58
93
  return WS_MESSAGE2;
59
94
  })(WS_MESSAGE || {});
95
+ ((WS_MESSAGE2) => {
96
+ let SUBTOPIC;
97
+ ((SUBTOPIC2) => {
98
+ SUBTOPIC2["BIG_CHART_COMPONENT"] = "BigChartComponentPresenter-4";
99
+ })(SUBTOPIC = WS_MESSAGE2.SUBTOPIC || (WS_MESSAGE2.SUBTOPIC = {}));
100
+ })(WS_MESSAGE || (WS_MESSAGE = {}));
60
101
 
61
102
  // src/constants/errors.ts
62
103
  var DxtradeError = class extends Error {
@@ -145,6 +186,14 @@ function debugLog(msg) {
145
186
  function clearDebugLog() {
146
187
  writeFileSync(DEBUG_LOG, "");
147
188
  }
189
+ function parseAtmosphereId(data) {
190
+ const raw = data.toString();
191
+ const parts = raw.split("|");
192
+ if (parts.length >= 2 && /^[0-9a-f-]{36}$/.test(parts[1])) {
193
+ return parts[1];
194
+ }
195
+ return null;
196
+ }
148
197
  function parseWsData(data) {
149
198
  const raw = data.toString();
150
199
  const pipeIndex = raw.indexOf("|");
@@ -159,13 +208,13 @@ function parseWsData(data) {
159
208
  // src/domains/account/account.ts
160
209
  async function getAccountMetrics(ctx, timeout = 3e4) {
161
210
  ctx.ensureSession();
162
- const wsUrl = endpoints.websocket(ctx.broker);
211
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
163
212
  const cookieStr = Cookies.serialize(ctx.cookies);
164
213
  return new Promise((resolve, reject) => {
165
214
  const ws = new WebSocket(wsUrl, { headers: { Cookie: cookieStr } });
166
215
  const timer = setTimeout(() => {
167
216
  ws.close();
168
- reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT", "Account metrics timed out"));
217
+ reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT" /* ACCOUNT_METRICS_TIMEOUT */, "Account metrics timed out"));
169
218
  }, timeout);
170
219
  ws.on("message", (data) => {
171
220
  const msg = parseWsData(data);
@@ -181,7 +230,7 @@ async function getAccountMetrics(ctx, timeout = 3e4) {
181
230
  ws.on("error", (error) => {
182
231
  clearTimeout(timer);
183
232
  ws.close();
184
- reject(new DxtradeError("ACCOUNT_METRICS_ERROR", `Account metrics error: ${error.message}`));
233
+ reject(new DxtradeError("ACCOUNT_METRICS_ERROR" /* ACCOUNT_METRICS_ERROR */, `Account metrics error: ${error.message}`));
185
234
  });
186
235
  });
187
236
  }
@@ -203,12 +252,12 @@ async function getTradeJournal(ctx, params) {
203
252
  ctx.cookies = Cookies.merge(ctx.cookies, incoming);
204
253
  return response.data;
205
254
  } else {
206
- ctx.throwError("TRADE_JOURNAL_ERROR", `Login failed: ${response.status}`);
255
+ ctx.throwError("TRADE_JOURNAL_ERROR" /* TRADE_JOURNAL_ERROR */, `Login failed: ${response.status}`);
207
256
  }
208
257
  } catch (error) {
209
258
  if (error instanceof DxtradeError) throw error;
210
259
  const message = error instanceof Error ? error.message : "Unknown error";
211
- ctx.throwError("TRADE_JOURNAL_ERROR", `Trade journal error: ${message}`);
260
+ ctx.throwError("TRADE_JOURNAL_ERROR" /* TRADE_JOURNAL_ERROR */, `Trade journal error: ${message}`);
212
261
  }
213
262
  }
214
263
 
@@ -234,7 +283,7 @@ async function getAssessments(ctx, params) {
234
283
  } catch (error) {
235
284
  if (error instanceof DxtradeError) throw error;
236
285
  const message = error instanceof Error ? error.message : "Unknown error";
237
- ctx.throwError("ASSESSMENTS_ERROR", `Error fetching assessments: ${message}`);
286
+ ctx.throwError("ASSESSMENTS_ERROR" /* ASSESSMENTS_ERROR */, `Error fetching assessments: ${message}`);
238
287
  }
239
288
  }
240
289
 
@@ -242,13 +291,13 @@ async function getAssessments(ctx, params) {
242
291
  import WebSocket2 from "ws";
243
292
  async function getInstruments(ctx, params = {}, timeout = 3e4) {
244
293
  ctx.ensureSession();
245
- const wsUrl = endpoints.websocket(ctx.broker);
294
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
246
295
  const cookieStr = Cookies.serialize(ctx.cookies);
247
296
  return new Promise((resolve, reject) => {
248
297
  const ws = new WebSocket2(wsUrl, { headers: { Cookie: cookieStr } });
249
298
  const timer = setTimeout(() => {
250
299
  ws.close();
251
- reject(new DxtradeError("INSTRUMENTS_TIMEOUT", "Instruments request timed out"));
300
+ reject(new DxtradeError("INSTRUMENTS_TIMEOUT" /* INSTRUMENTS_TIMEOUT */, "Instruments request timed out"));
252
301
  }, timeout);
253
302
  let instruments = [];
254
303
  let settleTimer = null;
@@ -278,17 +327,115 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
278
327
  ws.on("error", (error) => {
279
328
  clearTimeout(timer);
280
329
  ws.close();
281
- reject(new DxtradeError("INSTRUMENTS_ERROR", `Instruments error: ${error.message}`));
330
+ reject(new DxtradeError("INSTRUMENTS_ERROR" /* INSTRUMENTS_ERROR */, `Instruments error: ${error.message}`));
331
+ });
332
+ });
333
+ }
334
+
335
+ // src/domains/ohlc/ohlc.ts
336
+ import WebSocket3 from "ws";
337
+ async function getOHLC(ctx, params, timeout = 3e4) {
338
+ ctx.ensureSession();
339
+ const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
340
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
341
+ const cookieStr = Cookies.serialize(ctx.cookies);
342
+ const headers = authHeaders(ctx.csrf, cookieStr);
343
+ return new Promise((resolve, reject) => {
344
+ const ws = new WebSocket3(wsUrl, { headers: { Cookie: cookieStr } });
345
+ const bars = [];
346
+ let putsSent = false;
347
+ let initSettleTimer = null;
348
+ let barSettleTimer = null;
349
+ const timer = setTimeout(() => {
350
+ ws.close();
351
+ reject(new DxtradeError("OHLC_TIMEOUT" /* OHLC_TIMEOUT */, "OHLC data timed out"));
352
+ }, timeout);
353
+ function cleanup() {
354
+ clearTimeout(timer);
355
+ if (initSettleTimer) clearTimeout(initSettleTimer);
356
+ if (barSettleTimer) clearTimeout(barSettleTimer);
357
+ ws.close();
358
+ }
359
+ async function sendPuts() {
360
+ putsSent = true;
361
+ try {
362
+ await retryRequest(
363
+ {
364
+ method: "PUT",
365
+ url: endpoints.subscribeInstruments(ctx.broker),
366
+ data: { instruments: [symbol] },
367
+ headers
368
+ },
369
+ ctx.retries
370
+ );
371
+ await retryRequest(
372
+ {
373
+ method: "PUT",
374
+ url: endpoints.charts(ctx.broker),
375
+ data: {
376
+ chartIds: [],
377
+ requests: [
378
+ {
379
+ aggregationPeriodSeconds: resolution,
380
+ extendedSession: true,
381
+ forexPriceField: priceField,
382
+ id: 0,
383
+ maxBarsCount: maxBars,
384
+ range,
385
+ studySubscription: [],
386
+ subtopic: WS_MESSAGE.SUBTOPIC.BIG_CHART_COMPONENT,
387
+ symbol
388
+ }
389
+ ]
390
+ },
391
+ headers
392
+ },
393
+ ctx.retries
394
+ );
395
+ } catch (error) {
396
+ cleanup();
397
+ const message = error instanceof Error ? error.message : "Unknown error";
398
+ reject(new DxtradeError("OHLC_ERROR" /* OHLC_ERROR */, `Error fetching OHLC data: ${message}`));
399
+ }
400
+ }
401
+ ws.on("message", (data) => {
402
+ const msg = parseWsData(data);
403
+ if (shouldLog(msg, ctx.debug)) debugLog(msg);
404
+ if (typeof msg === "string") return;
405
+ if (!putsSent) {
406
+ if (initSettleTimer) clearTimeout(initSettleTimer);
407
+ initSettleTimer = setTimeout(() => sendPuts(), 1e3);
408
+ return;
409
+ }
410
+ const body = msg.body;
411
+ if (body?.subtopic !== WS_MESSAGE.SUBTOPIC.BIG_CHART_COMPONENT) return;
412
+ if (Array.isArray(body.data)) {
413
+ bars.push(...body.data);
414
+ }
415
+ if (barSettleTimer) clearTimeout(barSettleTimer);
416
+ if (body.snapshotEnd) {
417
+ cleanup();
418
+ resolve(bars);
419
+ } else {
420
+ barSettleTimer = setTimeout(() => {
421
+ cleanup();
422
+ resolve(bars);
423
+ }, 2e3);
424
+ }
425
+ });
426
+ ws.on("error", (error) => {
427
+ cleanup();
428
+ reject(new DxtradeError("OHLC_ERROR" /* OHLC_ERROR */, `OHLC WebSocket error: ${error.message}`));
282
429
  });
283
430
  });
284
431
  }
285
432
 
286
433
  // src/domains/order/order.ts
287
434
  import crypto from "crypto";
288
- import WebSocket4 from "ws";
435
+ import WebSocket5 from "ws";
289
436
 
290
437
  // src/domains/symbol/symbol.ts
291
- import WebSocket3 from "ws";
438
+ import WebSocket4 from "ws";
292
439
  async function getSymbolSuggestions(ctx, text) {
293
440
  ctx.ensureSession();
294
441
  try {
@@ -303,13 +450,13 @@ async function getSymbolSuggestions(ctx, text) {
303
450
  );
304
451
  const suggests = response.data?.suggests;
305
452
  if (!suggests?.length) {
306
- ctx.throwError("NO_SUGGESTIONS", "No symbol suggestions found");
453
+ ctx.throwError("NO_SUGGESTIONS" /* NO_SUGGESTIONS */, "No symbol suggestions found");
307
454
  }
308
455
  return suggests;
309
456
  } catch (error) {
310
457
  if (error instanceof DxtradeError) throw error;
311
458
  const message = error instanceof Error ? error.message : "Unknown error";
312
- ctx.throwError("SUGGEST_ERROR", `Error getting symbol suggestions: ${message}`);
459
+ ctx.throwError("SUGGEST_ERROR" /* SUGGEST_ERROR */, `Error getting symbol suggestions: ${message}`);
313
460
  }
314
461
  }
315
462
  async function getSymbolInfo(ctx, symbol) {
@@ -326,24 +473,24 @@ async function getSymbolInfo(ctx, symbol) {
326
473
  ctx.retries
327
474
  );
328
475
  if (!response.data) {
329
- ctx.throwError("NO_SYMBOL_INFO", "No symbol info returned");
476
+ ctx.throwError("NO_SYMBOL_INFO" /* NO_SYMBOL_INFO */, "No symbol info returned");
330
477
  }
331
478
  return response.data;
332
479
  } catch (error) {
333
480
  if (error instanceof DxtradeError) throw error;
334
481
  const message = error instanceof Error ? error.message : "Unknown error";
335
- ctx.throwError("SYMBOL_INFO_ERROR", `Error getting symbol info: ${message}`);
482
+ ctx.throwError("SYMBOL_INFO_ERROR" /* SYMBOL_INFO_ERROR */, `Error getting symbol info: ${message}`);
336
483
  }
337
484
  }
338
485
  async function getSymbolLimits(ctx, timeout = 3e4) {
339
486
  ctx.ensureSession();
340
- const wsUrl = endpoints.websocket(ctx.broker);
487
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
341
488
  const cookieStr = Cookies.serialize(ctx.cookies);
342
489
  return new Promise((resolve, reject) => {
343
- const ws = new WebSocket3(wsUrl, { headers: { Cookie: cookieStr } });
490
+ const ws = new WebSocket4(wsUrl, { headers: { Cookie: cookieStr } });
344
491
  const timer = setTimeout(() => {
345
492
  ws.close();
346
- reject(new DxtradeError("LIMITS_TIMEOUT", "Symbol limits request timed out"));
493
+ reject(new DxtradeError("LIMITS_TIMEOUT" /* LIMITS_TIMEOUT */, "Symbol limits request timed out"));
347
494
  }, timeout);
348
495
  let limits = [];
349
496
  let settleTimer = null;
@@ -366,14 +513,14 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
366
513
  ws.on("error", (error) => {
367
514
  clearTimeout(timer);
368
515
  ws.close();
369
- reject(new DxtradeError("LIMITS_ERROR", `Symbol limits error: ${error.message}`));
516
+ reject(new DxtradeError("LIMITS_ERROR" /* LIMITS_ERROR */, `Symbol limits error: ${error.message}`));
370
517
  });
371
518
  });
372
519
  }
373
520
 
374
521
  // src/domains/order/order.ts
375
522
  function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
376
- const ws = new WebSocket4(wsUrl, { headers: { Cookie: cookieStr } });
523
+ const ws = new WebSocket5(wsUrl, { headers: { Cookie: cookieStr } });
377
524
  let settled = false;
378
525
  const ready = new Promise((resolve) => {
379
526
  ws.on("open", resolve);
@@ -507,7 +654,7 @@ async function submitOrder(ctx, params) {
507
654
  };
508
655
  }
509
656
  try {
510
- const wsUrl = endpoints.websocket(ctx.broker);
657
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
511
658
  const cookieStr = Cookies.serialize(ctx.cookies);
512
659
  const listener = createOrderListener(wsUrl, cookieStr, 3e4, ctx.debug);
513
660
  await listener.ready;
@@ -527,21 +674,21 @@ async function submitOrder(ctx, params) {
527
674
  } catch (error) {
528
675
  if (error instanceof DxtradeError) throw error;
529
676
  const message = error instanceof Error ? error.response?.data?.message ?? error.message : "Unknown error";
530
- ctx.throwError("ORDER_ERROR", `Error submitting order: ${message}`);
677
+ ctx.throwError("ORDER_ERROR" /* ORDER_ERROR */, `Error submitting order: ${message}`);
531
678
  }
532
679
  }
533
680
 
534
681
  // src/domains/position/position.ts
535
- import WebSocket5 from "ws";
682
+ import WebSocket6 from "ws";
536
683
  async function getPositions(ctx) {
537
684
  ctx.ensureSession();
538
- const wsUrl = endpoints.websocket(ctx.broker);
685
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
539
686
  const cookieStr = Cookies.serialize(ctx.cookies);
540
687
  return new Promise((resolve, reject) => {
541
- const ws = new WebSocket5(wsUrl, { headers: { Cookie: cookieStr } });
688
+ const ws = new WebSocket6(wsUrl, { headers: { Cookie: cookieStr } });
542
689
  const timer = setTimeout(() => {
543
690
  ws.close();
544
- reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT", "Account positions timed out"));
691
+ reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT" /* ACCOUNT_POSITIONS_TIMEOUT */, "Account positions timed out"));
545
692
  }, 3e4);
546
693
  ws.on("message", (data) => {
547
694
  const msg = parseWsData(data);
@@ -556,7 +703,7 @@ async function getPositions(ctx) {
556
703
  ws.on("error", (error) => {
557
704
  clearTimeout(timer);
558
705
  ws.close();
559
- reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR", `Account positions error: ${error.message}`));
706
+ reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR" /* ACCOUNT_POSITIONS_ERROR */, `Account positions error: ${error.message}`));
560
707
  });
561
708
  });
562
709
  }
@@ -574,27 +721,31 @@ async function closePosition(ctx, data) {
574
721
  } catch (error) {
575
722
  if (error instanceof DxtradeError) throw error;
576
723
  const message = error instanceof Error ? error.response?.data?.message ?? error.message : "Unknown error";
577
- ctx.throwError("POSITION_CLOSE_ERROR", `Position close error: ${message}`);
724
+ ctx.throwError("POSITION_CLOSE_ERROR" /* POSITION_CLOSE_ERROR */, `Position close error: ${message}`);
578
725
  }
579
726
  }
580
727
 
581
728
  // src/domains/session/session.ts
582
- import WebSocket6 from "ws";
729
+ import WebSocket7 from "ws";
583
730
  function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
584
731
  return new Promise((resolve, reject) => {
585
- const ws = new WebSocket6(wsUrl, { headers: { Cookie: cookieStr } });
732
+ const ws = new WebSocket7(wsUrl, { headers: { Cookie: cookieStr } });
733
+ let atmosphereId = null;
586
734
  const timer = setTimeout(() => {
587
735
  ws.close();
588
736
  reject(new Error("[dxtrade-api] Handshake timed out"));
589
737
  }, timeout);
590
738
  ws.on("message", (data) => {
739
+ if (!atmosphereId) {
740
+ atmosphereId = parseAtmosphereId(data);
741
+ }
591
742
  const msg = parseWsData(data);
592
743
  if (shouldLog(msg, debug)) debugLog(msg);
593
744
  if (typeof msg === "string") return;
594
745
  if (msg.accountId) {
595
746
  clearTimeout(timer);
596
747
  ws.close();
597
- resolve();
748
+ resolve(atmosphereId);
598
749
  }
599
750
  });
600
751
  ws.on("error", (error) => {
@@ -625,12 +776,12 @@ async function login(ctx) {
625
776
  ctx.cookies = Cookies.merge(ctx.cookies, incoming);
626
777
  ctx.callbacks.onLogin?.();
627
778
  } else {
628
- ctx.throwError("LOGIN_FAILED", `Login failed: ${response.status}`);
779
+ ctx.throwError("LOGIN_FAILED" /* LOGIN_FAILED */, `Login failed: ${response.status}`);
629
780
  }
630
781
  } catch (error) {
631
782
  if (error instanceof DxtradeError) throw error;
632
783
  const message = error instanceof Error ? error.message : "Unknown error";
633
- ctx.throwError("LOGIN_ERROR", `Login error: ${message}`);
784
+ ctx.throwError("LOGIN_ERROR" /* LOGIN_ERROR */, `Login error: ${message}`);
634
785
  }
635
786
  }
636
787
  async function fetchCsrf(ctx) {
@@ -648,12 +799,12 @@ async function fetchCsrf(ctx) {
648
799
  if (csrfMatch) {
649
800
  ctx.csrf = csrfMatch[1];
650
801
  } else {
651
- ctx.throwError("CSRF_NOT_FOUND", "CSRF token not found");
802
+ ctx.throwError("CSRF_NOT_FOUND" /* CSRF_NOT_FOUND */, "CSRF token not found");
652
803
  }
653
804
  } catch (error) {
654
805
  if (error instanceof DxtradeError) throw error;
655
806
  const message = error instanceof Error ? error.message : "Unknown error";
656
- ctx.throwError("CSRF_ERROR", `CSRF fetch error: ${message}`);
807
+ ctx.throwError("CSRF_ERROR" /* CSRF_ERROR */, `CSRF fetch error: ${message}`);
657
808
  }
658
809
  }
659
810
  async function switchAccount(ctx, accountId) {
@@ -671,19 +822,23 @@ async function switchAccount(ctx, accountId) {
671
822
  } catch (error) {
672
823
  if (error instanceof DxtradeError) throw error;
673
824
  const message = error instanceof Error ? error.message : "Unknown error";
674
- ctx.throwError("ACCOUNT_SWITCH_ERROR", `Error switching account: ${message}`);
825
+ ctx.throwError("ACCOUNT_SWITCH_ERROR" /* ACCOUNT_SWITCH_ERROR */, `Error switching account: ${message}`);
675
826
  }
676
827
  }
677
828
  async function connect(ctx) {
678
829
  await login(ctx);
679
830
  await fetchCsrf(ctx);
680
831
  if (ctx.debug) clearDebugLog();
681
- const wsUrl = endpoints.websocket(ctx.broker);
682
832
  const cookieStr = Cookies.serialize(ctx.cookies);
683
- await waitForHandshake(wsUrl, cookieStr, 3e4, ctx.debug);
833
+ ctx.atmosphereId = await waitForHandshake(endpoints.websocket(ctx.broker), cookieStr, 3e4, ctx.debug);
684
834
  if (ctx.config.accountId) {
685
835
  await switchAccount(ctx, ctx.config.accountId);
686
- await waitForHandshake(endpoints.websocket(ctx.broker), Cookies.serialize(ctx.cookies), 3e4, ctx.debug);
836
+ ctx.atmosphereId = await waitForHandshake(
837
+ endpoints.websocket(ctx.broker, ctx.atmosphereId),
838
+ Cookies.serialize(ctx.cookies),
839
+ 3e4,
840
+ ctx.debug
841
+ );
687
842
  }
688
843
  }
689
844
 
@@ -697,12 +852,16 @@ var DxtradeClient = class {
697
852
  callbacks,
698
853
  cookies: {},
699
854
  csrf: null,
855
+ atmosphereId: null,
700
856
  broker: config.broker,
701
857
  retries: config.retries ?? 3,
702
858
  debug: config.debug ?? false,
703
859
  ensureSession() {
704
860
  if (!this.csrf) {
705
- throw new DxtradeError("NO_SESSION", "No active session. Call login() and fetchCsrf() or connect() first.");
861
+ throw new DxtradeError(
862
+ "NO_SESSION" /* NO_SESSION */,
863
+ "No active session. Call login() and fetchCsrf() or connect() first."
864
+ );
706
865
  }
707
866
  },
708
867
  throwError(code, message) {
@@ -775,12 +934,24 @@ var DxtradeClient = class {
775
934
  async getAssessments(params) {
776
935
  return getAssessments(this._ctx, params);
777
936
  }
937
+ /**
938
+ * Fetch OHLC price bars for a symbol.
939
+ * @param params.symbol - Instrument symbol (e.g. "EURUSD")
940
+ * @param params.resolution - Bar period in seconds (default: 60 = 1 min)
941
+ * @param params.range - Lookback window in seconds (default: 432000 = 5 days)
942
+ * @param params.maxBars - Maximum bars to return (default: 3500)
943
+ * @param params.priceField - "bid" or "ask" (default: "bid")
944
+ */
945
+ async getOHLC(params) {
946
+ return getOHLC(this._ctx, params);
947
+ }
778
948
  };
779
949
  export {
780
950
  ACTION,
781
951
  BROKER,
782
952
  DxtradeClient,
783
953
  DxtradeError,
954
+ ERROR,
784
955
  ORDER_TYPE,
785
956
  SIDE,
786
957
  TIF,