@danielgroen/dxtrade-api 1.0.20 → 1.0.22
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 +18 -5
- package/dist/index.d.mts +143 -3
- package/dist/index.d.ts +143 -3
- package/dist/index.js +388 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +387 -44
- package/dist/index.mjs.map +1 -1
- package/llms.txt +10 -1
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
BROKER: () => BROKER,
|
|
35
35
|
DxtradeClient: () => DxtradeClient,
|
|
36
36
|
DxtradeError: () => DxtradeError,
|
|
37
|
+
ERROR: () => ERROR,
|
|
37
38
|
ORDER_TYPE: () => ORDER_TYPE,
|
|
38
39
|
SIDE: () => SIDE,
|
|
39
40
|
TIF: () => TIF,
|
|
@@ -50,7 +51,10 @@ var BROKER = {
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
// src/constants/endpoints.ts
|
|
53
|
-
|
|
54
|
+
function websocketQuery(atmosphereId) {
|
|
55
|
+
const trackingId = atmosphereId ?? "0";
|
|
56
|
+
return `?X-Atmosphere-tracking-id=${trackingId}&X-Atmosphere-Framework=2.3.2-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=text/x-gwt-rpc;%20charset=UTF-8&X-atmo-protocol=true&sessionState=dx-new&guest-mode=false`;
|
|
57
|
+
}
|
|
54
58
|
var endpoints = {
|
|
55
59
|
login: (base) => `${base}/api/auth/login`,
|
|
56
60
|
switchAccount: (base, id) => `${base}/api/accounts/switch?accountId=${id}`,
|
|
@@ -58,9 +62,13 @@ var endpoints = {
|
|
|
58
62
|
instrumentInfo: (base, symbol, tzOffset) => `${base}/api/instruments/info?symbol=${symbol}&timezoneOffset=${tzOffset}&withExDividends=true`,
|
|
59
63
|
submitOrder: (base) => `${base}/api/orders/single`,
|
|
60
64
|
closePosition: (base) => `${base}/api/positions/close`,
|
|
65
|
+
cancelOrder: (base, accountId, orderChainId) => `${base}/api/orders/cancel?accountId=${accountId}&orderChainId=${orderChainId}`,
|
|
61
66
|
assessments: (base) => `${base}/api/assessments`,
|
|
62
|
-
websocket: (base) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery,
|
|
63
|
-
tradeJournal: (base, params) => `${base}/api/tradejournal?from=${params.from}&to=${params.to}
|
|
67
|
+
websocket: (base, atmosphereId) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery(atmosphereId),
|
|
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=`,
|
|
70
|
+
subscribeInstruments: (base) => `${base}/api/instruments/subscribeInstrumentSymbols`,
|
|
71
|
+
charts: (base) => `${base}/api/charts`
|
|
64
72
|
};
|
|
65
73
|
|
|
66
74
|
// src/constants/enums.ts
|
|
@@ -86,21 +94,63 @@ var TIF = /* @__PURE__ */ ((TIF2) => {
|
|
|
86
94
|
TIF2["GTD"] = "GTD";
|
|
87
95
|
return TIF2;
|
|
88
96
|
})(TIF || {});
|
|
97
|
+
var ERROR = /* @__PURE__ */ ((ERROR2) => {
|
|
98
|
+
ERROR2["NO_SESSION"] = "NO_SESSION";
|
|
99
|
+
ERROR2["LOGIN_FAILED"] = "LOGIN_FAILED";
|
|
100
|
+
ERROR2["LOGIN_ERROR"] = "LOGIN_ERROR";
|
|
101
|
+
ERROR2["CSRF_NOT_FOUND"] = "CSRF_NOT_FOUND";
|
|
102
|
+
ERROR2["CSRF_ERROR"] = "CSRF_ERROR";
|
|
103
|
+
ERROR2["ACCOUNT_SWITCH_ERROR"] = "ACCOUNT_SWITCH_ERROR";
|
|
104
|
+
ERROR2["NO_SUGGESTIONS"] = "NO_SUGGESTIONS";
|
|
105
|
+
ERROR2["SUGGEST_ERROR"] = "SUGGEST_ERROR";
|
|
106
|
+
ERROR2["NO_SYMBOL_INFO"] = "NO_SYMBOL_INFO";
|
|
107
|
+
ERROR2["SYMBOL_INFO_ERROR"] = "SYMBOL_INFO_ERROR";
|
|
108
|
+
ERROR2["INSTRUMENTS_TIMEOUT"] = "INSTRUMENTS_TIMEOUT";
|
|
109
|
+
ERROR2["INSTRUMENTS_ERROR"] = "INSTRUMENTS_ERROR";
|
|
110
|
+
ERROR2["LIMITS_TIMEOUT"] = "LIMITS_TIMEOUT";
|
|
111
|
+
ERROR2["LIMITS_ERROR"] = "LIMITS_ERROR";
|
|
112
|
+
ERROR2["OHLC_TIMEOUT"] = "OHLC_TIMEOUT";
|
|
113
|
+
ERROR2["OHLC_ERROR"] = "OHLC_ERROR";
|
|
114
|
+
ERROR2["ORDER_ERROR"] = "ORDER_ERROR";
|
|
115
|
+
ERROR2["ORDERS_TIMEOUT"] = "ORDERS_TIMEOUT";
|
|
116
|
+
ERROR2["ORDERS_ERROR"] = "ORDERS_ERROR";
|
|
117
|
+
ERROR2["CANCEL_ORDER_ERROR"] = "CANCEL_ORDER_ERROR";
|
|
118
|
+
ERROR2["POSITION_CLOSE_ERROR"] = "POSITION_CLOSE_ERROR";
|
|
119
|
+
ERROR2["POSITION_METRICS_TIMEOUT"] = "POSITION_METRICS_TIMEOUT";
|
|
120
|
+
ERROR2["POSITION_METRICS_ERROR"] = "POSITION_METRICS_ERROR";
|
|
121
|
+
ERROR2["ACCOUNT_METRICS_TIMEOUT"] = "ACCOUNT_METRICS_TIMEOUT";
|
|
122
|
+
ERROR2["ACCOUNT_METRICS_ERROR"] = "ACCOUNT_METRICS_ERROR";
|
|
123
|
+
ERROR2["ACCOUNT_POSITIONS_TIMEOUT"] = "ACCOUNT_POSITIONS_TIMEOUT";
|
|
124
|
+
ERROR2["ACCOUNT_POSITIONS_ERROR"] = "ACCOUNT_POSITIONS_ERROR";
|
|
125
|
+
ERROR2["TRADE_JOURNAL_ERROR"] = "TRADE_JOURNAL_ERROR";
|
|
126
|
+
ERROR2["TRADE_HISTORY_ERROR"] = "TRADE_HISTORY_ERROR";
|
|
127
|
+
ERROR2["ASSESSMENTS_ERROR"] = "ASSESSMENTS_ERROR";
|
|
128
|
+
return ERROR2;
|
|
129
|
+
})(ERROR || {});
|
|
89
130
|
var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
|
|
90
131
|
WS_MESSAGE2["ACCOUNT_METRICS"] = "ACCOUNT_METRICS";
|
|
91
132
|
WS_MESSAGE2["ACCOUNTS"] = "ACCOUNTS";
|
|
92
133
|
WS_MESSAGE2["AVAILABLE_WATCHLISTS"] = "AVAILABLE_WATCHLISTS";
|
|
134
|
+
WS_MESSAGE2["CHART_FEED_SUBTOPIC"] = "chartFeedSubtopic";
|
|
93
135
|
WS_MESSAGE2["INSTRUMENTS"] = "INSTRUMENTS";
|
|
94
136
|
WS_MESSAGE2["LIMITS"] = "LIMITS";
|
|
95
137
|
WS_MESSAGE2["MESSAGE"] = "MESSAGE";
|
|
96
138
|
WS_MESSAGE2["ORDERS"] = "ORDERS";
|
|
97
139
|
WS_MESSAGE2["POSITIONS"] = "POSITIONS";
|
|
140
|
+
WS_MESSAGE2["POSITION_METRICS"] = "POSITION_METRICS";
|
|
98
141
|
WS_MESSAGE2["POSITION_CASH_TRANSFERS"] = "POSITION_CASH_TRANSFERS";
|
|
99
142
|
WS_MESSAGE2["PRIVATE_LAYOUT_NAMES"] = "PRIVATE_LAYOUT_NAMES";
|
|
100
143
|
WS_MESSAGE2["SHARED_PROPERTIES_MESSAGE"] = "SHARED_PROPERTIES_MESSAGE";
|
|
144
|
+
WS_MESSAGE2["TRADE_STATUSES"] = "TRADE_STATUSES";
|
|
101
145
|
WS_MESSAGE2["USER_LOGIN_INFO"] = "USER_LOGIN_INFO";
|
|
102
146
|
return WS_MESSAGE2;
|
|
103
147
|
})(WS_MESSAGE || {});
|
|
148
|
+
((WS_MESSAGE2) => {
|
|
149
|
+
let SUBTOPIC;
|
|
150
|
+
((SUBTOPIC2) => {
|
|
151
|
+
SUBTOPIC2["BIG_CHART_COMPONENT"] = "BigChartComponentPresenter-4";
|
|
152
|
+
})(SUBTOPIC = WS_MESSAGE2.SUBTOPIC || (WS_MESSAGE2.SUBTOPIC = {}));
|
|
153
|
+
})(WS_MESSAGE || (WS_MESSAGE = {}));
|
|
104
154
|
|
|
105
155
|
// src/constants/errors.ts
|
|
106
156
|
var DxtradeError = class extends Error {
|
|
@@ -189,6 +239,14 @@ function debugLog(msg) {
|
|
|
189
239
|
function clearDebugLog() {
|
|
190
240
|
(0, import_fs.writeFileSync)(DEBUG_LOG, "");
|
|
191
241
|
}
|
|
242
|
+
function parseAtmosphereId(data) {
|
|
243
|
+
const raw = data.toString();
|
|
244
|
+
const parts = raw.split("|");
|
|
245
|
+
if (parts.length >= 2 && /^[0-9a-f-]{36}$/.test(parts[1])) {
|
|
246
|
+
return parts[1];
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
192
250
|
function parseWsData(data) {
|
|
193
251
|
const raw = data.toString();
|
|
194
252
|
const pipeIndex = raw.indexOf("|");
|
|
@@ -203,13 +261,13 @@ function parseWsData(data) {
|
|
|
203
261
|
// src/domains/account/account.ts
|
|
204
262
|
async function getAccountMetrics(ctx, timeout = 3e4) {
|
|
205
263
|
ctx.ensureSession();
|
|
206
|
-
const wsUrl = endpoints.websocket(ctx.broker);
|
|
264
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
207
265
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
208
266
|
return new Promise((resolve, reject) => {
|
|
209
267
|
const ws = new import_ws.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
210
268
|
const timer = setTimeout(() => {
|
|
211
269
|
ws.close();
|
|
212
|
-
reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT"
|
|
270
|
+
reject(new DxtradeError("ACCOUNT_METRICS_TIMEOUT" /* ACCOUNT_METRICS_TIMEOUT */, "Account metrics timed out"));
|
|
213
271
|
}, timeout);
|
|
214
272
|
ws.on("message", (data) => {
|
|
215
273
|
const msg = parseWsData(data);
|
|
@@ -225,10 +283,36 @@ async function getAccountMetrics(ctx, timeout = 3e4) {
|
|
|
225
283
|
ws.on("error", (error) => {
|
|
226
284
|
clearTimeout(timer);
|
|
227
285
|
ws.close();
|
|
228
|
-
reject(new DxtradeError("ACCOUNT_METRICS_ERROR"
|
|
286
|
+
reject(new DxtradeError("ACCOUNT_METRICS_ERROR" /* ACCOUNT_METRICS_ERROR */, `Account metrics error: ${error.message}`));
|
|
229
287
|
});
|
|
230
288
|
});
|
|
231
289
|
}
|
|
290
|
+
async function getTradeHistory(ctx, params) {
|
|
291
|
+
ctx.ensureSession();
|
|
292
|
+
try {
|
|
293
|
+
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
294
|
+
const response = await retryRequest(
|
|
295
|
+
{
|
|
296
|
+
method: "GET",
|
|
297
|
+
url: endpoints.tradeHistory(ctx.broker, params),
|
|
298
|
+
headers: { ...baseHeaders(), Cookie: cookieStr }
|
|
299
|
+
},
|
|
300
|
+
ctx.retries
|
|
301
|
+
);
|
|
302
|
+
if (response.status === 200) {
|
|
303
|
+
const setCookies = response.headers["set-cookie"] ?? [];
|
|
304
|
+
const incoming = Cookies.parse(setCookies);
|
|
305
|
+
ctx.cookies = Cookies.merge(ctx.cookies, incoming);
|
|
306
|
+
return response.data;
|
|
307
|
+
} else {
|
|
308
|
+
ctx.throwError("TRADE_HISTORY_ERROR" /* TRADE_HISTORY_ERROR */, `Trade history failed: ${response.status}`);
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
if (error instanceof DxtradeError) throw error;
|
|
312
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
313
|
+
ctx.throwError("TRADE_HISTORY_ERROR" /* TRADE_HISTORY_ERROR */, `Trade history error: ${message}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
232
316
|
async function getTradeJournal(ctx, params) {
|
|
233
317
|
ctx.ensureSession();
|
|
234
318
|
try {
|
|
@@ -247,12 +331,12 @@ async function getTradeJournal(ctx, params) {
|
|
|
247
331
|
ctx.cookies = Cookies.merge(ctx.cookies, incoming);
|
|
248
332
|
return response.data;
|
|
249
333
|
} else {
|
|
250
|
-
ctx.throwError("TRADE_JOURNAL_ERROR"
|
|
334
|
+
ctx.throwError("TRADE_JOURNAL_ERROR" /* TRADE_JOURNAL_ERROR */, `Login failed: ${response.status}`);
|
|
251
335
|
}
|
|
252
336
|
} catch (error) {
|
|
253
337
|
if (error instanceof DxtradeError) throw error;
|
|
254
338
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
255
|
-
ctx.throwError("TRADE_JOURNAL_ERROR"
|
|
339
|
+
ctx.throwError("TRADE_JOURNAL_ERROR" /* TRADE_JOURNAL_ERROR */, `Trade journal error: ${message}`);
|
|
256
340
|
}
|
|
257
341
|
}
|
|
258
342
|
|
|
@@ -278,7 +362,7 @@ async function getAssessments(ctx, params) {
|
|
|
278
362
|
} catch (error) {
|
|
279
363
|
if (error instanceof DxtradeError) throw error;
|
|
280
364
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
281
|
-
ctx.throwError("ASSESSMENTS_ERROR"
|
|
365
|
+
ctx.throwError("ASSESSMENTS_ERROR" /* ASSESSMENTS_ERROR */, `Error fetching assessments: ${message}`);
|
|
282
366
|
}
|
|
283
367
|
}
|
|
284
368
|
|
|
@@ -286,13 +370,13 @@ async function getAssessments(ctx, params) {
|
|
|
286
370
|
var import_ws2 = __toESM(require("ws"));
|
|
287
371
|
async function getInstruments(ctx, params = {}, timeout = 3e4) {
|
|
288
372
|
ctx.ensureSession();
|
|
289
|
-
const wsUrl = endpoints.websocket(ctx.broker);
|
|
373
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
290
374
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
291
375
|
return new Promise((resolve, reject) => {
|
|
292
376
|
const ws = new import_ws2.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
293
377
|
const timer = setTimeout(() => {
|
|
294
378
|
ws.close();
|
|
295
|
-
reject(new DxtradeError("INSTRUMENTS_TIMEOUT"
|
|
379
|
+
reject(new DxtradeError("INSTRUMENTS_TIMEOUT" /* INSTRUMENTS_TIMEOUT */, "Instruments request timed out"));
|
|
296
380
|
}, timeout);
|
|
297
381
|
let instruments = [];
|
|
298
382
|
let settleTimer = null;
|
|
@@ -322,17 +406,115 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
|
|
|
322
406
|
ws.on("error", (error) => {
|
|
323
407
|
clearTimeout(timer);
|
|
324
408
|
ws.close();
|
|
325
|
-
reject(new DxtradeError("INSTRUMENTS_ERROR"
|
|
409
|
+
reject(new DxtradeError("INSTRUMENTS_ERROR" /* INSTRUMENTS_ERROR */, `Instruments error: ${error.message}`));
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/domains/ohlc/ohlc.ts
|
|
415
|
+
var import_ws3 = __toESM(require("ws"));
|
|
416
|
+
async function getOHLC(ctx, params, timeout = 3e4) {
|
|
417
|
+
ctx.ensureSession();
|
|
418
|
+
const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
|
|
419
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
420
|
+
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
421
|
+
const headers = authHeaders(ctx.csrf, cookieStr);
|
|
422
|
+
return new Promise((resolve, reject) => {
|
|
423
|
+
const ws = new import_ws3.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
424
|
+
const bars = [];
|
|
425
|
+
let putsSent = false;
|
|
426
|
+
let initSettleTimer = null;
|
|
427
|
+
let barSettleTimer = null;
|
|
428
|
+
const timer = setTimeout(() => {
|
|
429
|
+
ws.close();
|
|
430
|
+
reject(new DxtradeError("OHLC_TIMEOUT" /* OHLC_TIMEOUT */, "OHLC data timed out"));
|
|
431
|
+
}, timeout);
|
|
432
|
+
function cleanup() {
|
|
433
|
+
clearTimeout(timer);
|
|
434
|
+
if (initSettleTimer) clearTimeout(initSettleTimer);
|
|
435
|
+
if (barSettleTimer) clearTimeout(barSettleTimer);
|
|
436
|
+
ws.close();
|
|
437
|
+
}
|
|
438
|
+
async function sendPuts() {
|
|
439
|
+
putsSent = true;
|
|
440
|
+
try {
|
|
441
|
+
await retryRequest(
|
|
442
|
+
{
|
|
443
|
+
method: "PUT",
|
|
444
|
+
url: endpoints.subscribeInstruments(ctx.broker),
|
|
445
|
+
data: { instruments: [symbol] },
|
|
446
|
+
headers
|
|
447
|
+
},
|
|
448
|
+
ctx.retries
|
|
449
|
+
);
|
|
450
|
+
await retryRequest(
|
|
451
|
+
{
|
|
452
|
+
method: "PUT",
|
|
453
|
+
url: endpoints.charts(ctx.broker),
|
|
454
|
+
data: {
|
|
455
|
+
chartIds: [],
|
|
456
|
+
requests: [
|
|
457
|
+
{
|
|
458
|
+
aggregationPeriodSeconds: resolution,
|
|
459
|
+
extendedSession: true,
|
|
460
|
+
forexPriceField: priceField,
|
|
461
|
+
id: 0,
|
|
462
|
+
maxBarsCount: maxBars,
|
|
463
|
+
range,
|
|
464
|
+
studySubscription: [],
|
|
465
|
+
subtopic: WS_MESSAGE.SUBTOPIC.BIG_CHART_COMPONENT,
|
|
466
|
+
symbol
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
},
|
|
470
|
+
headers
|
|
471
|
+
},
|
|
472
|
+
ctx.retries
|
|
473
|
+
);
|
|
474
|
+
} catch (error) {
|
|
475
|
+
cleanup();
|
|
476
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
477
|
+
reject(new DxtradeError("OHLC_ERROR" /* OHLC_ERROR */, `Error fetching OHLC data: ${message}`));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
ws.on("message", (data) => {
|
|
481
|
+
const msg = parseWsData(data);
|
|
482
|
+
if (shouldLog(msg, ctx.debug)) debugLog(msg);
|
|
483
|
+
if (typeof msg === "string") return;
|
|
484
|
+
if (!putsSent) {
|
|
485
|
+
if (initSettleTimer) clearTimeout(initSettleTimer);
|
|
486
|
+
initSettleTimer = setTimeout(() => sendPuts(), 1e3);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const body = msg.body;
|
|
490
|
+
if (body?.subtopic !== WS_MESSAGE.SUBTOPIC.BIG_CHART_COMPONENT) return;
|
|
491
|
+
if (Array.isArray(body.data)) {
|
|
492
|
+
bars.push(...body.data);
|
|
493
|
+
}
|
|
494
|
+
if (barSettleTimer) clearTimeout(barSettleTimer);
|
|
495
|
+
if (body.snapshotEnd) {
|
|
496
|
+
cleanup();
|
|
497
|
+
resolve(bars);
|
|
498
|
+
} else {
|
|
499
|
+
barSettleTimer = setTimeout(() => {
|
|
500
|
+
cleanup();
|
|
501
|
+
resolve(bars);
|
|
502
|
+
}, 2e3);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
ws.on("error", (error) => {
|
|
506
|
+
cleanup();
|
|
507
|
+
reject(new DxtradeError("OHLC_ERROR" /* OHLC_ERROR */, `OHLC WebSocket error: ${error.message}`));
|
|
326
508
|
});
|
|
327
509
|
});
|
|
328
510
|
}
|
|
329
511
|
|
|
330
512
|
// src/domains/order/order.ts
|
|
331
513
|
var import_crypto = __toESM(require("crypto"));
|
|
332
|
-
var
|
|
514
|
+
var import_ws5 = __toESM(require("ws"));
|
|
333
515
|
|
|
334
516
|
// src/domains/symbol/symbol.ts
|
|
335
|
-
var
|
|
517
|
+
var import_ws4 = __toESM(require("ws"));
|
|
336
518
|
async function getSymbolSuggestions(ctx, text) {
|
|
337
519
|
ctx.ensureSession();
|
|
338
520
|
try {
|
|
@@ -347,13 +529,13 @@ async function getSymbolSuggestions(ctx, text) {
|
|
|
347
529
|
);
|
|
348
530
|
const suggests = response.data?.suggests;
|
|
349
531
|
if (!suggests?.length) {
|
|
350
|
-
ctx.throwError("NO_SUGGESTIONS"
|
|
532
|
+
ctx.throwError("NO_SUGGESTIONS" /* NO_SUGGESTIONS */, "No symbol suggestions found");
|
|
351
533
|
}
|
|
352
534
|
return suggests;
|
|
353
535
|
} catch (error) {
|
|
354
536
|
if (error instanceof DxtradeError) throw error;
|
|
355
537
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
356
|
-
ctx.throwError("SUGGEST_ERROR"
|
|
538
|
+
ctx.throwError("SUGGEST_ERROR" /* SUGGEST_ERROR */, `Error getting symbol suggestions: ${message}`);
|
|
357
539
|
}
|
|
358
540
|
}
|
|
359
541
|
async function getSymbolInfo(ctx, symbol) {
|
|
@@ -370,24 +552,24 @@ async function getSymbolInfo(ctx, symbol) {
|
|
|
370
552
|
ctx.retries
|
|
371
553
|
);
|
|
372
554
|
if (!response.data) {
|
|
373
|
-
ctx.throwError("NO_SYMBOL_INFO"
|
|
555
|
+
ctx.throwError("NO_SYMBOL_INFO" /* NO_SYMBOL_INFO */, "No symbol info returned");
|
|
374
556
|
}
|
|
375
557
|
return response.data;
|
|
376
558
|
} catch (error) {
|
|
377
559
|
if (error instanceof DxtradeError) throw error;
|
|
378
560
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
379
|
-
ctx.throwError("SYMBOL_INFO_ERROR"
|
|
561
|
+
ctx.throwError("SYMBOL_INFO_ERROR" /* SYMBOL_INFO_ERROR */, `Error getting symbol info: ${message}`);
|
|
380
562
|
}
|
|
381
563
|
}
|
|
382
564
|
async function getSymbolLimits(ctx, timeout = 3e4) {
|
|
383
565
|
ctx.ensureSession();
|
|
384
|
-
const wsUrl = endpoints.websocket(ctx.broker);
|
|
566
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
385
567
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
386
568
|
return new Promise((resolve, reject) => {
|
|
387
|
-
const ws = new
|
|
569
|
+
const ws = new import_ws4.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
388
570
|
const timer = setTimeout(() => {
|
|
389
571
|
ws.close();
|
|
390
|
-
reject(new DxtradeError("LIMITS_TIMEOUT"
|
|
572
|
+
reject(new DxtradeError("LIMITS_TIMEOUT" /* LIMITS_TIMEOUT */, "Symbol limits request timed out"));
|
|
391
573
|
}, timeout);
|
|
392
574
|
let limits = [];
|
|
393
575
|
let settleTimer = null;
|
|
@@ -410,14 +592,14 @@ async function getSymbolLimits(ctx, timeout = 3e4) {
|
|
|
410
592
|
ws.on("error", (error) => {
|
|
411
593
|
clearTimeout(timer);
|
|
412
594
|
ws.close();
|
|
413
|
-
reject(new DxtradeError("LIMITS_ERROR"
|
|
595
|
+
reject(new DxtradeError("LIMITS_ERROR" /* LIMITS_ERROR */, `Symbol limits error: ${error.message}`));
|
|
414
596
|
});
|
|
415
597
|
});
|
|
416
598
|
}
|
|
417
599
|
|
|
418
600
|
// src/domains/order/order.ts
|
|
419
601
|
function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
|
|
420
|
-
const ws = new
|
|
602
|
+
const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
421
603
|
let settled = false;
|
|
422
604
|
const ready = new Promise((resolve) => {
|
|
423
605
|
ws.on("open", resolve);
|
|
@@ -482,6 +664,61 @@ function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
|
|
|
482
664
|
});
|
|
483
665
|
return { promise, ready };
|
|
484
666
|
}
|
|
667
|
+
async function getOrders(ctx, timeout = 3e4) {
|
|
668
|
+
ctx.ensureSession();
|
|
669
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
670
|
+
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
671
|
+
return new Promise((resolve, reject) => {
|
|
672
|
+
const ws = new import_ws5.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
673
|
+
const timer = setTimeout(() => {
|
|
674
|
+
ws.close();
|
|
675
|
+
reject(new DxtradeError("ORDERS_TIMEOUT" /* ORDERS_TIMEOUT */, "Orders request timed out"));
|
|
676
|
+
}, timeout);
|
|
677
|
+
ws.on("message", (data) => {
|
|
678
|
+
const msg = parseWsData(data);
|
|
679
|
+
if (shouldLog(msg, ctx.debug)) debugLog(msg);
|
|
680
|
+
if (typeof msg === "string") return;
|
|
681
|
+
if (msg.type === "ORDERS" /* ORDERS */) {
|
|
682
|
+
clearTimeout(timer);
|
|
683
|
+
ws.close();
|
|
684
|
+
resolve(msg.body);
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
ws.on("error", (error) => {
|
|
688
|
+
clearTimeout(timer);
|
|
689
|
+
ws.close();
|
|
690
|
+
reject(new DxtradeError("ORDERS_ERROR" /* ORDERS_ERROR */, `Orders error: ${error.message}`));
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
async function cancelOrder(ctx, orderChainId) {
|
|
695
|
+
ctx.ensureSession();
|
|
696
|
+
const accountId = ctx.accountId ?? ctx.config.accountId;
|
|
697
|
+
if (!accountId) {
|
|
698
|
+
ctx.throwError("CANCEL_ORDER_ERROR" /* CANCEL_ORDER_ERROR */, "accountId is required to cancel an order");
|
|
699
|
+
}
|
|
700
|
+
try {
|
|
701
|
+
await retryRequest(
|
|
702
|
+
{
|
|
703
|
+
method: "DELETE",
|
|
704
|
+
url: endpoints.cancelOrder(ctx.broker, accountId, orderChainId),
|
|
705
|
+
headers: authHeaders(ctx.csrf, Cookies.serialize(ctx.cookies))
|
|
706
|
+
},
|
|
707
|
+
ctx.retries
|
|
708
|
+
);
|
|
709
|
+
} catch (error) {
|
|
710
|
+
if (error instanceof DxtradeError) throw error;
|
|
711
|
+
const message = error instanceof Error ? error.response?.data?.message ?? error.message : "Unknown error";
|
|
712
|
+
ctx.throwError("CANCEL_ORDER_ERROR" /* CANCEL_ORDER_ERROR */, `Cancel order error: ${message}`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
async function cancelAllOrders(ctx) {
|
|
716
|
+
const orders = await getOrders(ctx);
|
|
717
|
+
const pending = orders.filter((o) => !o.finalStatus);
|
|
718
|
+
for (const order of pending) {
|
|
719
|
+
await cancelOrder(ctx, order.orderId);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
485
722
|
async function submitOrder(ctx, params) {
|
|
486
723
|
ctx.ensureSession();
|
|
487
724
|
const {
|
|
@@ -551,7 +788,7 @@ async function submitOrder(ctx, params) {
|
|
|
551
788
|
};
|
|
552
789
|
}
|
|
553
790
|
try {
|
|
554
|
-
const wsUrl = endpoints.websocket(ctx.broker);
|
|
791
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
555
792
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
556
793
|
const listener = createOrderListener(wsUrl, cookieStr, 3e4, ctx.debug);
|
|
557
794
|
await listener.ready;
|
|
@@ -571,21 +808,21 @@ async function submitOrder(ctx, params) {
|
|
|
571
808
|
} catch (error) {
|
|
572
809
|
if (error instanceof DxtradeError) throw error;
|
|
573
810
|
const message = error instanceof Error ? error.response?.data?.message ?? error.message : "Unknown error";
|
|
574
|
-
ctx.throwError("ORDER_ERROR"
|
|
811
|
+
ctx.throwError("ORDER_ERROR" /* ORDER_ERROR */, `Error submitting order: ${message}`);
|
|
575
812
|
}
|
|
576
813
|
}
|
|
577
814
|
|
|
578
815
|
// src/domains/position/position.ts
|
|
579
|
-
var
|
|
816
|
+
var import_ws6 = __toESM(require("ws"));
|
|
580
817
|
async function getPositions(ctx) {
|
|
581
818
|
ctx.ensureSession();
|
|
582
|
-
const wsUrl = endpoints.websocket(ctx.broker);
|
|
819
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
583
820
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
584
821
|
return new Promise((resolve, reject) => {
|
|
585
|
-
const ws = new
|
|
822
|
+
const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
586
823
|
const timer = setTimeout(() => {
|
|
587
824
|
ws.close();
|
|
588
|
-
reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT"
|
|
825
|
+
reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT" /* ACCOUNT_POSITIONS_TIMEOUT */, "Account positions timed out"));
|
|
589
826
|
}, 3e4);
|
|
590
827
|
ws.on("message", (data) => {
|
|
591
828
|
const msg = parseWsData(data);
|
|
@@ -600,10 +837,58 @@ async function getPositions(ctx) {
|
|
|
600
837
|
ws.on("error", (error) => {
|
|
601
838
|
clearTimeout(timer);
|
|
602
839
|
ws.close();
|
|
603
|
-
reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR"
|
|
840
|
+
reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR" /* ACCOUNT_POSITIONS_ERROR */, `Account positions error: ${error.message}`));
|
|
604
841
|
});
|
|
605
842
|
});
|
|
606
843
|
}
|
|
844
|
+
async function getPositionMetrics(ctx, timeout = 3e4) {
|
|
845
|
+
ctx.ensureSession();
|
|
846
|
+
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
847
|
+
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
848
|
+
return new Promise((resolve, reject) => {
|
|
849
|
+
const ws = new import_ws6.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
850
|
+
const timer = setTimeout(() => {
|
|
851
|
+
ws.close();
|
|
852
|
+
reject(new DxtradeError("POSITION_METRICS_TIMEOUT" /* POSITION_METRICS_TIMEOUT */, "Position metrics timed out"));
|
|
853
|
+
}, timeout);
|
|
854
|
+
ws.on("message", (data) => {
|
|
855
|
+
const msg = parseWsData(data);
|
|
856
|
+
if (shouldLog(msg, ctx.debug)) debugLog(msg);
|
|
857
|
+
if (typeof msg === "string") return;
|
|
858
|
+
if (msg.type === "POSITION_METRICS" /* POSITION_METRICS */) {
|
|
859
|
+
clearTimeout(timer);
|
|
860
|
+
ws.close();
|
|
861
|
+
resolve(msg.body);
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
ws.on("error", (error) => {
|
|
865
|
+
clearTimeout(timer);
|
|
866
|
+
ws.close();
|
|
867
|
+
reject(new DxtradeError("POSITION_METRICS_ERROR" /* POSITION_METRICS_ERROR */, `Position metrics error: ${error.message}`));
|
|
868
|
+
});
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
async function closeAllPositions(ctx) {
|
|
872
|
+
const positions = await getPositions(ctx);
|
|
873
|
+
for (const pos of positions) {
|
|
874
|
+
const closeData = {
|
|
875
|
+
legs: [
|
|
876
|
+
{
|
|
877
|
+
instrumentId: pos.positionKey.instrumentId,
|
|
878
|
+
positionCode: pos.positionKey.positionCode,
|
|
879
|
+
positionEffect: "CLOSING",
|
|
880
|
+
ratioQuantity: 1,
|
|
881
|
+
symbol: pos.positionKey.positionCode
|
|
882
|
+
}
|
|
883
|
+
],
|
|
884
|
+
limitPrice: 0,
|
|
885
|
+
orderType: "MARKET",
|
|
886
|
+
quantity: -pos.quantity,
|
|
887
|
+
timeInForce: "GTC"
|
|
888
|
+
};
|
|
889
|
+
await closePosition(ctx, closeData);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
607
892
|
async function closePosition(ctx, data) {
|
|
608
893
|
try {
|
|
609
894
|
await retryRequest(
|
|
@@ -618,27 +903,31 @@ async function closePosition(ctx, data) {
|
|
|
618
903
|
} catch (error) {
|
|
619
904
|
if (error instanceof DxtradeError) throw error;
|
|
620
905
|
const message = error instanceof Error ? error.response?.data?.message ?? error.message : "Unknown error";
|
|
621
|
-
ctx.throwError("POSITION_CLOSE_ERROR"
|
|
906
|
+
ctx.throwError("POSITION_CLOSE_ERROR" /* POSITION_CLOSE_ERROR */, `Position close error: ${message}`);
|
|
622
907
|
}
|
|
623
908
|
}
|
|
624
909
|
|
|
625
910
|
// src/domains/session/session.ts
|
|
626
|
-
var
|
|
911
|
+
var import_ws7 = __toESM(require("ws"));
|
|
627
912
|
function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
|
|
628
913
|
return new Promise((resolve, reject) => {
|
|
629
|
-
const ws = new
|
|
914
|
+
const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
915
|
+
let atmosphereId = null;
|
|
630
916
|
const timer = setTimeout(() => {
|
|
631
917
|
ws.close();
|
|
632
918
|
reject(new Error("[dxtrade-api] Handshake timed out"));
|
|
633
919
|
}, timeout);
|
|
634
920
|
ws.on("message", (data) => {
|
|
921
|
+
if (!atmosphereId) {
|
|
922
|
+
atmosphereId = parseAtmosphereId(data);
|
|
923
|
+
}
|
|
635
924
|
const msg = parseWsData(data);
|
|
636
925
|
if (shouldLog(msg, debug)) debugLog(msg);
|
|
637
926
|
if (typeof msg === "string") return;
|
|
638
927
|
if (msg.accountId) {
|
|
639
928
|
clearTimeout(timer);
|
|
640
929
|
ws.close();
|
|
641
|
-
resolve();
|
|
930
|
+
resolve({ atmosphereId, accountId: msg.accountId });
|
|
642
931
|
}
|
|
643
932
|
});
|
|
644
933
|
ws.on("error", (error) => {
|
|
@@ -669,12 +958,12 @@ async function login(ctx) {
|
|
|
669
958
|
ctx.cookies = Cookies.merge(ctx.cookies, incoming);
|
|
670
959
|
ctx.callbacks.onLogin?.();
|
|
671
960
|
} else {
|
|
672
|
-
ctx.throwError("LOGIN_FAILED"
|
|
961
|
+
ctx.throwError("LOGIN_FAILED" /* LOGIN_FAILED */, `Login failed: ${response.status}`);
|
|
673
962
|
}
|
|
674
963
|
} catch (error) {
|
|
675
964
|
if (error instanceof DxtradeError) throw error;
|
|
676
965
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
677
|
-
ctx.throwError("LOGIN_ERROR"
|
|
966
|
+
ctx.throwError("LOGIN_ERROR" /* LOGIN_ERROR */, `Login error: ${message}`);
|
|
678
967
|
}
|
|
679
968
|
}
|
|
680
969
|
async function fetchCsrf(ctx) {
|
|
@@ -692,12 +981,12 @@ async function fetchCsrf(ctx) {
|
|
|
692
981
|
if (csrfMatch) {
|
|
693
982
|
ctx.csrf = csrfMatch[1];
|
|
694
983
|
} else {
|
|
695
|
-
ctx.throwError("CSRF_NOT_FOUND"
|
|
984
|
+
ctx.throwError("CSRF_NOT_FOUND" /* CSRF_NOT_FOUND */, "CSRF token not found");
|
|
696
985
|
}
|
|
697
986
|
} catch (error) {
|
|
698
987
|
if (error instanceof DxtradeError) throw error;
|
|
699
988
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
700
|
-
ctx.throwError("CSRF_ERROR"
|
|
989
|
+
ctx.throwError("CSRF_ERROR" /* CSRF_ERROR */, `CSRF fetch error: ${message}`);
|
|
701
990
|
}
|
|
702
991
|
}
|
|
703
992
|
async function switchAccount(ctx, accountId) {
|
|
@@ -715,19 +1004,27 @@ async function switchAccount(ctx, accountId) {
|
|
|
715
1004
|
} catch (error) {
|
|
716
1005
|
if (error instanceof DxtradeError) throw error;
|
|
717
1006
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
718
|
-
ctx.throwError("ACCOUNT_SWITCH_ERROR"
|
|
1007
|
+
ctx.throwError("ACCOUNT_SWITCH_ERROR" /* ACCOUNT_SWITCH_ERROR */, `Error switching account: ${message}`);
|
|
719
1008
|
}
|
|
720
1009
|
}
|
|
721
1010
|
async function connect(ctx) {
|
|
722
1011
|
await login(ctx);
|
|
723
1012
|
await fetchCsrf(ctx);
|
|
724
1013
|
if (ctx.debug) clearDebugLog();
|
|
725
|
-
const wsUrl = endpoints.websocket(ctx.broker);
|
|
726
1014
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
727
|
-
await waitForHandshake(
|
|
1015
|
+
const handshake = await waitForHandshake(endpoints.websocket(ctx.broker), cookieStr, 3e4, ctx.debug);
|
|
1016
|
+
ctx.atmosphereId = handshake.atmosphereId;
|
|
1017
|
+
ctx.accountId = handshake.accountId;
|
|
728
1018
|
if (ctx.config.accountId) {
|
|
729
1019
|
await switchAccount(ctx, ctx.config.accountId);
|
|
730
|
-
await waitForHandshake(
|
|
1020
|
+
const reconnect = await waitForHandshake(
|
|
1021
|
+
endpoints.websocket(ctx.broker, ctx.atmosphereId),
|
|
1022
|
+
Cookies.serialize(ctx.cookies),
|
|
1023
|
+
3e4,
|
|
1024
|
+
ctx.debug
|
|
1025
|
+
);
|
|
1026
|
+
ctx.atmosphereId = reconnect.atmosphereId;
|
|
1027
|
+
ctx.accountId = reconnect.accountId;
|
|
731
1028
|
}
|
|
732
1029
|
}
|
|
733
1030
|
|
|
@@ -741,12 +1038,17 @@ var DxtradeClient = class {
|
|
|
741
1038
|
callbacks,
|
|
742
1039
|
cookies: {},
|
|
743
1040
|
csrf: null,
|
|
1041
|
+
accountId: config.accountId ?? null,
|
|
1042
|
+
atmosphereId: null,
|
|
744
1043
|
broker: config.broker,
|
|
745
1044
|
retries: config.retries ?? 3,
|
|
746
1045
|
debug: config.debug ?? false,
|
|
747
1046
|
ensureSession() {
|
|
748
1047
|
if (!this.csrf) {
|
|
749
|
-
throw new DxtradeError(
|
|
1048
|
+
throw new DxtradeError(
|
|
1049
|
+
"NO_SESSION" /* NO_SESSION */,
|
|
1050
|
+
"No active session. Call login() and fetchCsrf() or connect() first."
|
|
1051
|
+
);
|
|
750
1052
|
}
|
|
751
1053
|
},
|
|
752
1054
|
throwError(code, message) {
|
|
@@ -791,6 +1093,18 @@ var DxtradeClient = class {
|
|
|
791
1093
|
async submitOrder(params) {
|
|
792
1094
|
return submitOrder(this._ctx, params);
|
|
793
1095
|
}
|
|
1096
|
+
/** Get all pending/open orders via WebSocket. */
|
|
1097
|
+
async getOrders() {
|
|
1098
|
+
return getOrders(this._ctx);
|
|
1099
|
+
}
|
|
1100
|
+
/** Cancel a single pending order by its order chain ID. */
|
|
1101
|
+
async cancelOrder(orderChainId) {
|
|
1102
|
+
return cancelOrder(this._ctx, orderChainId);
|
|
1103
|
+
}
|
|
1104
|
+
/** Cancel all pending orders. */
|
|
1105
|
+
async cancelAllOrders() {
|
|
1106
|
+
return cancelAllOrders(this._ctx);
|
|
1107
|
+
}
|
|
794
1108
|
/** Get account metrics including equity, balance, margin, and open P&L. */
|
|
795
1109
|
async getAccountMetrics() {
|
|
796
1110
|
return getAccountMetrics(this._ctx);
|
|
@@ -799,10 +1113,20 @@ var DxtradeClient = class {
|
|
|
799
1113
|
async getPositions() {
|
|
800
1114
|
return getPositions(this._ctx);
|
|
801
1115
|
}
|
|
802
|
-
/**
|
|
1116
|
+
/**
|
|
1117
|
+
* Close a position. Supports partial closes by specifying a quantity smaller than the full position size.
|
|
1118
|
+
*/
|
|
803
1119
|
async closePosition(position) {
|
|
804
1120
|
return closePosition(this._ctx, position);
|
|
805
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
|
+
}
|
|
806
1130
|
/**
|
|
807
1131
|
* Fetch trade journal entries for a date range.
|
|
808
1132
|
* @param params.from - Start timestamp (Unix ms)
|
|
@@ -811,6 +1135,14 @@ var DxtradeClient = class {
|
|
|
811
1135
|
async getTradeJournal(params) {
|
|
812
1136
|
return getTradeJournal(this._ctx, params);
|
|
813
1137
|
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Fetch trade history for a date range.
|
|
1140
|
+
* @param params.from - Start timestamp (Unix ms)
|
|
1141
|
+
* @param params.to - End timestamp (Unix ms)
|
|
1142
|
+
*/
|
|
1143
|
+
async getTradeHistory(params) {
|
|
1144
|
+
return getTradeHistory(this._ctx, params);
|
|
1145
|
+
}
|
|
814
1146
|
/** Get all available instruments, optionally filtered by partial match (e.g. `{ type: "FOREX" }`). */
|
|
815
1147
|
async getInstruments(params = {}) {
|
|
816
1148
|
return getInstruments(this._ctx, params);
|
|
@@ -819,6 +1151,17 @@ var DxtradeClient = class {
|
|
|
819
1151
|
async getAssessments(params) {
|
|
820
1152
|
return getAssessments(this._ctx, params);
|
|
821
1153
|
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Fetch OHLC price bars for a symbol.
|
|
1156
|
+
* @param params.symbol - Instrument symbol (e.g. "EURUSD")
|
|
1157
|
+
* @param params.resolution - Bar period in seconds (default: 60 = 1 min)
|
|
1158
|
+
* @param params.range - Lookback window in seconds (default: 432000 = 5 days)
|
|
1159
|
+
* @param params.maxBars - Maximum bars to return (default: 3500)
|
|
1160
|
+
* @param params.priceField - "bid" or "ask" (default: "bid")
|
|
1161
|
+
*/
|
|
1162
|
+
async getOHLC(params) {
|
|
1163
|
+
return getOHLC(this._ctx, params);
|
|
1164
|
+
}
|
|
822
1165
|
};
|
|
823
1166
|
// Annotate the CommonJS export names for ESM import in node:
|
|
824
1167
|
0 && (module.exports = {
|
|
@@ -826,6 +1169,7 @@ var DxtradeClient = class {
|
|
|
826
1169
|
BROKER,
|
|
827
1170
|
DxtradeClient,
|
|
828
1171
|
DxtradeError,
|
|
1172
|
+
ERROR,
|
|
829
1173
|
ORDER_TYPE,
|
|
830
1174
|
SIDE,
|
|
831
1175
|
TIF,
|