@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.js CHANGED
@@ -66,7 +66,7 @@ var endpoints = {
66
66
  assessments: (base) => `${base}/api/assessments`,
67
67
  websocket: (base, atmosphereId) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery(atmosphereId),
68
68
  tradeJournal: (base, params) => `${base}/api/tradejournal?from=${params.from}&to=${params.to}`,
69
- tradeHistory: (base, params) => `${base}/api/history?from=${params.from}&to=${params.to}&orderId=`,
69
+ tradeHistory: (base, params) => `${base}/api/history?from=${params.from}&to=${params.to}`,
70
70
  subscribeInstruments: (base) => `${base}/api/instruments/subscribeInstrumentSymbols`,
71
71
  charts: (base) => `${base}/api/charts`
72
72
  };
@@ -125,6 +125,9 @@ var ERROR = /* @__PURE__ */ ((ERROR2) => {
125
125
  ERROR2["TRADE_JOURNAL_ERROR"] = "TRADE_JOURNAL_ERROR";
126
126
  ERROR2["TRADE_HISTORY_ERROR"] = "TRADE_HISTORY_ERROR";
127
127
  ERROR2["ASSESSMENTS_ERROR"] = "ASSESSMENTS_ERROR";
128
+ ERROR2["RATE_LIMITED"] = "RATE_LIMITED";
129
+ ERROR2["WS_MANAGER_ERROR"] = "WS_MANAGER_ERROR";
130
+ ERROR2["STREAM_REQUIRES_CONNECT"] = "STREAM_REQUIRES_CONNECT";
128
131
  return ERROR2;
129
132
  })(ERROR || {});
130
133
  var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
@@ -163,7 +166,7 @@ var DxtradeError = class extends Error {
163
166
  };
164
167
 
165
168
  // src/domains/account/account.ts
166
- var import_ws = __toESM(require("ws"));
169
+ var import_ws2 = __toESM(require("ws"));
167
170
 
168
171
  // src/utils/cookies.ts
169
172
  var Cookies = class {
@@ -215,7 +218,10 @@ async function retryRequest(config, retries = 3) {
215
218
  return await (0, import_axios.default)(config);
216
219
  } catch (error) {
217
220
  const message = error instanceof Error ? error.message : "Unknown error";
218
- console.warn(`[dxtrade-api] Attempt ${attempt} failed: ${message}`);
221
+ console.warn(`[dxtrade-api] Attempt ${attempt} failed: ${message}`, config.url);
222
+ if ((0, import_axios.isAxiosError)(error) && error.response?.status === 429) {
223
+ throw new DxtradeError("RATE_LIMITED" /* RATE_LIMITED */, "Rate limited (429). Too many requests \u2014 try again later.");
224
+ }
219
225
  if (attempt === retries) throw error;
220
226
  await new Promise((res) => setTimeout(res, 1e3 * attempt));
221
227
  }
@@ -258,13 +264,83 @@ function parseWsData(data) {
258
264
  }
259
265
  }
260
266
 
267
+ // src/utils/ws-manager.ts
268
+ var import_events = require("events");
269
+ var import_ws = __toESM(require("ws"));
270
+ var WsManager = class extends import_events.EventEmitter {
271
+ _ws = null;
272
+ _cache = /* @__PURE__ */ new Map();
273
+ connect(wsUrl, cookieStr, debug = false) {
274
+ return new Promise((resolve, reject) => {
275
+ const ws = new import_ws.default(wsUrl, { headers: { Cookie: cookieStr } });
276
+ ws.on("open", () => {
277
+ this._ws = ws;
278
+ resolve();
279
+ });
280
+ ws.on("message", (data) => {
281
+ const msg = parseWsData(data);
282
+ if (shouldLog(msg, debug)) debugLog(msg);
283
+ if (typeof msg === "string") return;
284
+ const payload = msg;
285
+ this._cache.set(payload.type, payload.body);
286
+ this.emit(payload.type, payload.body);
287
+ });
288
+ ws.on("error", (error) => {
289
+ if (!this._ws) {
290
+ return reject(error);
291
+ }
292
+ this.emit("error", error);
293
+ });
294
+ ws.on("close", () => {
295
+ this._ws = null;
296
+ this.emit("close");
297
+ });
298
+ });
299
+ }
300
+ waitFor(type, timeout = 3e4) {
301
+ const cached = this._cache.get(type);
302
+ if (cached !== void 0) {
303
+ return Promise.resolve(cached);
304
+ }
305
+ return new Promise((resolve, reject) => {
306
+ const timer = setTimeout(() => {
307
+ this.removeListener(type, onMessage);
308
+ reject(new Error(`WsManager: timed out waiting for ${type}`));
309
+ }, timeout);
310
+ const onMessage = (body) => {
311
+ clearTimeout(timer);
312
+ resolve(body);
313
+ };
314
+ this.once(type, onMessage);
315
+ });
316
+ }
317
+ getCached(type) {
318
+ return this._cache.get(type);
319
+ }
320
+ close() {
321
+ if (this._ws) {
322
+ this._ws.close();
323
+ this._ws = null;
324
+ }
325
+ this._cache.clear();
326
+ this.removeAllListeners();
327
+ }
328
+ get isConnected() {
329
+ return this._ws !== null && this._ws.readyState === import_ws.default.OPEN;
330
+ }
331
+ };
332
+
261
333
  // src/domains/account/account.ts
262
334
  async function getAccountMetrics(ctx, timeout = 3e4) {
263
335
  ctx.ensureSession();
336
+ if (ctx.wsManager) {
337
+ const body = await ctx.wsManager.waitFor("ACCOUNT_METRICS" /* ACCOUNT_METRICS */, timeout);
338
+ return body.allMetrics;
339
+ }
264
340
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
265
341
  const cookieStr = Cookies.serialize(ctx.cookies);
266
342
  return new Promise((resolve, reject) => {
267
- const ws = new import_ws.default(wsUrl, { headers: { Cookie: cookieStr } });
343
+ const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
268
344
  const timer = setTimeout(() => {
269
345
  ws.close();
270
346
  reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT" /* ACCOUNT_METRICS_TIMEOUT */, "Account metrics timed out"));
@@ -290,12 +366,11 @@ async function getAccountMetrics(ctx, timeout = 3e4) {
290
366
  async function getTradeHistory(ctx, params) {
291
367
  ctx.ensureSession();
292
368
  try {
293
- const cookieStr = Cookies.serialize(ctx.cookies);
294
369
  const response = await retryRequest(
295
370
  {
296
- method: "GET",
371
+ method: "POST",
297
372
  url: endpoints.tradeHistory(ctx.broker, params),
298
- headers: { ...baseHeaders(), Cookie: cookieStr }
373
+ headers: authHeaders(ctx.csrf, Cookies.serialize(ctx.cookies))
299
374
  },
300
375
  ctx.retries
301
376
  );
@@ -367,13 +442,13 @@ async function getAssessments(ctx, params) {
367
442
  }
368
443
 
369
444
  // src/domains/instrument/instrument.ts
370
- var import_ws2 = __toESM(require("ws"));
445
+ var import_ws3 = __toESM(require("ws"));
371
446
  async function getInstruments(ctx, params = {}, timeout = 3e4) {
372
447
  ctx.ensureSession();
373
448
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
374
449
  const cookieStr = Cookies.serialize(ctx.cookies);
375
450
  return new Promise((resolve, reject) => {
376
- const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
451
+ const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
377
452
  const timer = setTimeout(() => {
378
453
  ws.close();
379
454
  reject(new DxtradeError("INSTRUMENTS_TIMEOUT" /* INSTRUMENTS_TIMEOUT */, "Instruments request timed out"));
@@ -400,7 +475,7 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
400
475
  return true;
401
476
  })
402
477
  );
403
- }, 0);
478
+ }, 200);
404
479
  }
405
480
  });
406
481
  ws.on("error", (error) => {
@@ -412,7 +487,7 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
412
487
  }
413
488
 
414
489
  // src/domains/ohlc/ohlc.ts
415
- var import_ws3 = __toESM(require("ws"));
490
+ var import_ws4 = __toESM(require("ws"));
416
491
  async function getOHLC(ctx, params, timeout = 3e4) {
417
492
  ctx.ensureSession();
418
493
  const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
@@ -420,7 +495,7 @@ async function getOHLC(ctx, params, timeout = 3e4) {
420
495
  const cookieStr = Cookies.serialize(ctx.cookies);
421
496
  const headers = authHeaders(ctx.csrf, cookieStr);
422
497
  return new Promise((resolve, reject) => {
423
- const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
498
+ const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
424
499
  const bars = [];
425
500
  let putsSent = false;
426
501
  let initSettleTimer = null;
@@ -511,10 +586,10 @@ async function getOHLC(ctx, params, timeout = 3e4) {
511
586
 
512
587
  // src/domains/order/order.ts
513
588
  var import_crypto = __toESM(require("crypto"));
514
- var import_ws5 = __toESM(require("ws"));
589
+ var import_ws6 = __toESM(require("ws"));
515
590
 
516
591
  // src/domains/symbol/symbol.ts
517
- var import_ws4 = __toESM(require("ws"));
592
+ var import_ws5 = __toESM(require("ws"));
518
593
  async function getSymbolSuggestions(ctx, text) {
519
594
  ctx.ensureSession();
520
595
  try {
@@ -566,7 +641,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
566
641
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
567
642
  const cookieStr = Cookies.serialize(ctx.cookies);
568
643
  return new Promise((resolve, reject) => {
569
- const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
644
+ const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
570
645
  const timer = setTimeout(() => {
571
646
  ws.close();
572
647
  reject(new DxtradeError("LIMITS_TIMEOUT" /* LIMITS_TIMEOUT */, "Symbol limits request timed out"));
@@ -586,7 +661,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
586
661
  clearTimeout(timer);
587
662
  ws.close();
588
663
  resolve(limits);
589
- }, 0);
664
+ }, 200);
590
665
  }
591
666
  });
592
667
  ws.on("error", (error) => {
@@ -599,7 +674,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
599
674
 
600
675
  // src/domains/order/order.ts
601
676
  function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
602
- const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
677
+ const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
603
678
  let settled = false;
604
679
  const ready = new Promise((resolve) => {
605
680
  ws.on("open", resolve);
@@ -666,10 +741,13 @@ function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
666
741
  }
667
742
  async function getOrders(ctx, timeout = 3e4) {
668
743
  ctx.ensureSession();
744
+ if (ctx.wsManager) {
745
+ return ctx.wsManager.waitFor("ORDERS" /* ORDERS */, timeout);
746
+ }
669
747
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
670
748
  const cookieStr = Cookies.serialize(ctx.cookies);
671
749
  return new Promise((resolve, reject) => {
672
- const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
750
+ const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
673
751
  const timer = setTimeout(() => {
674
752
  ws.close();
675
753
  reject(new DxtradeError("ORDERS_TIMEOUT" /* ORDERS_TIMEOUT */, "Orders request timed out"));
@@ -813,13 +891,33 @@ async function submitOrder(ctx, params) {
813
891
  }
814
892
 
815
893
  // src/domains/position/position.ts
816
- var import_ws6 = __toESM(require("ws"));
894
+ var import_ws7 = __toESM(require("ws"));
895
+ function streamPositions(ctx, callback) {
896
+ if (!ctx.wsManager) {
897
+ ctx.throwError(
898
+ "STREAM_REQUIRES_CONNECT" /* STREAM_REQUIRES_CONNECT */,
899
+ "Streaming requires a persistent WebSocket. Use connect() instead of auth()."
900
+ );
901
+ }
902
+ const listener = (body) => callback(body);
903
+ ctx.wsManager.on("POSITIONS" /* POSITIONS */, listener);
904
+ const cached = ctx.wsManager.getCached("POSITIONS" /* POSITIONS */);
905
+ if (cached !== void 0) {
906
+ callback(cached);
907
+ }
908
+ return () => {
909
+ ctx.wsManager?.removeListener("POSITIONS" /* POSITIONS */, listener);
910
+ };
911
+ }
817
912
  async function getPositions(ctx) {
818
913
  ctx.ensureSession();
914
+ if (ctx.wsManager) {
915
+ return ctx.wsManager.waitFor("POSITIONS" /* POSITIONS */);
916
+ }
819
917
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
820
918
  const cookieStr = Cookies.serialize(ctx.cookies);
821
919
  return new Promise((resolve, reject) => {
822
- const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
920
+ const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
823
921
  const timer = setTimeout(() => {
824
922
  ws.close();
825
923
  reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT" /* ACCOUNT_POSITIONS_TIMEOUT */, "Account positions timed out"));
@@ -843,10 +941,13 @@ async function getPositions(ctx) {
843
941
  }
844
942
  async function getPositionMetrics(ctx, timeout = 3e4) {
845
943
  ctx.ensureSession();
944
+ if (ctx.wsManager) {
945
+ return ctx.wsManager.waitFor("POSITION_METRICS" /* POSITION_METRICS */, timeout);
946
+ }
846
947
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
847
948
  const cookieStr = Cookies.serialize(ctx.cookies);
848
949
  return new Promise((resolve, reject) => {
849
- const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
950
+ const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
850
951
  const timer = setTimeout(() => {
851
952
  ws.close();
852
953
  reject(new DxtradeError("POSITION_METRICS_TIMEOUT" /* POSITION_METRICS_TIMEOUT */, "Position metrics timed out"));
@@ -908,10 +1009,10 @@ async function closePosition(ctx, data) {
908
1009
  }
909
1010
 
910
1011
  // src/domains/session/session.ts
911
- var import_ws7 = __toESM(require("ws"));
1012
+ var import_ws8 = __toESM(require("ws"));
912
1013
  function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
913
1014
  return new Promise((resolve, reject) => {
914
- const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
1015
+ const ws = new import_ws8.default(wsUrl, { headers: { Cookie: cookieStr } });
915
1016
  let atmosphereId = null;
916
1017
  const timer = setTimeout(() => {
917
1018
  ws.close();
@@ -946,7 +1047,11 @@ async function login(ctx) {
946
1047
  data: {
947
1048
  username: ctx.config.username,
948
1049
  password: ctx.config.password,
949
- domain: ctx.config.broker
1050
+ // TODO:: take a look at this below, domain nor vendor seems required. it works if i comment out both.
1051
+ // however i still use it since i see brokers use it as well in the login endpoint.
1052
+ // domain: ctx.config.broker,
1053
+ vendor: ctx.config.broker
1054
+ // END TODO::
950
1055
  },
951
1056
  headers: { "Content-Type": "application/json" }
952
1057
  },
@@ -1007,7 +1112,7 @@ async function switchAccount(ctx, accountId) {
1007
1112
  ctx.throwError("ACCOUNT_SWITCH_ERROR" /* ACCOUNT_SWITCH_ERROR */, `Error switching account: ${message}`);
1008
1113
  }
1009
1114
  }
1010
- async function connect(ctx) {
1115
+ async function auth(ctx) {
1011
1116
  await login(ctx);
1012
1117
  await fetchCsrf(ctx);
1013
1118
  if (ctx.debug) clearDebugLog();
@@ -1027,112 +1132,85 @@ async function connect(ctx) {
1027
1132
  ctx.accountId = reconnect.accountId;
1028
1133
  }
1029
1134
  }
1135
+ async function connect(ctx) {
1136
+ await auth(ctx);
1137
+ const wsManager = new WsManager();
1138
+ const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
1139
+ const cookieStr = Cookies.serialize(ctx.cookies);
1140
+ await wsManager.connect(wsUrl, cookieStr, ctx.debug);
1141
+ ctx.wsManager = wsManager;
1142
+ }
1143
+ function disconnect(ctx) {
1144
+ if (ctx.wsManager) {
1145
+ ctx.wsManager.close();
1146
+ ctx.wsManager = null;
1147
+ }
1148
+ }
1030
1149
 
1031
1150
  // src/client.ts
1032
- var DxtradeClient = class {
1033
- _ctx;
1034
- constructor(config) {
1035
- const callbacks = config.callbacks ?? {};
1036
- this._ctx = {
1037
- config,
1038
- callbacks,
1039
- cookies: {},
1040
- csrf: null,
1041
- accountId: config.accountId ?? null,
1042
- atmosphereId: null,
1043
- broker: config.broker,
1044
- retries: config.retries ?? 3,
1045
- debug: config.debug ?? false,
1046
- ensureSession() {
1047
- if (!this.csrf) {
1048
- throw new DxtradeError(
1049
- "NO_SESSION" /* NO_SESSION */,
1050
- "No active session. Call login() and fetchCsrf() or connect() first."
1051
- );
1052
- }
1053
- },
1054
- throwError(code, message) {
1055
- const error = new DxtradeError(code, message);
1056
- callbacks.onError?.(error);
1057
- throw error;
1058
- }
1059
- };
1151
+ var PositionsDomain = class {
1152
+ constructor(_ctx) {
1153
+ this._ctx = _ctx;
1060
1154
  }
1061
- /** Authenticate with the broker using username and password. */
1062
- async login() {
1063
- return login(this._ctx);
1155
+ /** Get all open positions via WebSocket. */
1156
+ get() {
1157
+ return getPositions(this._ctx);
1064
1158
  }
1065
- /** Fetch the CSRF token required for authenticated requests. */
1066
- async fetchCsrf() {
1067
- return fetchCsrf(this._ctx);
1159
+ /** Close a position. Supports partial closes by specifying a quantity smaller than the full position size. */
1160
+ close(params) {
1161
+ return closePosition(this._ctx, params);
1068
1162
  }
1069
- /** Switch to a specific trading account by ID. */
1070
- async switchAccount(accountId) {
1071
- return switchAccount(this._ctx, accountId);
1163
+ /** Close all open positions with market orders. */
1164
+ closeAll() {
1165
+ return closeAllPositions(this._ctx);
1072
1166
  }
1073
- /** Connect to the broker: login, fetch CSRF, WebSocket handshake, and optional account switch. */
1074
- async connect() {
1075
- return connect(this._ctx);
1167
+ /** Get position-level P&L metrics via WebSocket. */
1168
+ metrics() {
1169
+ return getPositionMetrics(this._ctx);
1076
1170
  }
1077
- /** Search for symbols matching the given text (e.g. "EURUSD", "BTC"). */
1078
- async getSymbolSuggestions(text) {
1079
- return getSymbolSuggestions(this._ctx, text);
1171
+ /** Stream real-time position updates. Requires connect(). Returns unsubscribe function. */
1172
+ stream(callback) {
1173
+ return streamPositions(this._ctx, callback);
1080
1174
  }
1081
- /** Get detailed instrument info for a symbol, including volume limits and lot size. */
1082
- async getSymbolInfo(symbol) {
1083
- return getSymbolInfo(this._ctx, symbol);
1175
+ };
1176
+ var OrdersDomain = class {
1177
+ constructor(_ctx) {
1178
+ this._ctx = _ctx;
1084
1179
  }
1085
- /** Get order size limits and stop/limit distances for all symbols. */
1086
- async getSymbolLimits() {
1087
- return getSymbolLimits(this._ctx);
1180
+ /** Get all pending/open orders via WebSocket. */
1181
+ get() {
1182
+ return getOrders(this._ctx);
1088
1183
  }
1089
1184
  /**
1090
1185
  * Submit a trading order and wait for WebSocket confirmation.
1091
1186
  * Supports market, limit, and stop orders with optional stop loss and take profit.
1092
1187
  */
1093
- async submitOrder(params) {
1188
+ submit(params) {
1094
1189
  return submitOrder(this._ctx, params);
1095
1190
  }
1096
- /** Get all pending/open orders via WebSocket. */
1097
- async getOrders() {
1098
- return getOrders(this._ctx);
1099
- }
1100
1191
  /** Cancel a single pending order by its order chain ID. */
1101
- async cancelOrder(orderChainId) {
1192
+ cancel(orderChainId) {
1102
1193
  return cancelOrder(this._ctx, orderChainId);
1103
1194
  }
1104
1195
  /** Cancel all pending orders. */
1105
- async cancelAllOrders() {
1196
+ cancelAll() {
1106
1197
  return cancelAllOrders(this._ctx);
1107
1198
  }
1199
+ };
1200
+ var AccountDomain = class {
1201
+ constructor(_ctx) {
1202
+ this._ctx = _ctx;
1203
+ }
1108
1204
  /** Get account metrics including equity, balance, margin, and open P&L. */
1109
- async getAccountMetrics() {
1205
+ metrics() {
1110
1206
  return getAccountMetrics(this._ctx);
1111
1207
  }
1112
- /** Get all open positions via WebSocket. */
1113
- async getPositions() {
1114
- return getPositions(this._ctx);
1115
- }
1116
- /**
1117
- * Close a position. Supports partial closes by specifying a quantity smaller than the full position size.
1118
- */
1119
- async closePosition(position) {
1120
- return closePosition(this._ctx, position);
1121
- }
1122
- /** Close all open positions with market orders. */
1123
- async closeAllPositions() {
1124
- return closeAllPositions(this._ctx);
1125
- }
1126
- /** Get position-level P&L metrics via WebSocket. */
1127
- async getPositionMetrics() {
1128
- return getPositionMetrics(this._ctx);
1129
- }
1130
1208
  /**
1131
1209
  * Fetch trade journal entries for a date range.
1132
1210
  * @param params.from - Start timestamp (Unix ms)
1133
1211
  * @param params.to - End timestamp (Unix ms)
1134
1212
  */
1135
- async getTradeJournal(params) {
1213
+ tradeJournal(params) {
1136
1214
  return getTradeJournal(this._ctx, params);
1137
1215
  }
1138
1216
  /**
@@ -1140,16 +1218,39 @@ var DxtradeClient = class {
1140
1218
  * @param params.from - Start timestamp (Unix ms)
1141
1219
  * @param params.to - End timestamp (Unix ms)
1142
1220
  */
1143
- async getTradeHistory(params) {
1221
+ tradeHistory(params) {
1144
1222
  return getTradeHistory(this._ctx, params);
1145
1223
  }
1224
+ };
1225
+ var SymbolsDomain = class {
1226
+ constructor(_ctx) {
1227
+ this._ctx = _ctx;
1228
+ }
1229
+ /** Search for symbols matching the given text (e.g. "EURUSD", "BTC"). */
1230
+ search(text) {
1231
+ return getSymbolSuggestions(this._ctx, text);
1232
+ }
1233
+ /** Get detailed instrument info for a symbol, including volume limits and lot size. */
1234
+ info(symbol) {
1235
+ return getSymbolInfo(this._ctx, symbol);
1236
+ }
1237
+ /** Get order size limits and stop/limit distances for all symbols. */
1238
+ limits() {
1239
+ return getSymbolLimits(this._ctx);
1240
+ }
1241
+ };
1242
+ var InstrumentsDomain = class {
1243
+ constructor(_ctx) {
1244
+ this._ctx = _ctx;
1245
+ }
1146
1246
  /** Get all available instruments, optionally filtered by partial match (e.g. `{ type: "FOREX" }`). */
1147
- async getInstruments(params = {}) {
1247
+ get(params = {}) {
1148
1248
  return getInstruments(this._ctx, params);
1149
1249
  }
1150
- /** Fetch PnL assessments for an instrument within a date range. */
1151
- async getAssessments(params) {
1152
- return getAssessments(this._ctx, params);
1250
+ };
1251
+ var OhlcDomain = class {
1252
+ constructor(_ctx) {
1253
+ this._ctx = _ctx;
1153
1254
  }
1154
1255
  /**
1155
1256
  * Fetch OHLC price bars for a symbol.
@@ -1159,10 +1260,92 @@ var DxtradeClient = class {
1159
1260
  * @param params.maxBars - Maximum bars to return (default: 3500)
1160
1261
  * @param params.priceField - "bid" or "ask" (default: "bid")
1161
1262
  */
1162
- async getOHLC(params) {
1263
+ get(params) {
1163
1264
  return getOHLC(this._ctx, params);
1164
1265
  }
1165
1266
  };
1267
+ var AssessmentsDomain = class {
1268
+ constructor(_ctx) {
1269
+ this._ctx = _ctx;
1270
+ }
1271
+ /** Fetch PnL assessments for an instrument within a date range. */
1272
+ get(params) {
1273
+ return getAssessments(this._ctx, params);
1274
+ }
1275
+ };
1276
+ var DxtradeClient = class {
1277
+ _ctx;
1278
+ /** Position operations: get, close, metrics, streaming. */
1279
+ positions;
1280
+ /** Order operations: get, submit, cancel. */
1281
+ orders;
1282
+ /** Account operations: metrics, trade journal, trade history. */
1283
+ account;
1284
+ /** Symbol operations: search, info, limits. */
1285
+ symbols;
1286
+ /** Instrument operations: get (with optional filtering). */
1287
+ instruments;
1288
+ /** OHLC price bar operations: get. */
1289
+ ohlc;
1290
+ /** PnL assessment operations: get. */
1291
+ assessments;
1292
+ constructor(config) {
1293
+ const callbacks = config.callbacks ?? {};
1294
+ this._ctx = {
1295
+ config,
1296
+ callbacks,
1297
+ cookies: {},
1298
+ csrf: null,
1299
+ accountId: config.accountId ?? null,
1300
+ atmosphereId: null,
1301
+ wsManager: null,
1302
+ broker: config.broker,
1303
+ retries: config.retries ?? 3,
1304
+ debug: config.debug ?? false,
1305
+ ensureSession() {
1306
+ if (!this.csrf) {
1307
+ throw new DxtradeError("NO_SESSION" /* NO_SESSION */, "No active session. Call auth() or connect() first.");
1308
+ }
1309
+ },
1310
+ throwError(code, message) {
1311
+ const error = new DxtradeError(code, message);
1312
+ callbacks.onError?.(error);
1313
+ throw error;
1314
+ }
1315
+ };
1316
+ this.positions = new PositionsDomain(this._ctx);
1317
+ this.orders = new OrdersDomain(this._ctx);
1318
+ this.account = new AccountDomain(this._ctx);
1319
+ this.symbols = new SymbolsDomain(this._ctx);
1320
+ this.instruments = new InstrumentsDomain(this._ctx);
1321
+ this.ohlc = new OhlcDomain(this._ctx);
1322
+ this.assessments = new AssessmentsDomain(this._ctx);
1323
+ }
1324
+ /** Authenticate with the broker using username and password. */
1325
+ async login() {
1326
+ return login(this._ctx);
1327
+ }
1328
+ /** Fetch the CSRF token required for authenticated requests. */
1329
+ async fetchCsrf() {
1330
+ return fetchCsrf(this._ctx);
1331
+ }
1332
+ /** Switch to a specific trading account by ID. */
1333
+ async switchAccount(accountId) {
1334
+ return switchAccount(this._ctx, accountId);
1335
+ }
1336
+ /** Authenticate and establish a session: login, fetch CSRF, WebSocket handshake, and optional account switch. */
1337
+ async auth() {
1338
+ return auth(this._ctx);
1339
+ }
1340
+ /** Connect to the broker with a persistent WebSocket: auth + persistent WS for data reuse and streaming. */
1341
+ async connect() {
1342
+ return connect(this._ctx);
1343
+ }
1344
+ /** Close the persistent WebSocket connection. */
1345
+ disconnect() {
1346
+ return disconnect(this._ctx);
1347
+ }
1348
+ };
1166
1349
  // Annotate the CommonJS export names for ESM import in node:
1167
1350
  0 && (module.exports = {
1168
1351
  ACTION,