@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/README.md +65 -41
- package/dist/index.d.mts +130 -55
- package/dist/index.d.ts +130 -55
- package/dist/index.js +290 -107
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +291 -108
- package/dist/index.mjs.map +1 -1
- package/llms.txt +38 -30
- package/package.json +17 -17
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}
|
|
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
|
|
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
|
|
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: "
|
|
371
|
+
method: "POST",
|
|
297
372
|
url: endpoints.tradeHistory(ctx.broker, params),
|
|
298
|
-
headers:
|
|
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
|
|
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
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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
|
|
589
|
+
var import_ws6 = __toESM(require("ws"));
|
|
515
590
|
|
|
516
591
|
// src/domains/symbol/symbol.ts
|
|
517
|
-
var
|
|
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
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1033
|
-
_ctx
|
|
1034
|
-
|
|
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
|
-
/**
|
|
1062
|
-
|
|
1063
|
-
return
|
|
1155
|
+
/** Get all open positions via WebSocket. */
|
|
1156
|
+
get() {
|
|
1157
|
+
return getPositions(this._ctx);
|
|
1064
1158
|
}
|
|
1065
|
-
/**
|
|
1066
|
-
|
|
1067
|
-
return
|
|
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
|
-
/**
|
|
1070
|
-
|
|
1071
|
-
return
|
|
1163
|
+
/** Close all open positions with market orders. */
|
|
1164
|
+
closeAll() {
|
|
1165
|
+
return closeAllPositions(this._ctx);
|
|
1072
1166
|
}
|
|
1073
|
-
/**
|
|
1074
|
-
|
|
1075
|
-
return
|
|
1167
|
+
/** Get position-level P&L metrics via WebSocket. */
|
|
1168
|
+
metrics() {
|
|
1169
|
+
return getPositionMetrics(this._ctx);
|
|
1076
1170
|
}
|
|
1077
|
-
/**
|
|
1078
|
-
|
|
1079
|
-
return
|
|
1171
|
+
/** Stream real-time position updates. Requires connect(). Returns unsubscribe function. */
|
|
1172
|
+
stream(callback) {
|
|
1173
|
+
return streamPositions(this._ctx, callback);
|
|
1080
1174
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1175
|
+
};
|
|
1176
|
+
var OrdersDomain = class {
|
|
1177
|
+
constructor(_ctx) {
|
|
1178
|
+
this._ctx = _ctx;
|
|
1084
1179
|
}
|
|
1085
|
-
/** Get
|
|
1086
|
-
|
|
1087
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
1192
|
+
cancel(orderChainId) {
|
|
1102
1193
|
return cancelOrder(this._ctx, orderChainId);
|
|
1103
1194
|
}
|
|
1104
1195
|
/** Cancel all pending orders. */
|
|
1105
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1247
|
+
get(params = {}) {
|
|
1148
1248
|
return getInstruments(this._ctx, params);
|
|
1149
1249
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
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
|
-
|
|
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,
|