@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.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}
|
|
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
|
|
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
|
|
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: "
|
|
326
|
+
method: "POST",
|
|
252
327
|
url: endpoints.tradeHistory(ctx.broker, params),
|
|
253
|
-
headers:
|
|
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
|
|
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
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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
|
|
544
|
+
import WebSocket6 from "ws";
|
|
470
545
|
|
|
471
546
|
// src/domains/symbol/symbol.ts
|
|
472
|
-
import
|
|
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
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
988
|
-
_ctx
|
|
989
|
-
|
|
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
|
-
/**
|
|
1017
|
-
|
|
1018
|
-
return
|
|
1110
|
+
/** Get all open positions via WebSocket. */
|
|
1111
|
+
get() {
|
|
1112
|
+
return getPositions(this._ctx);
|
|
1019
1113
|
}
|
|
1020
|
-
/**
|
|
1021
|
-
|
|
1022
|
-
return
|
|
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
|
-
/**
|
|
1025
|
-
|
|
1026
|
-
return
|
|
1118
|
+
/** Close all open positions with market orders. */
|
|
1119
|
+
closeAll() {
|
|
1120
|
+
return closeAllPositions(this._ctx);
|
|
1027
1121
|
}
|
|
1028
|
-
/**
|
|
1029
|
-
|
|
1030
|
-
return
|
|
1122
|
+
/** Get position-level P&L metrics via WebSocket. */
|
|
1123
|
+
metrics() {
|
|
1124
|
+
return getPositionMetrics(this._ctx);
|
|
1031
1125
|
}
|
|
1032
|
-
/**
|
|
1033
|
-
|
|
1034
|
-
return
|
|
1126
|
+
/** Stream real-time position updates. Requires connect(). Returns unsubscribe function. */
|
|
1127
|
+
stream(callback) {
|
|
1128
|
+
return streamPositions(this._ctx, callback);
|
|
1035
1129
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1130
|
+
};
|
|
1131
|
+
var OrdersDomain = class {
|
|
1132
|
+
constructor(_ctx) {
|
|
1133
|
+
this._ctx = _ctx;
|
|
1039
1134
|
}
|
|
1040
|
-
/** Get
|
|
1041
|
-
|
|
1042
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
1147
|
+
cancel(orderChainId) {
|
|
1057
1148
|
return cancelOrder(this._ctx, orderChainId);
|
|
1058
1149
|
}
|
|
1059
1150
|
/** Cancel all pending orders. */
|
|
1060
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1202
|
+
get(params = {}) {
|
|
1103
1203
|
return getInstruments(this._ctx, params);
|
|
1104
1204
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
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
|
-
|
|
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,
|