@danielgroen/dxtrade-api 1.0.20 → 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.js CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  BROKER: () => BROKER,
35
35
  DxtradeClient: () => DxtradeClient,
36
36
  DxtradeError: () => DxtradeError,
37
+ ERROR: () => ERROR,
37
38
  ORDER_TYPE: () => ORDER_TYPE,
38
39
  SIDE: () => SIDE,
39
40
  TIF: () => TIF,
@@ -50,7 +51,10 @@ var BROKER = {
50
51
  };
51
52
 
52
53
  // src/constants/endpoints.ts
53
- 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`;
54
+ function websocketQuery(atmosphereId) {
55
+ const trackingId = atmosphereId ?? "0";
56
+ 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`;
57
+ }
54
58
  var endpoints = {
55
59
  login: (base) => `${base}/api/auth/login`,
56
60
  switchAccount: (base, id) => `${base}/api/accounts/switch?accountId=${id}`,
@@ -59,8 +63,10 @@ var endpoints = {
59
63
  submitOrder: (base) => `${base}/api/orders/single`,
60
64
  closePosition: (base) => `${base}/api/positions/close`,
61
65
  assessments: (base) => `${base}/api/assessments`,
62
- websocket: (base) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery,
63
- tradeJournal: (base, params) => `${base}/api/tradejournal?from=${params.from}&to=${params.to}`
66
+ websocket: (base, atmosphereId) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery(atmosphereId),
67
+ tradeJournal: (base, params) => `${base}/api/tradejournal?from=${params.from}&to=${params.to}`,
68
+ subscribeInstruments: (base) => `${base}/api/instruments/subscribeInstrumentSymbols`,
69
+ charts: (base) => `${base}/api/charts`
64
70
  };
65
71
 
66
72
  // src/constants/enums.ts
@@ -86,11 +92,40 @@ var TIF = /* @__PURE__ */ ((TIF2) => {
86
92
  TIF2["GTD"] = "GTD";
87
93
  return TIF2;
88
94
  })(TIF || {});
95
+ var ERROR = /* @__PURE__ */ ((ERROR2) => {
96
+ ERROR2["NO_SESSION"] = "NO_SESSION";
97
+ ERROR2["LOGIN_FAILED"] = "LOGIN_FAILED";
98
+ ERROR2["LOGIN_ERROR"] = "LOGIN_ERROR";
99
+ ERROR2["CSRF_NOT_FOUND"] = "CSRF_NOT_FOUND";
100
+ ERROR2["CSRF_ERROR"] = "CSRF_ERROR";
101
+ ERROR2["ACCOUNT_SWITCH_ERROR"] = "ACCOUNT_SWITCH_ERROR";
102
+ ERROR2["NO_SUGGESTIONS"] = "NO_SUGGESTIONS";
103
+ ERROR2["SUGGEST_ERROR"] = "SUGGEST_ERROR";
104
+ ERROR2["NO_SYMBOL_INFO"] = "NO_SYMBOL_INFO";
105
+ ERROR2["SYMBOL_INFO_ERROR"] = "SYMBOL_INFO_ERROR";
106
+ ERROR2["INSTRUMENTS_TIMEOUT"] = "INSTRUMENTS_TIMEOUT";
107
+ ERROR2["INSTRUMENTS_ERROR"] = "INSTRUMENTS_ERROR";
108
+ ERROR2["LIMITS_TIMEOUT"] = "LIMITS_TIMEOUT";
109
+ ERROR2["LIMITS_ERROR"] = "LIMITS_ERROR";
110
+ ERROR2["OHLC_TIMEOUT"] = "OHLC_TIMEOUT";
111
+ ERROR2["OHLC_ERROR"] = "OHLC_ERROR";
112
+ ERROR2["ORDER_ERROR"] = "ORDER_ERROR";
113
+ ERROR2["POSITION_CLOSE_ERROR"] = "POSITION_CLOSE_ERROR";
114
+ ERROR2["ACCOUNT_METRICS_TIMEOUT"] = "ACCOUNT_METRICS_TIMEOUT";
115
+ ERROR2["ACCOUNT_METRICS_ERROR"] = "ACCOUNT_METRICS_ERROR";
116
+ ERROR2["ACCOUNT_POSITIONS_TIMEOUT"] = "ACCOUNT_POSITIONS_TIMEOUT";
117
+ ERROR2["ACCOUNT_POSITIONS_ERROR"] = "ACCOUNT_POSITIONS_ERROR";
118
+ ERROR2["TRADE_JOURNAL_ERROR"] = "TRADE_JOURNAL_ERROR";
119
+ ERROR2["ASSESSMENTS_ERROR"] = "ASSESSMENTS_ERROR";
120
+ return ERROR2;
121
+ })(ERROR || {});
89
122
  var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
90
123
  WS_MESSAGE2["ACCOUNT_METRICS"] = "ACCOUNT_METRICS";
91
124
  WS_MESSAGE2["ACCOUNTS"] = "ACCOUNTS";
92
125
  WS_MESSAGE2["AVAILABLE_WATCHLISTS"] = "AVAILABLE_WATCHLISTS";
126
+ WS_MESSAGE2["CHART_FEED_SUBTOPIC"] = "chartFeedSubtopic";
93
127
  WS_MESSAGE2["INSTRUMENTS"] = "INSTRUMENTS";
128
+ WS_MESSAGE2["INSTRUMENT_METRICS"] = "INSTRUMENT_METRICS";
94
129
  WS_MESSAGE2["LIMITS"] = "LIMITS";
95
130
  WS_MESSAGE2["MESSAGE"] = "MESSAGE";
96
131
  WS_MESSAGE2["ORDERS"] = "ORDERS";
@@ -98,9 +133,16 @@ var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
98
133
  WS_MESSAGE2["POSITION_CASH_TRANSFERS"] = "POSITION_CASH_TRANSFERS";
99
134
  WS_MESSAGE2["PRIVATE_LAYOUT_NAMES"] = "PRIVATE_LAYOUT_NAMES";
100
135
  WS_MESSAGE2["SHARED_PROPERTIES_MESSAGE"] = "SHARED_PROPERTIES_MESSAGE";
136
+ WS_MESSAGE2["TRADE_STATUSES"] = "TRADE_STATUSES";
101
137
  WS_MESSAGE2["USER_LOGIN_INFO"] = "USER_LOGIN_INFO";
102
138
  return WS_MESSAGE2;
103
139
  })(WS_MESSAGE || {});
140
+ ((WS_MESSAGE2) => {
141
+ let SUBTOPIC;
142
+ ((SUBTOPIC2) => {
143
+ SUBTOPIC2["BIG_CHART_COMPONENT"] = "BigChartComponentPresenter-4";
144
+ })(SUBTOPIC = WS_MESSAGE2.SUBTOPIC || (WS_MESSAGE2.SUBTOPIC = {}));
145
+ })(WS_MESSAGE || (WS_MESSAGE = {}));
104
146
 
105
147
  // src/constants/errors.ts
106
148
  var DxtradeError = class extends Error {
@@ -189,6 +231,14 @@ function debugLog(msg) {
189
231
  function clearDebugLog() {
190
232
  (0, import_fs.writeFileSync)(DEBUG_LOG, "");
191
233
  }
234
+ function parseAtmosphereId(data) {
235
+ const raw = data.toString();
236
+ const parts = raw.split("|");
237
+ if (parts.length >= 2 && /^[0-9a-f-]{36}$/.test(parts[1])) {
238
+ return parts[1];
239
+ }
240
+ return null;
241
+ }
192
242
  function parseWsData(data) {
193
243
  const raw = data.toString();
194
244
  const pipeIndex = raw.indexOf("|");
@@ -203,13 +253,13 @@ function parseWsData(data) {
203
253
  // src/domains/account/account.ts
204
254
  async function getAccountMetrics(ctx, timeout = 3e4) {
205
255
  ctx.ensureSession();
206
- const wsUrl = endpoints.websocket(ctx.broker);
256
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
207
257
  const cookieStr = Cookies.serialize(ctx.cookies);
208
258
  return new Promise((resolve, reject) => {
209
259
  const ws = new import_ws.default(wsUrl, { headers: { Cookie: cookieStr } });
210
260
  const timer = setTimeout(() => {
211
261
  ws.close();
212
- reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT", "Account metrics timed out"));
262
+ reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT" /* ACCOUNT_METRICS_TIMEOUT */, "Account metrics timed out"));
213
263
  }, timeout);
214
264
  ws.on("message", (data) => {
215
265
  const msg = parseWsData(data);
@@ -225,7 +275,7 @@ async function getAccountMetrics(ctx, timeout = 3e4) {
225
275
  ws.on("error", (error) => {
226
276
  clearTimeout(timer);
227
277
  ws.close();
228
- reject(new DxtradeError("ACCOUNT_METRICS_ERROR", `Account metrics error: ${error.message}`));
278
+ reject(new DxtradeError("ACCOUNT_METRICS_ERROR" /* ACCOUNT_METRICS_ERROR */, `Account metrics error: ${error.message}`));
229
279
  });
230
280
  });
231
281
  }
@@ -247,12 +297,12 @@ async function getTradeJournal(ctx, params) {
247
297
  ctx.cookies = Cookies.merge(ctx.cookies, incoming);
248
298
  return response.data;
249
299
  } else {
250
- ctx.throwError("TRADE_JOURNAL_ERROR", `Login failed: ${response.status}`);
300
+ ctx.throwError("TRADE_JOURNAL_ERROR" /* TRADE_JOURNAL_ERROR */, `Login failed: ${response.status}`);
251
301
  }
252
302
  } catch (error) {
253
303
  if (error instanceof DxtradeError) throw error;
254
304
  const message = error instanceof Error ? error.message : "Unknown error";
255
- ctx.throwError("TRADE_JOURNAL_ERROR", `Trade journal error: ${message}`);
305
+ ctx.throwError("TRADE_JOURNAL_ERROR" /* TRADE_JOURNAL_ERROR */, `Trade journal error: ${message}`);
256
306
  }
257
307
  }
258
308
 
@@ -278,7 +328,7 @@ async function getAssessments(ctx, params) {
278
328
  } catch (error) {
279
329
  if (error instanceof DxtradeError) throw error;
280
330
  const message = error instanceof Error ? error.message : "Unknown error";
281
- ctx.throwError("ASSESSMENTS_ERROR", `Error fetching assessments: ${message}`);
331
+ ctx.throwError("ASSESSMENTS_ERROR" /* ASSESSMENTS_ERROR */, `Error fetching assessments: ${message}`);
282
332
  }
283
333
  }
284
334
 
@@ -286,13 +336,13 @@ async function getAssessments(ctx, params) {
286
336
  var import_ws2 = __toESM(require("ws"));
287
337
  async function getInstruments(ctx, params = {}, timeout = 3e4) {
288
338
  ctx.ensureSession();
289
- const wsUrl = endpoints.websocket(ctx.broker);
339
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
290
340
  const cookieStr = Cookies.serialize(ctx.cookies);
291
341
  return new Promise((resolve, reject) => {
292
342
  const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
293
343
  const timer = setTimeout(() => {
294
344
  ws.close();
295
- reject(new DxtradeError("INSTRUMENTS_TIMEOUT", "Instruments request timed out"));
345
+ reject(new DxtradeError("INSTRUMENTS_TIMEOUT" /* INSTRUMENTS_TIMEOUT */, "Instruments request timed out"));
296
346
  }, timeout);
297
347
  let instruments = [];
298
348
  let settleTimer = null;
@@ -322,17 +372,115 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
322
372
  ws.on("error", (error) => {
323
373
  clearTimeout(timer);
324
374
  ws.close();
325
- reject(new DxtradeError("INSTRUMENTS_ERROR", `Instruments error: ${error.message}`));
375
+ reject(new DxtradeError("INSTRUMENTS_ERROR" /* INSTRUMENTS_ERROR */, `Instruments error: ${error.message}`));
376
+ });
377
+ });
378
+ }
379
+
380
+ // src/domains/ohlc/ohlc.ts
381
+ var import_ws3 = __toESM(require("ws"));
382
+ async function getOHLC(ctx, params, timeout = 3e4) {
383
+ ctx.ensureSession();
384
+ const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
385
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
386
+ const cookieStr = Cookies.serialize(ctx.cookies);
387
+ const headers = authHeaders(ctx.csrf, cookieStr);
388
+ return new Promise((resolve, reject) => {
389
+ const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
390
+ const bars = [];
391
+ let putsSent = false;
392
+ let initSettleTimer = null;
393
+ let barSettleTimer = null;
394
+ const timer = setTimeout(() => {
395
+ ws.close();
396
+ reject(new DxtradeError("OHLC_TIMEOUT" /* OHLC_TIMEOUT */, "OHLC data timed out"));
397
+ }, timeout);
398
+ function cleanup() {
399
+ clearTimeout(timer);
400
+ if (initSettleTimer) clearTimeout(initSettleTimer);
401
+ if (barSettleTimer) clearTimeout(barSettleTimer);
402
+ ws.close();
403
+ }
404
+ async function sendPuts() {
405
+ putsSent = true;
406
+ try {
407
+ await retryRequest(
408
+ {
409
+ method: "PUT",
410
+ url: endpoints.subscribeInstruments(ctx.broker),
411
+ data: { instruments: [symbol] },
412
+ headers
413
+ },
414
+ ctx.retries
415
+ );
416
+ await retryRequest(
417
+ {
418
+ method: "PUT",
419
+ url: endpoints.charts(ctx.broker),
420
+ data: {
421
+ chartIds: [],
422
+ requests: [
423
+ {
424
+ aggregationPeriodSeconds: resolution,
425
+ extendedSession: true,
426
+ forexPriceField: priceField,
427
+ id: 0,
428
+ maxBarsCount: maxBars,
429
+ range,
430
+ studySubscription: [],
431
+ subtopic: WS_MESSAGE.SUBTOPIC.BIG_CHART_COMPONENT,
432
+ symbol
433
+ }
434
+ ]
435
+ },
436
+ headers
437
+ },
438
+ ctx.retries
439
+ );
440
+ } catch (error) {
441
+ cleanup();
442
+ const message = error instanceof Error ? error.message : "Unknown error";
443
+ reject(new DxtradeError("OHLC_ERROR" /* OHLC_ERROR */, `Error fetching OHLC data: ${message}`));
444
+ }
445
+ }
446
+ ws.on("message", (data) => {
447
+ const msg = parseWsData(data);
448
+ if (shouldLog(msg, ctx.debug)) debugLog(msg);
449
+ if (typeof msg === "string") return;
450
+ if (!putsSent) {
451
+ if (initSettleTimer) clearTimeout(initSettleTimer);
452
+ initSettleTimer = setTimeout(() => sendPuts(), 1e3);
453
+ return;
454
+ }
455
+ const body = msg.body;
456
+ if (body?.subtopic !== WS_MESSAGE.SUBTOPIC.BIG_CHART_COMPONENT) return;
457
+ if (Array.isArray(body.data)) {
458
+ bars.push(...body.data);
459
+ }
460
+ if (barSettleTimer) clearTimeout(barSettleTimer);
461
+ if (body.snapshotEnd) {
462
+ cleanup();
463
+ resolve(bars);
464
+ } else {
465
+ barSettleTimer = setTimeout(() => {
466
+ cleanup();
467
+ resolve(bars);
468
+ }, 2e3);
469
+ }
470
+ });
471
+ ws.on("error", (error) => {
472
+ cleanup();
473
+ reject(new DxtradeError("OHLC_ERROR" /* OHLC_ERROR */, `OHLC WebSocket error: ${error.message}`));
326
474
  });
327
475
  });
328
476
  }
329
477
 
330
478
  // src/domains/order/order.ts
331
479
  var import_crypto = __toESM(require("crypto"));
332
- var import_ws4 = __toESM(require("ws"));
480
+ var import_ws5 = __toESM(require("ws"));
333
481
 
334
482
  // src/domains/symbol/symbol.ts
335
- var import_ws3 = __toESM(require("ws"));
483
+ var import_ws4 = __toESM(require("ws"));
336
484
  async function getSymbolSuggestions(ctx, text) {
337
485
  ctx.ensureSession();
338
486
  try {
@@ -347,13 +495,13 @@ async function getSymbolSuggestions(ctx, text) {
347
495
  );
348
496
  const suggests = response.data?.suggests;
349
497
  if (!suggests?.length) {
350
- ctx.throwError("NO_SUGGESTIONS", "No symbol suggestions found");
498
+ ctx.throwError("NO_SUGGESTIONS" /* NO_SUGGESTIONS */, "No symbol suggestions found");
351
499
  }
352
500
  return suggests;
353
501
  } catch (error) {
354
502
  if (error instanceof DxtradeError) throw error;
355
503
  const message = error instanceof Error ? error.message : "Unknown error";
356
- ctx.throwError("SUGGEST_ERROR", `Error getting symbol suggestions: ${message}`);
504
+ ctx.throwError("SUGGEST_ERROR" /* SUGGEST_ERROR */, `Error getting symbol suggestions: ${message}`);
357
505
  }
358
506
  }
359
507
  async function getSymbolInfo(ctx, symbol) {
@@ -370,24 +518,24 @@ async function getSymbolInfo(ctx, symbol) {
370
518
  ctx.retries
371
519
  );
372
520
  if (!response.data) {
373
- ctx.throwError("NO_SYMBOL_INFO", "No symbol info returned");
521
+ ctx.throwError("NO_SYMBOL_INFO" /* NO_SYMBOL_INFO */, "No symbol info returned");
374
522
  }
375
523
  return response.data;
376
524
  } catch (error) {
377
525
  if (error instanceof DxtradeError) throw error;
378
526
  const message = error instanceof Error ? error.message : "Unknown error";
379
- ctx.throwError("SYMBOL_INFO_ERROR", `Error getting symbol info: ${message}`);
527
+ ctx.throwError("SYMBOL_INFO_ERROR" /* SYMBOL_INFO_ERROR */, `Error getting symbol info: ${message}`);
380
528
  }
381
529
  }
382
530
  async function getSymbolLimits(ctx, timeout = 3e4) {
383
531
  ctx.ensureSession();
384
- const wsUrl = endpoints.websocket(ctx.broker);
532
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
385
533
  const cookieStr = Cookies.serialize(ctx.cookies);
386
534
  return new Promise((resolve, reject) => {
387
- const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
535
+ const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
388
536
  const timer = setTimeout(() => {
389
537
  ws.close();
390
- reject(new DxtradeError("LIMITS_TIMEOUT", "Symbol limits request timed out"));
538
+ reject(new DxtradeError("LIMITS_TIMEOUT" /* LIMITS_TIMEOUT */, "Symbol limits request timed out"));
391
539
  }, timeout);
392
540
  let limits = [];
393
541
  let settleTimer = null;
@@ -410,14 +558,14 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
410
558
  ws.on("error", (error) => {
411
559
  clearTimeout(timer);
412
560
  ws.close();
413
- reject(new DxtradeError("LIMITS_ERROR", `Symbol limits error: ${error.message}`));
561
+ reject(new DxtradeError("LIMITS_ERROR" /* LIMITS_ERROR */, `Symbol limits error: ${error.message}`));
414
562
  });
415
563
  });
416
564
  }
417
565
 
418
566
  // src/domains/order/order.ts
419
567
  function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
420
- const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
568
+ const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
421
569
  let settled = false;
422
570
  const ready = new Promise((resolve) => {
423
571
  ws.on("open", resolve);
@@ -551,7 +699,7 @@ async function submitOrder(ctx, params) {
551
699
  };
552
700
  }
553
701
  try {
554
- const wsUrl = endpoints.websocket(ctx.broker);
702
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
555
703
  const cookieStr = Cookies.serialize(ctx.cookies);
556
704
  const listener = createOrderListener(wsUrl, cookieStr, 3e4, ctx.debug);
557
705
  await listener.ready;
@@ -571,21 +719,21 @@ async function submitOrder(ctx, params) {
571
719
  } catch (error) {
572
720
  if (error instanceof DxtradeError) throw error;
573
721
  const message = error instanceof Error ? error.response?.data?.message ?? error.message : "Unknown error";
574
- ctx.throwError("ORDER_ERROR", `Error submitting order: ${message}`);
722
+ ctx.throwError("ORDER_ERROR" /* ORDER_ERROR */, `Error submitting order: ${message}`);
575
723
  }
576
724
  }
577
725
 
578
726
  // src/domains/position/position.ts
579
- var import_ws5 = __toESM(require("ws"));
727
+ var import_ws6 = __toESM(require("ws"));
580
728
  async function getPositions(ctx) {
581
729
  ctx.ensureSession();
582
- const wsUrl = endpoints.websocket(ctx.broker);
730
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
583
731
  const cookieStr = Cookies.serialize(ctx.cookies);
584
732
  return new Promise((resolve, reject) => {
585
- const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
733
+ const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
586
734
  const timer = setTimeout(() => {
587
735
  ws.close();
588
- reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT", "Account positions timed out"));
736
+ reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT" /* ACCOUNT_POSITIONS_TIMEOUT */, "Account positions timed out"));
589
737
  }, 3e4);
590
738
  ws.on("message", (data) => {
591
739
  const msg = parseWsData(data);
@@ -600,7 +748,7 @@ async function getPositions(ctx) {
600
748
  ws.on("error", (error) => {
601
749
  clearTimeout(timer);
602
750
  ws.close();
603
- reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR", `Account positions error: ${error.message}`));
751
+ reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR" /* ACCOUNT_POSITIONS_ERROR */, `Account positions error: ${error.message}`));
604
752
  });
605
753
  });
606
754
  }
@@ -618,27 +766,31 @@ async function closePosition(ctx, data) {
618
766
  } catch (error) {
619
767
  if (error instanceof DxtradeError) throw error;
620
768
  const message = error instanceof Error ? error.response?.data?.message ?? error.message : "Unknown error";
621
- ctx.throwError("POSITION_CLOSE_ERROR", `Position close error: ${message}`);
769
+ ctx.throwError("POSITION_CLOSE_ERROR" /* POSITION_CLOSE_ERROR */, `Position close error: ${message}`);
622
770
  }
623
771
  }
624
772
 
625
773
  // src/domains/session/session.ts
626
- var import_ws6 = __toESM(require("ws"));
774
+ var import_ws7 = __toESM(require("ws"));
627
775
  function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
628
776
  return new Promise((resolve, reject) => {
629
- const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
777
+ const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
778
+ let atmosphereId = null;
630
779
  const timer = setTimeout(() => {
631
780
  ws.close();
632
781
  reject(new Error("[dxtrade-api] Handshake timed out"));
633
782
  }, timeout);
634
783
  ws.on("message", (data) => {
784
+ if (!atmosphereId) {
785
+ atmosphereId = parseAtmosphereId(data);
786
+ }
635
787
  const msg = parseWsData(data);
636
788
  if (shouldLog(msg, debug)) debugLog(msg);
637
789
  if (typeof msg === "string") return;
638
790
  if (msg.accountId) {
639
791
  clearTimeout(timer);
640
792
  ws.close();
641
- resolve();
793
+ resolve(atmosphereId);
642
794
  }
643
795
  });
644
796
  ws.on("error", (error) => {
@@ -669,12 +821,12 @@ async function login(ctx) {
669
821
  ctx.cookies = Cookies.merge(ctx.cookies, incoming);
670
822
  ctx.callbacks.onLogin?.();
671
823
  } else {
672
- ctx.throwError("LOGIN_FAILED", `Login failed: ${response.status}`);
824
+ ctx.throwError("LOGIN_FAILED" /* LOGIN_FAILED */, `Login failed: ${response.status}`);
673
825
  }
674
826
  } catch (error) {
675
827
  if (error instanceof DxtradeError) throw error;
676
828
  const message = error instanceof Error ? error.message : "Unknown error";
677
- ctx.throwError("LOGIN_ERROR", `Login error: ${message}`);
829
+ ctx.throwError("LOGIN_ERROR" /* LOGIN_ERROR */, `Login error: ${message}`);
678
830
  }
679
831
  }
680
832
  async function fetchCsrf(ctx) {
@@ -692,12 +844,12 @@ async function fetchCsrf(ctx) {
692
844
  if (csrfMatch) {
693
845
  ctx.csrf = csrfMatch[1];
694
846
  } else {
695
- ctx.throwError("CSRF_NOT_FOUND", "CSRF token not found");
847
+ ctx.throwError("CSRF_NOT_FOUND" /* CSRF_NOT_FOUND */, "CSRF token not found");
696
848
  }
697
849
  } catch (error) {
698
850
  if (error instanceof DxtradeError) throw error;
699
851
  const message = error instanceof Error ? error.message : "Unknown error";
700
- ctx.throwError("CSRF_ERROR", `CSRF fetch error: ${message}`);
852
+ ctx.throwError("CSRF_ERROR" /* CSRF_ERROR */, `CSRF fetch error: ${message}`);
701
853
  }
702
854
  }
703
855
  async function switchAccount(ctx, accountId) {
@@ -715,19 +867,23 @@ async function switchAccount(ctx, accountId) {
715
867
  } catch (error) {
716
868
  if (error instanceof DxtradeError) throw error;
717
869
  const message = error instanceof Error ? error.message : "Unknown error";
718
- ctx.throwError("ACCOUNT_SWITCH_ERROR", `Error switching account: ${message}`);
870
+ ctx.throwError("ACCOUNT_SWITCH_ERROR" /* ACCOUNT_SWITCH_ERROR */, `Error switching account: ${message}`);
719
871
  }
720
872
  }
721
873
  async function connect(ctx) {
722
874
  await login(ctx);
723
875
  await fetchCsrf(ctx);
724
876
  if (ctx.debug) clearDebugLog();
725
- const wsUrl = endpoints.websocket(ctx.broker);
726
877
  const cookieStr = Cookies.serialize(ctx.cookies);
727
- await waitForHandshake(wsUrl, cookieStr, 3e4, ctx.debug);
878
+ ctx.atmosphereId = await waitForHandshake(endpoints.websocket(ctx.broker), cookieStr, 3e4, ctx.debug);
728
879
  if (ctx.config.accountId) {
729
880
  await switchAccount(ctx, ctx.config.accountId);
730
- await waitForHandshake(endpoints.websocket(ctx.broker), Cookies.serialize(ctx.cookies), 3e4, ctx.debug);
881
+ ctx.atmosphereId = await waitForHandshake(
882
+ endpoints.websocket(ctx.broker, ctx.atmosphereId),
883
+ Cookies.serialize(ctx.cookies),
884
+ 3e4,
885
+ ctx.debug
886
+ );
731
887
  }
732
888
  }
733
889
 
@@ -741,12 +897,16 @@ var DxtradeClient = class {
741
897
  callbacks,
742
898
  cookies: {},
743
899
  csrf: null,
900
+ atmosphereId: null,
744
901
  broker: config.broker,
745
902
  retries: config.retries ?? 3,
746
903
  debug: config.debug ?? false,
747
904
  ensureSession() {
748
905
  if (!this.csrf) {
749
- throw new DxtradeError("NO_SESSION", "No active session. Call login() and fetchCsrf() or connect() first.");
906
+ throw new DxtradeError(
907
+ "NO_SESSION" /* NO_SESSION */,
908
+ "No active session. Call login() and fetchCsrf() or connect() first."
909
+ );
750
910
  }
751
911
  },
752
912
  throwError(code, message) {
@@ -819,6 +979,17 @@ var DxtradeClient = class {
819
979
  async getAssessments(params) {
820
980
  return getAssessments(this._ctx, params);
821
981
  }
982
+ /**
983
+ * Fetch OHLC price bars for a symbol.
984
+ * @param params.symbol - Instrument symbol (e.g. "EURUSD")
985
+ * @param params.resolution - Bar period in seconds (default: 60 = 1 min)
986
+ * @param params.range - Lookback window in seconds (default: 432000 = 5 days)
987
+ * @param params.maxBars - Maximum bars to return (default: 3500)
988
+ * @param params.priceField - "bid" or "ask" (default: "bid")
989
+ */
990
+ async getOHLC(params) {
991
+ return getOHLC(this._ctx, params);
992
+ }
822
993
  };
823
994
  // Annotate the CommonJS export names for ESM import in node:
824
995
  0 && (module.exports = {
@@ -826,6 +997,7 @@ var DxtradeClient = class {
826
997
  BROKER,
827
998
  DxtradeClient,
828
999
  DxtradeError,
1000
+ ERROR,
829
1001
  ORDER_TYPE,
830
1002
  SIDE,
831
1003
  TIF,