@danielgroen/dxtrade-api 1.0.23 → 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 {
@@ -216,7 +219,9 @@ async function retryRequest(config, retries = 3) {
216
219
  } catch (error) {
217
220
  const message = error instanceof Error ? error.message : "Unknown error";
218
221
  console.warn(`[dxtrade-api] Attempt ${attempt} failed: ${message}`, config.url);
219
- if ((0, import_axios.isAxiosError)(error) && error.response?.status === 429) throw error;
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
+ }
220
225
  if (attempt === retries) throw error;
221
226
  await new Promise((res) => setTimeout(res, 1e3 * attempt));
222
227
  }
@@ -259,13 +264,83 @@ function parseWsData(data) {
259
264
  }
260
265
  }
261
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
+
262
333
  // src/domains/account/account.ts
263
334
  async function getAccountMetrics(ctx, timeout = 3e4) {
264
335
  ctx.ensureSession();
336
+ if (ctx.wsManager) {
337
+ const body = await ctx.wsManager.waitFor("ACCOUNT_METRICS" /* ACCOUNT_METRICS */, timeout);
338
+ return body.allMetrics;
339
+ }
265
340
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
266
341
  const cookieStr = Cookies.serialize(ctx.cookies);
267
342
  return new Promise((resolve, reject) => {
268
- const ws = new import_ws.default(wsUrl, { headers: { Cookie: cookieStr } });
343
+ const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
269
344
  const timer = setTimeout(() => {
270
345
  ws.close();
271
346
  reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT" /* ACCOUNT_METRICS_TIMEOUT */, "Account metrics timed out"));
@@ -291,12 +366,11 @@ async function getAccountMetrics(ctx, timeout = 3e4) {
291
366
  async function getTradeHistory(ctx, params) {
292
367
  ctx.ensureSession();
293
368
  try {
294
- const cookieStr = Cookies.serialize(ctx.cookies);
295
369
  const response = await retryRequest(
296
370
  {
297
- method: "GET",
371
+ method: "POST",
298
372
  url: endpoints.tradeHistory(ctx.broker, params),
299
- headers: { ...baseHeaders(), Cookie: cookieStr }
373
+ headers: authHeaders(ctx.csrf, Cookies.serialize(ctx.cookies))
300
374
  },
301
375
  ctx.retries
302
376
  );
@@ -368,13 +442,13 @@ async function getAssessments(ctx, params) {
368
442
  }
369
443
 
370
444
  // src/domains/instrument/instrument.ts
371
- var import_ws2 = __toESM(require("ws"));
445
+ var import_ws3 = __toESM(require("ws"));
372
446
  async function getInstruments(ctx, params = {}, timeout = 3e4) {
373
447
  ctx.ensureSession();
374
448
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
375
449
  const cookieStr = Cookies.serialize(ctx.cookies);
376
450
  return new Promise((resolve, reject) => {
377
- const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
451
+ const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
378
452
  const timer = setTimeout(() => {
379
453
  ws.close();
380
454
  reject(new DxtradeError("INSTRUMENTS_TIMEOUT" /* INSTRUMENTS_TIMEOUT */, "Instruments request timed out"));
@@ -401,7 +475,7 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
401
475
  return true;
402
476
  })
403
477
  );
404
- }, 0);
478
+ }, 200);
405
479
  }
406
480
  });
407
481
  ws.on("error", (error) => {
@@ -413,7 +487,7 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
413
487
  }
414
488
 
415
489
  // src/domains/ohlc/ohlc.ts
416
- var import_ws3 = __toESM(require("ws"));
490
+ var import_ws4 = __toESM(require("ws"));
417
491
  async function getOHLC(ctx, params, timeout = 3e4) {
418
492
  ctx.ensureSession();
419
493
  const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
@@ -421,7 +495,7 @@ async function getOHLC(ctx, params, timeout = 3e4) {
421
495
  const cookieStr = Cookies.serialize(ctx.cookies);
422
496
  const headers = authHeaders(ctx.csrf, cookieStr);
423
497
  return new Promise((resolve, reject) => {
424
- const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
498
+ const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
425
499
  const bars = [];
426
500
  let putsSent = false;
427
501
  let initSettleTimer = null;
@@ -512,10 +586,10 @@ async function getOHLC(ctx, params, timeout = 3e4) {
512
586
 
513
587
  // src/domains/order/order.ts
514
588
  var import_crypto = __toESM(require("crypto"));
515
- var import_ws5 = __toESM(require("ws"));
589
+ var import_ws6 = __toESM(require("ws"));
516
590
 
517
591
  // src/domains/symbol/symbol.ts
518
- var import_ws4 = __toESM(require("ws"));
592
+ var import_ws5 = __toESM(require("ws"));
519
593
  async function getSymbolSuggestions(ctx, text) {
520
594
  ctx.ensureSession();
521
595
  try {
@@ -567,7 +641,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
567
641
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
568
642
  const cookieStr = Cookies.serialize(ctx.cookies);
569
643
  return new Promise((resolve, reject) => {
570
- const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
644
+ const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
571
645
  const timer = setTimeout(() => {
572
646
  ws.close();
573
647
  reject(new DxtradeError("LIMITS_TIMEOUT" /* LIMITS_TIMEOUT */, "Symbol limits request timed out"));
@@ -587,7 +661,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
587
661
  clearTimeout(timer);
588
662
  ws.close();
589
663
  resolve(limits);
590
- }, 0);
664
+ }, 200);
591
665
  }
592
666
  });
593
667
  ws.on("error", (error) => {
@@ -600,7 +674,7 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
600
674
 
601
675
  // src/domains/order/order.ts
602
676
  function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
603
- const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
677
+ const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
604
678
  let settled = false;
605
679
  const ready = new Promise((resolve) => {
606
680
  ws.on("open", resolve);
@@ -667,10 +741,13 @@ function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
667
741
  }
668
742
  async function getOrders(ctx, timeout = 3e4) {
669
743
  ctx.ensureSession();
744
+ if (ctx.wsManager) {
745
+ return ctx.wsManager.waitFor("ORDERS" /* ORDERS */, timeout);
746
+ }
670
747
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
671
748
  const cookieStr = Cookies.serialize(ctx.cookies);
672
749
  return new Promise((resolve, reject) => {
673
- const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
750
+ const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
674
751
  const timer = setTimeout(() => {
675
752
  ws.close();
676
753
  reject(new DxtradeError("ORDERS_TIMEOUT" /* ORDERS_TIMEOUT */, "Orders request timed out"));
@@ -814,13 +891,33 @@ async function submitOrder(ctx, params) {
814
891
  }
815
892
 
816
893
  // src/domains/position/position.ts
817
- 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
+ }
818
912
  async function getPositions(ctx) {
819
913
  ctx.ensureSession();
914
+ if (ctx.wsManager) {
915
+ return ctx.wsManager.waitFor("POSITIONS" /* POSITIONS */);
916
+ }
820
917
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
821
918
  const cookieStr = Cookies.serialize(ctx.cookies);
822
919
  return new Promise((resolve, reject) => {
823
- const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
920
+ const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
824
921
  const timer = setTimeout(() => {
825
922
  ws.close();
826
923
  reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT" /* ACCOUNT_POSITIONS_TIMEOUT */, "Account positions timed out"));
@@ -844,10 +941,13 @@ async function getPositions(ctx) {
844
941
  }
845
942
  async function getPositionMetrics(ctx, timeout = 3e4) {
846
943
  ctx.ensureSession();
944
+ if (ctx.wsManager) {
945
+ return ctx.wsManager.waitFor("POSITION_METRICS" /* POSITION_METRICS */, timeout);
946
+ }
847
947
  const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
848
948
  const cookieStr = Cookies.serialize(ctx.cookies);
849
949
  return new Promise((resolve, reject) => {
850
- const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
950
+ const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
851
951
  const timer = setTimeout(() => {
852
952
  ws.close();
853
953
  reject(new DxtradeError("POSITION_METRICS_TIMEOUT" /* POSITION_METRICS_TIMEOUT */, "Position metrics timed out"));
@@ -909,10 +1009,10 @@ async function closePosition(ctx, data) {
909
1009
  }
910
1010
 
911
1011
  // src/domains/session/session.ts
912
- var import_ws7 = __toESM(require("ws"));
1012
+ var import_ws8 = __toESM(require("ws"));
913
1013
  function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
914
1014
  return new Promise((resolve, reject) => {
915
- const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
1015
+ const ws = new import_ws8.default(wsUrl, { headers: { Cookie: cookieStr } });
916
1016
  let atmosphereId = null;
917
1017
  const timer = setTimeout(() => {
918
1018
  ws.close();
@@ -1012,7 +1112,7 @@ async function switchAccount(ctx, accountId) {
1012
1112
  ctx.throwError("ACCOUNT_SWITCH_ERROR" /* ACCOUNT_SWITCH_ERROR */, `Error switching account: ${message}`);
1013
1113
  }
1014
1114
  }
1015
- async function connect(ctx) {
1115
+ async function auth(ctx) {
1016
1116
  await login(ctx);
1017
1117
  await fetchCsrf(ctx);
1018
1118
  if (ctx.debug) clearDebugLog();
@@ -1032,112 +1132,85 @@ async function connect(ctx) {
1032
1132
  ctx.accountId = reconnect.accountId;
1033
1133
  }
1034
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
+ }
1035
1149
 
1036
1150
  // src/client.ts
1037
- var DxtradeClient = class {
1038
- _ctx;
1039
- constructor(config) {
1040
- const callbacks = config.callbacks ?? {};
1041
- this._ctx = {
1042
- config,
1043
- callbacks,
1044
- cookies: {},
1045
- csrf: null,
1046
- accountId: config.accountId ?? null,
1047
- atmosphereId: null,
1048
- broker: config.broker,
1049
- retries: config.retries ?? 3,
1050
- debug: config.debug ?? false,
1051
- ensureSession() {
1052
- if (!this.csrf) {
1053
- throw new DxtradeError(
1054
- "NO_SESSION" /* NO_SESSION */,
1055
- "No active session. Call login() and fetchCsrf() or connect() first."
1056
- );
1057
- }
1058
- },
1059
- throwError(code, message) {
1060
- const error = new DxtradeError(code, message);
1061
- callbacks.onError?.(error);
1062
- throw error;
1063
- }
1064
- };
1151
+ var PositionsDomain = class {
1152
+ constructor(_ctx) {
1153
+ this._ctx = _ctx;
1065
1154
  }
1066
- /** Authenticate with the broker using username and password. */
1067
- async login() {
1068
- return login(this._ctx);
1155
+ /** Get all open positions via WebSocket. */
1156
+ get() {
1157
+ return getPositions(this._ctx);
1069
1158
  }
1070
- /** Fetch the CSRF token required for authenticated requests. */
1071
- async fetchCsrf() {
1072
- 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);
1073
1162
  }
1074
- /** Switch to a specific trading account by ID. */
1075
- async switchAccount(accountId) {
1076
- return switchAccount(this._ctx, accountId);
1163
+ /** Close all open positions with market orders. */
1164
+ closeAll() {
1165
+ return closeAllPositions(this._ctx);
1077
1166
  }
1078
- /** Connect to the broker: login, fetch CSRF, WebSocket handshake, and optional account switch. */
1079
- async connect() {
1080
- return connect(this._ctx);
1167
+ /** Get position-level P&L metrics via WebSocket. */
1168
+ metrics() {
1169
+ return getPositionMetrics(this._ctx);
1081
1170
  }
1082
- /** Search for symbols matching the given text (e.g. "EURUSD", "BTC"). */
1083
- async getSymbolSuggestions(text) {
1084
- 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);
1085
1174
  }
1086
- /** Get detailed instrument info for a symbol, including volume limits and lot size. */
1087
- async getSymbolInfo(symbol) {
1088
- return getSymbolInfo(this._ctx, symbol);
1175
+ };
1176
+ var OrdersDomain = class {
1177
+ constructor(_ctx) {
1178
+ this._ctx = _ctx;
1089
1179
  }
1090
- /** Get order size limits and stop/limit distances for all symbols. */
1091
- async getSymbolLimits() {
1092
- return getSymbolLimits(this._ctx);
1180
+ /** Get all pending/open orders via WebSocket. */
1181
+ get() {
1182
+ return getOrders(this._ctx);
1093
1183
  }
1094
1184
  /**
1095
1185
  * Submit a trading order and wait for WebSocket confirmation.
1096
1186
  * Supports market, limit, and stop orders with optional stop loss and take profit.
1097
1187
  */
1098
- async submitOrder(params) {
1188
+ submit(params) {
1099
1189
  return submitOrder(this._ctx, params);
1100
1190
  }
1101
- /** Get all pending/open orders via WebSocket. */
1102
- async getOrders() {
1103
- return getOrders(this._ctx);
1104
- }
1105
1191
  /** Cancel a single pending order by its order chain ID. */
1106
- async cancelOrder(orderChainId) {
1192
+ cancel(orderChainId) {
1107
1193
  return cancelOrder(this._ctx, orderChainId);
1108
1194
  }
1109
1195
  /** Cancel all pending orders. */
1110
- async cancelAllOrders() {
1196
+ cancelAll() {
1111
1197
  return cancelAllOrders(this._ctx);
1112
1198
  }
1199
+ };
1200
+ var AccountDomain = class {
1201
+ constructor(_ctx) {
1202
+ this._ctx = _ctx;
1203
+ }
1113
1204
  /** Get account metrics including equity, balance, margin, and open P&L. */
1114
- async getAccountMetrics() {
1205
+ metrics() {
1115
1206
  return getAccountMetrics(this._ctx);
1116
1207
  }
1117
- /** Get all open positions via WebSocket. */
1118
- async getPositions() {
1119
- return getPositions(this._ctx);
1120
- }
1121
- /**
1122
- * Close a position. Supports partial closes by specifying a quantity smaller than the full position size.
1123
- */
1124
- async closePosition(position) {
1125
- return closePosition(this._ctx, position);
1126
- }
1127
- /** Close all open positions with market orders. */
1128
- async closeAllPositions() {
1129
- return closeAllPositions(this._ctx);
1130
- }
1131
- /** Get position-level P&L metrics via WebSocket. */
1132
- async getPositionMetrics() {
1133
- return getPositionMetrics(this._ctx);
1134
- }
1135
1208
  /**
1136
1209
  * Fetch trade journal entries for a date range.
1137
1210
  * @param params.from - Start timestamp (Unix ms)
1138
1211
  * @param params.to - End timestamp (Unix ms)
1139
1212
  */
1140
- async getTradeJournal(params) {
1213
+ tradeJournal(params) {
1141
1214
  return getTradeJournal(this._ctx, params);
1142
1215
  }
1143
1216
  /**
@@ -1145,16 +1218,39 @@ var DxtradeClient = class {
1145
1218
  * @param params.from - Start timestamp (Unix ms)
1146
1219
  * @param params.to - End timestamp (Unix ms)
1147
1220
  */
1148
- async getTradeHistory(params) {
1221
+ tradeHistory(params) {
1149
1222
  return getTradeHistory(this._ctx, params);
1150
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
+ }
1151
1246
  /** Get all available instruments, optionally filtered by partial match (e.g. `{ type: "FOREX" }`). */
1152
- async getInstruments(params = {}) {
1247
+ get(params = {}) {
1153
1248
  return getInstruments(this._ctx, params);
1154
1249
  }
1155
- /** Fetch PnL assessments for an instrument within a date range. */
1156
- async getAssessments(params) {
1157
- return getAssessments(this._ctx, params);
1250
+ };
1251
+ var OhlcDomain = class {
1252
+ constructor(_ctx) {
1253
+ this._ctx = _ctx;
1158
1254
  }
1159
1255
  /**
1160
1256
  * Fetch OHLC price bars for a symbol.
@@ -1164,10 +1260,92 @@ var DxtradeClient = class {
1164
1260
  * @param params.maxBars - Maximum bars to return (default: 3500)
1165
1261
  * @param params.priceField - "bid" or "ask" (default: "bid")
1166
1262
  */
1167
- async getOHLC(params) {
1263
+ get(params) {
1168
1264
  return getOHLC(this._ctx, params);
1169
1265
  }
1170
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
+ };
1171
1349
  // Annotate the CommonJS export names for ESM import in node:
1172
1350
  0 && (module.exports = {
1173
1351
  ACTION,