@danielgroen/dxtrade-api 1.0.22 → 1.0.24

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
@@ -21,7 +21,7 @@ var endpoints = {
21
21
  assessments: (base) => `${base}/api/assessments`,
22
22
  websocket: (base, atmosphereId) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery(atmosphereId),
23
23
  tradeJournal: (base, params) => `${base}/api/tradejournal?from=${params.from}&to=${params.to}`,
24
- tradeHistory: (base, params) => `${base}/api/history?from=${params.from}&to=${params.to}&orderId=`,
24
+ tradeHistory: (base, params) => `${base}/api/history?from=${params.from}&to=${params.to}`,
25
25
  subscribeInstruments: (base) => `${base}/api/instruments/subscribeInstrumentSymbols`,
26
26
  charts: (base) => `${base}/api/charts`
27
27
  };
@@ -80,6 +80,9 @@ var ERROR = /* @__PURE__ */ ((ERROR2) => {
80
80
  ERROR2["TRADE_JOURNAL_ERROR"] = "TRADE_JOURNAL_ERROR";
81
81
  ERROR2["TRADE_HISTORY_ERROR"] = "TRADE_HISTORY_ERROR";
82
82
  ERROR2["ASSESSMENTS_ERROR"] = "ASSESSMENTS_ERROR";
83
+ ERROR2["RATE_LIMITED"] = "RATE_LIMITED";
84
+ ERROR2["WS_MANAGER_ERROR"] = "WS_MANAGER_ERROR";
85
+ ERROR2["STREAM_REQUIRES_CONNECT"] = "STREAM_REQUIRES_CONNECT";
83
86
  return ERROR2;
84
87
  })(ERROR || {});
85
88
  var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
@@ -118,7 +121,7 @@ var DxtradeError = class extends Error {
118
121
  };
119
122
 
120
123
  // src/domains/account/account.ts
121
- import WebSocket from "ws";
124
+ import WebSocket2 from "ws";
122
125
 
123
126
  // src/utils/cookies.ts
124
127
  var Cookies = class {
@@ -163,14 +166,17 @@ function cookieOnlyHeaders(cookieStr) {
163
166
  }
164
167
 
165
168
  // src/utils/retry.ts
166
- import axios from "axios";
169
+ import axios, { isAxiosError } from "axios";
167
170
  async function retryRequest(config, retries = 3) {
168
171
  for (let attempt = 1; attempt <= retries; attempt++) {
169
172
  try {
170
173
  return await axios(config);
171
174
  } catch (error) {
172
175
  const message = error instanceof Error ? error.message : "Unknown error";
173
- console.warn(`[dxtrade-api] Attempt ${attempt} failed: ${message}`);
176
+ console.warn(`[dxtrade-api] Attempt ${attempt} failed: ${message}`, config.url);
177
+ if (isAxiosError(error) && error.response?.status === 429) {
178
+ throw new DxtradeError("RATE_LIMITED" /* RATE_LIMITED */, "Rate limited (429). Too many requests \u2014 try again later.");
179
+ }
174
180
  if (attempt === retries) throw error;
175
181
  await new Promise((res) => setTimeout(res, 1e3 * attempt));
176
182
  }
@@ -213,13 +219,83 @@ function parseWsData(data) {
213
219
  }
214
220
  }
215
221
 
222
+ // src/utils/ws-manager.ts
223
+ import { EventEmitter } from "events";
224
+ import WebSocket from "ws";
225
+ var WsManager = class extends EventEmitter {
226
+ _ws = null;
227
+ _cache = /* @__PURE__ */ new Map();
228
+ connect(wsUrl, cookieStr, debug = false) {
229
+ return new Promise((resolve, reject) => {
230
+ const ws = new WebSocket(wsUrl, { headers: { Cookie: cookieStr } });
231
+ ws.on("open", () => {
232
+ this._ws = ws;
233
+ resolve();
234
+ });
235
+ ws.on("message", (data) => {
236
+ const msg = parseWsData(data);
237
+ if (shouldLog(msg, debug)) debugLog(msg);
238
+ if (typeof msg === "string") return;
239
+ const payload = msg;
240
+ this._cache.set(payload.type, payload.body);
241
+ this.emit(payload.type, payload.body);
242
+ });
243
+ ws.on("error", (error) => {
244
+ if (!this._ws) {
245
+ return reject(error);
246
+ }
247
+ this.emit("error", error);
248
+ });
249
+ ws.on("close", () => {
250
+ this._ws = null;
251
+ this.emit("close");
252
+ });
253
+ });
254
+ }
255
+ waitFor(type, timeout = 3e4) {
256
+ const cached = this._cache.get(type);
257
+ if (cached !== void 0) {
258
+ return Promise.resolve(cached);
259
+ }
260
+ return new Promise((resolve, reject) => {
261
+ const timer = setTimeout(() => {
262
+ this.removeListener(type, onMessage);
263
+ reject(new Error(`WsManager: timed out waiting for ${type}`));
264
+ }, timeout);
265
+ const onMessage = (body) => {
266
+ clearTimeout(timer);
267
+ resolve(body);
268
+ };
269
+ this.once(type, onMessage);
270
+ });
271
+ }
272
+ getCached(type) {
273
+ return this._cache.get(type);
274
+ }
275
+ close() {
276
+ if (this._ws) {
277
+ this._ws.close();
278
+ this._ws = null;
279
+ }
280
+ this._cache.clear();
281
+ this.removeAllListeners();
282
+ }
283
+ get isConnected() {
284
+ return this._ws !== null && this._ws.readyState === WebSocket.OPEN;
285
+ }
286
+ };
287
+
216
288
  // src/domains/account/account.ts
217
289
  async function getAccountMetrics(ctx, timeout = 3e4) {
218
290
  ctx.ensureSession();
291
+ if (ctx.wsManager) {
292
+ const body = await ctx.wsManager.waitFor("ACCOUNT_METRICS" /* ACCOUNT_METRICS */, timeout);
293
+ return body.allMetrics;
294
+ }
219
295
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
220
296
  const cookieStr = Cookies.serialize(ctx.cookies);
221
297
  return new Promise((resolve, reject) => {
222
- const ws = new WebSocket(wsUrl, { headers: { Cookie: cookieStr } });
298
+ const ws = new WebSocket2(wsUrl, { headers: { Cookie: cookieStr } });
223
299
  const timer = setTimeout(() => {
224
300
  ws.close();
225
301
  reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT" /* ACCOUNT_METRICS_TIMEOUT */, "Account metrics timed out"));
@@ -245,12 +321,11 @@ async function getAccountMetrics(ctx, timeout = 3e4) {
245
321
  async function getTradeHistory(ctx, params) {
246
322
  ctx.ensureSession();
247
323
  try {
248
- const cookieStr = Cookies.serialize(ctx.cookies);
249
324
  const response = await retryRequest(
250
325
  {
251
- method: "GET",
326
+ method: "POST",
252
327
  url: endpoints.tradeHistory(ctx.broker, params),
253
- headers: { ...baseHeaders(), Cookie: cookieStr }
328
+ headers: authHeaders(ctx.csrf, Cookies.serialize(ctx.cookies))
254
329
  },
255
330
  ctx.retries
256
331
  );
@@ -322,13 +397,13 @@ async function getAssessments(ctx, params) {
322
397
  }
323
398
 
324
399
  // src/domains/instrument/instrument.ts
325
- import WebSocket2 from "ws";
400
+ import WebSocket3 from "ws";
326
401
  async function getInstruments(ctx, params = {}, timeout = 3e4) {
327
402
  ctx.ensureSession();
328
403
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
329
404
  const cookieStr = Cookies.serialize(ctx.cookies);
330
405
  return new Promise((resolve, reject) => {
331
- const ws = new WebSocket2(wsUrl, { headers: { Cookie: cookieStr } });
406
+ const ws = new WebSocket3(wsUrl, { headers: { Cookie: cookieStr } });
332
407
  const timer = setTimeout(() => {
333
408
  ws.close();
334
409
  reject(new DxtradeError("INSTRUMENTS_TIMEOUT" /* INSTRUMENTS_TIMEOUT */, "Instruments request timed out"));
@@ -355,7 +430,7 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
355
430
  return true;
356
431
  })
357
432
  );
358
- }, 0);
433
+ }, 200);
359
434
  }
360
435
  });
361
436
  ws.on("error", (error) => {
@@ -367,7 +442,7 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
367
442
  }
368
443
 
369
444
  // src/domains/ohlc/ohlc.ts
370
- import WebSocket3 from "ws";
445
+ import WebSocket4 from "ws";
371
446
  async function getOHLC(ctx, params, timeout = 3e4) {
372
447
  ctx.ensureSession();
373
448
  const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
@@ -375,7 +450,7 @@ async function getOHLC(ctx, params, timeout = 3e4) {
375
450
  const cookieStr = Cookies.serialize(ctx.cookies);
376
451
  const headers = authHeaders(ctx.csrf, cookieStr);
377
452
  return new Promise((resolve, reject) => {
378
- const ws = new WebSocket3(wsUrl, { headers: { Cookie: cookieStr } });
453
+ const ws = new WebSocket4(wsUrl, { headers: { Cookie: cookieStr } });
379
454
  const bars = [];
380
455
  let putsSent = false;
381
456
  let initSettleTimer = null;
@@ -466,10 +541,10 @@ async function getOHLC(ctx, params, timeout = 3e4) {
466
541
 
467
542
  // src/domains/order/order.ts
468
543
  import crypto from "crypto";
469
- import WebSocket5 from "ws";
544
+ import WebSocket6 from "ws";
470
545
 
471
546
  // src/domains/symbol/symbol.ts
472
- import WebSocket4 from "ws";
547
+ import WebSocket5 from "ws";
473
548
  async function getSymbolSuggestions(ctx, text) {
474
549
  ctx.ensureSession();
475
550
  try {
@@ -521,7 +596,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
521
596
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
522
597
  const cookieStr = Cookies.serialize(ctx.cookies);
523
598
  return new Promise((resolve, reject) => {
524
- const ws = new WebSocket4(wsUrl, { headers: { Cookie: cookieStr } });
599
+ const ws = new WebSocket5(wsUrl, { headers: { Cookie: cookieStr } });
525
600
  const timer = setTimeout(() => {
526
601
  ws.close();
527
602
  reject(new DxtradeError("LIMITS_TIMEOUT" /* LIMITS_TIMEOUT */, "Symbol limits request timed out"));
@@ -541,7 +616,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
541
616
  clearTimeout(timer);
542
617
  ws.close();
543
618
  resolve(limits);
544
- }, 0);
619
+ }, 200);
545
620
  }
546
621
  });
547
622
  ws.on("error", (error) => {
@@ -554,7 +629,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
554
629
 
555
630
  // src/domains/order/order.ts
556
631
  function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
557
- const ws = new WebSocket5(wsUrl, { headers: { Cookie: cookieStr } });
632
+ const ws = new WebSocket6(wsUrl, { headers: { Cookie: cookieStr } });
558
633
  let settled = false;
559
634
  const ready = new Promise((resolve) => {
560
635
  ws.on("open", resolve);
@@ -621,10 +696,13 @@ function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
621
696
  }
622
697
  async function getOrders(ctx, timeout = 3e4) {
623
698
  ctx.ensureSession();
699
+ if (ctx.wsManager) {
700
+ return ctx.wsManager.waitFor("ORDERS" /* ORDERS */, timeout);
701
+ }
624
702
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
625
703
  const cookieStr = Cookies.serialize(ctx.cookies);
626
704
  return new Promise((resolve, reject) => {
627
- const ws = new WebSocket5(wsUrl, { headers: { Cookie: cookieStr } });
705
+ const ws = new WebSocket6(wsUrl, { headers: { Cookie: cookieStr } });
628
706
  const timer = setTimeout(() => {
629
707
  ws.close();
630
708
  reject(new DxtradeError("ORDERS_TIMEOUT" /* ORDERS_TIMEOUT */, "Orders request timed out"));
@@ -768,13 +846,33 @@ async function submitOrder(ctx, params) {
768
846
  }
769
847
 
770
848
  // src/domains/position/position.ts
771
- import WebSocket6 from "ws";
849
+ import WebSocket7 from "ws";
850
+ function streamPositions(ctx, callback) {
851
+ if (!ctx.wsManager) {
852
+ ctx.throwError(
853
+ "STREAM_REQUIRES_CONNECT" /* STREAM_REQUIRES_CONNECT */,
854
+ "Streaming requires a persistent WebSocket. Use connect() instead of auth()."
855
+ );
856
+ }
857
+ const listener = (body) => callback(body);
858
+ ctx.wsManager.on("POSITIONS" /* POSITIONS */, listener);
859
+ const cached = ctx.wsManager.getCached("POSITIONS" /* POSITIONS */);
860
+ if (cached !== void 0) {
861
+ callback(cached);
862
+ }
863
+ return () => {
864
+ ctx.wsManager?.removeListener("POSITIONS" /* POSITIONS */, listener);
865
+ };
866
+ }
772
867
  async function getPositions(ctx) {
773
868
  ctx.ensureSession();
869
+ if (ctx.wsManager) {
870
+ return ctx.wsManager.waitFor("POSITIONS" /* POSITIONS */);
871
+ }
774
872
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
775
873
  const cookieStr = Cookies.serialize(ctx.cookies);
776
874
  return new Promise((resolve, reject) => {
777
- const ws = new WebSocket6(wsUrl, { headers: { Cookie: cookieStr } });
875
+ const ws = new WebSocket7(wsUrl, { headers: { Cookie: cookieStr } });
778
876
  const timer = setTimeout(() => {
779
877
  ws.close();
780
878
  reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT" /* ACCOUNT_POSITIONS_TIMEOUT */, "Account positions timed out"));
@@ -798,10 +896,13 @@ async function getPositions(ctx) {
798
896
  }
799
897
  async function getPositionMetrics(ctx, timeout = 3e4) {
800
898
  ctx.ensureSession();
899
+ if (ctx.wsManager) {
900
+ return ctx.wsManager.waitFor("POSITION_METRICS" /* POSITION_METRICS */, timeout);
901
+ }
801
902
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
802
903
  const cookieStr = Cookies.serialize(ctx.cookies);
803
904
  return new Promise((resolve, reject) => {
804
- const ws = new WebSocket6(wsUrl, { headers: { Cookie: cookieStr } });
905
+ const ws = new WebSocket7(wsUrl, { headers: { Cookie: cookieStr } });
805
906
  const timer = setTimeout(() => {
806
907
  ws.close();
807
908
  reject(new DxtradeError("POSITION_METRICS_TIMEOUT" /* POSITION_METRICS_TIMEOUT */, "Position metrics timed out"));
@@ -863,10 +964,10 @@ async function closePosition(ctx, data) {
863
964
  }
864
965
 
865
966
  // src/domains/session/session.ts
866
- import WebSocket7 from "ws";
967
+ import WebSocket8 from "ws";
867
968
  function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
868
969
  return new Promise((resolve, reject) => {
869
- const ws = new WebSocket7(wsUrl, { headers: { Cookie: cookieStr } });
970
+ const ws = new WebSocket8(wsUrl, { headers: { Cookie: cookieStr } });
870
971
  let atmosphereId = null;
871
972
  const timer = setTimeout(() => {
872
973
  ws.close();
@@ -901,7 +1002,11 @@ async function login(ctx) {
901
1002
  data: {
902
1003
  username: ctx.config.username,
903
1004
  password: ctx.config.password,
904
- domain: ctx.config.broker
1005
+ // TODO:: take a look at this below, domain nor vendor seems required. it works if i comment out both.
1006
+ // however i still use it since i see brokers use it as well in the login endpoint.
1007
+ // domain: ctx.config.broker,
1008
+ vendor: ctx.config.broker
1009
+ // END TODO::
905
1010
  },
906
1011
  headers: { "Content-Type": "application/json" }
907
1012
  },
@@ -962,7 +1067,7 @@ async function switchAccount(ctx, accountId) {
962
1067
  ctx.throwError("ACCOUNT_SWITCH_ERROR" /* ACCOUNT_SWITCH_ERROR */, `Error switching account: ${message}`);
963
1068
  }
964
1069
  }
965
- async function connect(ctx) {
1070
+ async function auth(ctx) {
966
1071
  await login(ctx);
967
1072
  await fetchCsrf(ctx);
968
1073
  if (ctx.debug) clearDebugLog();
@@ -982,112 +1087,85 @@ async function connect(ctx) {
982
1087
  ctx.accountId = reconnect.accountId;
983
1088
  }
984
1089
  }
1090
+ async function connect(ctx) {
1091
+ await auth(ctx);
1092
+ const wsManager = new WsManager();
1093
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
1094
+ const cookieStr = Cookies.serialize(ctx.cookies);
1095
+ await wsManager.connect(wsUrl, cookieStr, ctx.debug);
1096
+ ctx.wsManager = wsManager;
1097
+ }
1098
+ function disconnect(ctx) {
1099
+ if (ctx.wsManager) {
1100
+ ctx.wsManager.close();
1101
+ ctx.wsManager = null;
1102
+ }
1103
+ }
985
1104
 
986
1105
  // src/client.ts
987
- var DxtradeClient = class {
988
- _ctx;
989
- constructor(config) {
990
- const callbacks = config.callbacks ?? {};
991
- this._ctx = {
992
- config,
993
- callbacks,
994
- cookies: {},
995
- csrf: null,
996
- accountId: config.accountId ?? null,
997
- atmosphereId: null,
998
- broker: config.broker,
999
- retries: config.retries ?? 3,
1000
- debug: config.debug ?? false,
1001
- ensureSession() {
1002
- if (!this.csrf) {
1003
- throw new DxtradeError(
1004
- "NO_SESSION" /* NO_SESSION */,
1005
- "No active session. Call login() and fetchCsrf() or connect() first."
1006
- );
1007
- }
1008
- },
1009
- throwError(code, message) {
1010
- const error = new DxtradeError(code, message);
1011
- callbacks.onError?.(error);
1012
- throw error;
1013
- }
1014
- };
1106
+ var PositionsDomain = class {
1107
+ constructor(_ctx) {
1108
+ this._ctx = _ctx;
1015
1109
  }
1016
- /** Authenticate with the broker using username and password. */
1017
- async login() {
1018
- return login(this._ctx);
1110
+ /** Get all open positions via WebSocket. */
1111
+ get() {
1112
+ return getPositions(this._ctx);
1019
1113
  }
1020
- /** Fetch the CSRF token required for authenticated requests. */
1021
- async fetchCsrf() {
1022
- return fetchCsrf(this._ctx);
1114
+ /** Close a position. Supports partial closes by specifying a quantity smaller than the full position size. */
1115
+ close(params) {
1116
+ return closePosition(this._ctx, params);
1023
1117
  }
1024
- /** Switch to a specific trading account by ID. */
1025
- async switchAccount(accountId) {
1026
- return switchAccount(this._ctx, accountId);
1118
+ /** Close all open positions with market orders. */
1119
+ closeAll() {
1120
+ return closeAllPositions(this._ctx);
1027
1121
  }
1028
- /** Connect to the broker: login, fetch CSRF, WebSocket handshake, and optional account switch. */
1029
- async connect() {
1030
- return connect(this._ctx);
1122
+ /** Get position-level P&L metrics via WebSocket. */
1123
+ metrics() {
1124
+ return getPositionMetrics(this._ctx);
1031
1125
  }
1032
- /** Search for symbols matching the given text (e.g. "EURUSD", "BTC"). */
1033
- async getSymbolSuggestions(text) {
1034
- return getSymbolSuggestions(this._ctx, text);
1126
+ /** Stream real-time position updates. Requires connect(). Returns unsubscribe function. */
1127
+ stream(callback) {
1128
+ return streamPositions(this._ctx, callback);
1035
1129
  }
1036
- /** Get detailed instrument info for a symbol, including volume limits and lot size. */
1037
- async getSymbolInfo(symbol) {
1038
- return getSymbolInfo(this._ctx, symbol);
1130
+ };
1131
+ var OrdersDomain = class {
1132
+ constructor(_ctx) {
1133
+ this._ctx = _ctx;
1039
1134
  }
1040
- /** Get order size limits and stop/limit distances for all symbols. */
1041
- async getSymbolLimits() {
1042
- return getSymbolLimits(this._ctx);
1135
+ /** Get all pending/open orders via WebSocket. */
1136
+ get() {
1137
+ return getOrders(this._ctx);
1043
1138
  }
1044
1139
  /**
1045
1140
  * Submit a trading order and wait for WebSocket confirmation.
1046
1141
  * Supports market, limit, and stop orders with optional stop loss and take profit.
1047
1142
  */
1048
- async submitOrder(params) {
1143
+ submit(params) {
1049
1144
  return submitOrder(this._ctx, params);
1050
1145
  }
1051
- /** Get all pending/open orders via WebSocket. */
1052
- async getOrders() {
1053
- return getOrders(this._ctx);
1054
- }
1055
1146
  /** Cancel a single pending order by its order chain ID. */
1056
- async cancelOrder(orderChainId) {
1147
+ cancel(orderChainId) {
1057
1148
  return cancelOrder(this._ctx, orderChainId);
1058
1149
  }
1059
1150
  /** Cancel all pending orders. */
1060
- async cancelAllOrders() {
1151
+ cancelAll() {
1061
1152
  return cancelAllOrders(this._ctx);
1062
1153
  }
1154
+ };
1155
+ var AccountDomain = class {
1156
+ constructor(_ctx) {
1157
+ this._ctx = _ctx;
1158
+ }
1063
1159
  /** Get account metrics including equity, balance, margin, and open P&L. */
1064
- async getAccountMetrics() {
1160
+ metrics() {
1065
1161
  return getAccountMetrics(this._ctx);
1066
1162
  }
1067
- /** Get all open positions via WebSocket. */
1068
- async getPositions() {
1069
- return getPositions(this._ctx);
1070
- }
1071
- /**
1072
- * Close a position. Supports partial closes by specifying a quantity smaller than the full position size.
1073
- */
1074
- async closePosition(position) {
1075
- return closePosition(this._ctx, position);
1076
- }
1077
- /** Close all open positions with market orders. */
1078
- async closeAllPositions() {
1079
- return closeAllPositions(this._ctx);
1080
- }
1081
- /** Get position-level P&L metrics via WebSocket. */
1082
- async getPositionMetrics() {
1083
- return getPositionMetrics(this._ctx);
1084
- }
1085
1163
  /**
1086
1164
  * Fetch trade journal entries for a date range.
1087
1165
  * @param params.from - Start timestamp (Unix ms)
1088
1166
  * @param params.to - End timestamp (Unix ms)
1089
1167
  */
1090
- async getTradeJournal(params) {
1168
+ tradeJournal(params) {
1091
1169
  return getTradeJournal(this._ctx, params);
1092
1170
  }
1093
1171
  /**
@@ -1095,16 +1173,39 @@ var DxtradeClient = class {
1095
1173
  * @param params.from - Start timestamp (Unix ms)
1096
1174
  * @param params.to - End timestamp (Unix ms)
1097
1175
  */
1098
- async getTradeHistory(params) {
1176
+ tradeHistory(params) {
1099
1177
  return getTradeHistory(this._ctx, params);
1100
1178
  }
1179
+ };
1180
+ var SymbolsDomain = class {
1181
+ constructor(_ctx) {
1182
+ this._ctx = _ctx;
1183
+ }
1184
+ /** Search for symbols matching the given text (e.g. "EURUSD", "BTC"). */
1185
+ search(text) {
1186
+ return getSymbolSuggestions(this._ctx, text);
1187
+ }
1188
+ /** Get detailed instrument info for a symbol, including volume limits and lot size. */
1189
+ info(symbol) {
1190
+ return getSymbolInfo(this._ctx, symbol);
1191
+ }
1192
+ /** Get order size limits and stop/limit distances for all symbols. */
1193
+ limits() {
1194
+ return getSymbolLimits(this._ctx);
1195
+ }
1196
+ };
1197
+ var InstrumentsDomain = class {
1198
+ constructor(_ctx) {
1199
+ this._ctx = _ctx;
1200
+ }
1101
1201
  /** Get all available instruments, optionally filtered by partial match (e.g. `{ type: "FOREX" }`). */
1102
- async getInstruments(params = {}) {
1202
+ get(params = {}) {
1103
1203
  return getInstruments(this._ctx, params);
1104
1204
  }
1105
- /** Fetch PnL assessments for an instrument within a date range. */
1106
- async getAssessments(params) {
1107
- return getAssessments(this._ctx, params);
1205
+ };
1206
+ var OhlcDomain = class {
1207
+ constructor(_ctx) {
1208
+ this._ctx = _ctx;
1108
1209
  }
1109
1210
  /**
1110
1211
  * Fetch OHLC price bars for a symbol.
@@ -1114,10 +1215,92 @@ var DxtradeClient = class {
1114
1215
  * @param params.maxBars - Maximum bars to return (default: 3500)
1115
1216
  * @param params.priceField - "bid" or "ask" (default: "bid")
1116
1217
  */
1117
- async getOHLC(params) {
1218
+ get(params) {
1118
1219
  return getOHLC(this._ctx, params);
1119
1220
  }
1120
1221
  };
1222
+ var AssessmentsDomain = class {
1223
+ constructor(_ctx) {
1224
+ this._ctx = _ctx;
1225
+ }
1226
+ /** Fetch PnL assessments for an instrument within a date range. */
1227
+ get(params) {
1228
+ return getAssessments(this._ctx, params);
1229
+ }
1230
+ };
1231
+ var DxtradeClient = class {
1232
+ _ctx;
1233
+ /** Position operations: get, close, metrics, streaming. */
1234
+ positions;
1235
+ /** Order operations: get, submit, cancel. */
1236
+ orders;
1237
+ /** Account operations: metrics, trade journal, trade history. */
1238
+ account;
1239
+ /** Symbol operations: search, info, limits. */
1240
+ symbols;
1241
+ /** Instrument operations: get (with optional filtering). */
1242
+ instruments;
1243
+ /** OHLC price bar operations: get. */
1244
+ ohlc;
1245
+ /** PnL assessment operations: get. */
1246
+ assessments;
1247
+ constructor(config) {
1248
+ const callbacks = config.callbacks ?? {};
1249
+ this._ctx = {
1250
+ config,
1251
+ callbacks,
1252
+ cookies: {},
1253
+ csrf: null,
1254
+ accountId: config.accountId ?? null,
1255
+ atmosphereId: null,
1256
+ wsManager: null,
1257
+ broker: config.broker,
1258
+ retries: config.retries ?? 3,
1259
+ debug: config.debug ?? false,
1260
+ ensureSession() {
1261
+ if (!this.csrf) {
1262
+ throw new DxtradeError("NO_SESSION" /* NO_SESSION */, "No active session. Call auth() or connect() first.");
1263
+ }
1264
+ },
1265
+ throwError(code, message) {
1266
+ const error = new DxtradeError(code, message);
1267
+ callbacks.onError?.(error);
1268
+ throw error;
1269
+ }
1270
+ };
1271
+ this.positions = new PositionsDomain(this._ctx);
1272
+ this.orders = new OrdersDomain(this._ctx);
1273
+ this.account = new AccountDomain(this._ctx);
1274
+ this.symbols = new SymbolsDomain(this._ctx);
1275
+ this.instruments = new InstrumentsDomain(this._ctx);
1276
+ this.ohlc = new OhlcDomain(this._ctx);
1277
+ this.assessments = new AssessmentsDomain(this._ctx);
1278
+ }
1279
+ /** Authenticate with the broker using username and password. */
1280
+ async login() {
1281
+ return login(this._ctx);
1282
+ }
1283
+ /** Fetch the CSRF token required for authenticated requests. */
1284
+ async fetchCsrf() {
1285
+ return fetchCsrf(this._ctx);
1286
+ }
1287
+ /** Switch to a specific trading account by ID. */
1288
+ async switchAccount(accountId) {
1289
+ return switchAccount(this._ctx, accountId);
1290
+ }
1291
+ /** Authenticate and establish a session: login, fetch CSRF, WebSocket handshake, and optional account switch. */
1292
+ async auth() {
1293
+ return auth(this._ctx);
1294
+ }
1295
+ /** Connect to the broker with a persistent WebSocket: auth + persistent WS for data reuse and streaming. */
1296
+ async connect() {
1297
+ return connect(this._ctx);
1298
+ }
1299
+ /** Close the persistent WebSocket connection. */
1300
+ disconnect() {
1301
+ return disconnect(this._ctx);
1302
+ }
1303
+ };
1121
1304
  export {
1122
1305
  ACTION,
1123
1306
  BROKER,