@danielgroen/dxtrade-api 1.0.24 → 1.0.25
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 +12 -10
- package/dist/index.d.mts +29 -13
- package/dist/index.d.ts +29 -13
- package/dist/index.js +141 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +141 -45
- package/dist/index.mjs.map +1 -1
- package/llms.txt +3 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ npm install dxtrade-api
|
|
|
26
26
|
- [x] Position metrics (per-position P&L)
|
|
27
27
|
- [x] Account metrics, trade journal & trade history
|
|
28
28
|
- [x] Symbol search & instrument info
|
|
29
|
-
- [x] OHLC / price bar data
|
|
29
|
+
- [x] OHLC / price bar data (one-shot & streaming)
|
|
30
30
|
- [x] PnL assessments
|
|
31
31
|
- [x] Multi-broker support (FTMO, Eightcap, Lark Funding)
|
|
32
32
|
- [x] Persistent WebSocket with `connect()`
|
|
@@ -34,7 +34,7 @@ npm install dxtrade-api
|
|
|
34
34
|
- [x] Full TypeScript support
|
|
35
35
|
- [ ] Batch orders
|
|
36
36
|
- [ ] Modify existing orders
|
|
37
|
-
- [
|
|
37
|
+
- [x] Real-time OHLC streaming
|
|
38
38
|
|
|
39
39
|
## Quick Start
|
|
40
40
|
|
|
@@ -48,8 +48,8 @@ const client = new DxtradeClient({
|
|
|
48
48
|
accountId: "optional_account_id",
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
//
|
|
52
|
-
await client.connect();
|
|
51
|
+
// await client.auth(); // Auth only
|
|
52
|
+
await client.connect(); // Auth + persistent WebSocket (recommended)
|
|
53
53
|
|
|
54
54
|
const suggestions = await client.symbols.search("EURUSD");
|
|
55
55
|
const symbol = suggestions[0];
|
|
@@ -63,17 +63,17 @@ const order = await client.orders.submit({
|
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
console.log(`Order ${order.orderId}: ${order.status}`);
|
|
66
|
-
client.disconnect();
|
|
66
|
+
client.disconnect(); // disconnect stream -- only needed if client.connect()
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
## Connection Modes
|
|
70
70
|
|
|
71
71
|
```ts
|
|
72
|
-
// Persistent WebSocket (recommended) — reuses one WS for all data, enables streaming
|
|
72
|
+
// 1. Persistent WebSocket (recommended) — reuses one WS for all data, enables streaming
|
|
73
73
|
await client.connect();
|
|
74
74
|
client.disconnect(); // when done
|
|
75
75
|
|
|
76
|
-
// Lightweight — auth only, each data call opens a temporary WebSocket
|
|
76
|
+
// 2. Lightweight — auth only, each data call opens a temporary WebSocket
|
|
77
77
|
await client.auth();
|
|
78
78
|
```
|
|
79
79
|
|
|
@@ -113,11 +113,10 @@ BROKER.FTMO // "https://dxtrade.ftmo.com"
|
|
|
113
113
|
|
|
114
114
|
### Positions
|
|
115
115
|
|
|
116
|
-
- `client.positions.get()` — Get all open positions
|
|
116
|
+
- `client.positions.get()` — Get all open positions with P&L metrics merged (margin, plOpen, marketValue, etc.)
|
|
117
117
|
- `client.positions.close(params)` — Close a position (supports partial closes via the quantity field)
|
|
118
118
|
- `client.positions.closeAll()` — Close all open positions with market orders
|
|
119
|
-
- `client.positions.
|
|
120
|
-
- `client.positions.stream(callback)` — Stream real-time position updates (requires `connect()`). Returns an unsubscribe function.
|
|
119
|
+
- `client.positions.stream(callback)` — Stream real-time position updates with live P&L (requires `connect()`). Returns an unsubscribe function.
|
|
121
120
|
|
|
122
121
|
### Orders
|
|
123
122
|
|
|
@@ -145,6 +144,7 @@ BROKER.FTMO // "https://dxtrade.ftmo.com"
|
|
|
145
144
|
### OHLC
|
|
146
145
|
|
|
147
146
|
- `client.ohlc.get(params)` — Fetch OHLC price bars for a symbol (resolution, range, maxBars, priceField)
|
|
147
|
+
- `client.ohlc.stream(params, callback)` — Stream real-time OHLC bar updates (requires `connect()`). Returns a promise that resolves with an unsubscribe function after the snapshot is received.
|
|
148
148
|
|
|
149
149
|
### Assessments
|
|
150
150
|
|
|
@@ -196,6 +196,8 @@ npm run example:symbols:info:btc
|
|
|
196
196
|
npm run example:instruments:get
|
|
197
197
|
npm run example:instruments:get:forex
|
|
198
198
|
npm run example:ohlc:get
|
|
199
|
+
npm run example:ohlc:stream
|
|
200
|
+
npm run example:ohlc:stream:btc
|
|
199
201
|
npm run example:assessments:get
|
|
200
202
|
npm run example:assessments:get:btc
|
|
201
203
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -100,7 +100,8 @@ declare enum WS_MESSAGE {
|
|
|
100
100
|
}
|
|
101
101
|
declare namespace WS_MESSAGE {
|
|
102
102
|
enum SUBTOPIC {
|
|
103
|
-
BIG_CHART_COMPONENT = "BigChartComponentPresenter-4"
|
|
103
|
+
BIG_CHART_COMPONENT = "BigChartComponentPresenter-4",
|
|
104
|
+
OHLC_STREAM = "OHLCStreamPresenter-0"
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
|
|
@@ -389,13 +390,28 @@ declare namespace Position {
|
|
|
389
390
|
stopLoss: number | null;
|
|
390
391
|
}
|
|
391
392
|
interface Metrics {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
393
|
+
uid: string;
|
|
394
|
+
accountId: string;
|
|
395
|
+
margin: number;
|
|
396
|
+
plOpen: number;
|
|
397
|
+
plClosed: number;
|
|
398
|
+
totalCommissions: number;
|
|
399
|
+
totalFinancing: number;
|
|
400
|
+
plRate: number;
|
|
401
|
+
averagePrice: number;
|
|
402
|
+
marketValue: number;
|
|
397
403
|
[key: string]: unknown;
|
|
398
404
|
}
|
|
405
|
+
interface Full extends Get {
|
|
406
|
+
margin: number;
|
|
407
|
+
plOpen: number;
|
|
408
|
+
plClosed: number;
|
|
409
|
+
totalCommissions: number;
|
|
410
|
+
totalFinancing: number;
|
|
411
|
+
plRate: number;
|
|
412
|
+
averagePrice: number;
|
|
413
|
+
marketValue: number;
|
|
414
|
+
}
|
|
399
415
|
interface Close {
|
|
400
416
|
legs: {
|
|
401
417
|
instrumentId: number;
|
|
@@ -441,16 +457,14 @@ declare namespace Symbol {
|
|
|
441
457
|
declare class PositionsDomain {
|
|
442
458
|
private _ctx;
|
|
443
459
|
constructor(_ctx: ClientContext);
|
|
444
|
-
/** Get all open positions
|
|
445
|
-
get(): Promise<Position.
|
|
460
|
+
/** Get all open positions with P&L metrics merged. */
|
|
461
|
+
get(): Promise<Position.Full[]>;
|
|
446
462
|
/** Close a position. Supports partial closes by specifying a quantity smaller than the full position size. */
|
|
447
463
|
close(params: Position.Close): Promise<void>;
|
|
448
464
|
/** Close all open positions with market orders. */
|
|
449
465
|
closeAll(): Promise<void>;
|
|
450
|
-
/**
|
|
451
|
-
|
|
452
|
-
/** Stream real-time position updates. Requires connect(). Returns unsubscribe function. */
|
|
453
|
-
stream(callback: (positions: Position.Get[]) => void): () => void;
|
|
466
|
+
/** Stream real-time position updates with P&L metrics. Requires connect(). Returns unsubscribe function. */
|
|
467
|
+
stream(callback: (positions: Position.Full[]) => void): () => void;
|
|
454
468
|
}
|
|
455
469
|
declare class OrdersDomain {
|
|
456
470
|
private _ctx;
|
|
@@ -519,6 +533,8 @@ declare class OhlcDomain {
|
|
|
519
533
|
* @param params.priceField - "bid" or "ask" (default: "bid")
|
|
520
534
|
*/
|
|
521
535
|
get(params: OHLC.Params): Promise<OHLC.Bar[]>;
|
|
536
|
+
/** Stream real-time OHLC bar updates. Requires connect(). Returns unsubscribe function. */
|
|
537
|
+
stream(params: OHLC.Params, callback: (bars: OHLC.Bar[]) => void): Promise<() => void>;
|
|
522
538
|
}
|
|
523
539
|
declare class AssessmentsDomain {
|
|
524
540
|
private _ctx;
|
|
@@ -554,7 +570,7 @@ declare class DxtradeClient {
|
|
|
554
570
|
readonly symbols: SymbolsDomain;
|
|
555
571
|
/** Instrument operations: get (with optional filtering). */
|
|
556
572
|
readonly instruments: InstrumentsDomain;
|
|
557
|
-
/** OHLC price bar operations: get. */
|
|
573
|
+
/** OHLC price bar operations: get, stream. */
|
|
558
574
|
readonly ohlc: OhlcDomain;
|
|
559
575
|
/** PnL assessment operations: get. */
|
|
560
576
|
readonly assessments: AssessmentsDomain;
|
package/dist/index.d.ts
CHANGED
|
@@ -100,7 +100,8 @@ declare enum WS_MESSAGE {
|
|
|
100
100
|
}
|
|
101
101
|
declare namespace WS_MESSAGE {
|
|
102
102
|
enum SUBTOPIC {
|
|
103
|
-
BIG_CHART_COMPONENT = "BigChartComponentPresenter-4"
|
|
103
|
+
BIG_CHART_COMPONENT = "BigChartComponentPresenter-4",
|
|
104
|
+
OHLC_STREAM = "OHLCStreamPresenter-0"
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
|
|
@@ -389,13 +390,28 @@ declare namespace Position {
|
|
|
389
390
|
stopLoss: number | null;
|
|
390
391
|
}
|
|
391
392
|
interface Metrics {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
393
|
+
uid: string;
|
|
394
|
+
accountId: string;
|
|
395
|
+
margin: number;
|
|
396
|
+
plOpen: number;
|
|
397
|
+
plClosed: number;
|
|
398
|
+
totalCommissions: number;
|
|
399
|
+
totalFinancing: number;
|
|
400
|
+
plRate: number;
|
|
401
|
+
averagePrice: number;
|
|
402
|
+
marketValue: number;
|
|
397
403
|
[key: string]: unknown;
|
|
398
404
|
}
|
|
405
|
+
interface Full extends Get {
|
|
406
|
+
margin: number;
|
|
407
|
+
plOpen: number;
|
|
408
|
+
plClosed: number;
|
|
409
|
+
totalCommissions: number;
|
|
410
|
+
totalFinancing: number;
|
|
411
|
+
plRate: number;
|
|
412
|
+
averagePrice: number;
|
|
413
|
+
marketValue: number;
|
|
414
|
+
}
|
|
399
415
|
interface Close {
|
|
400
416
|
legs: {
|
|
401
417
|
instrumentId: number;
|
|
@@ -441,16 +457,14 @@ declare namespace Symbol {
|
|
|
441
457
|
declare class PositionsDomain {
|
|
442
458
|
private _ctx;
|
|
443
459
|
constructor(_ctx: ClientContext);
|
|
444
|
-
/** Get all open positions
|
|
445
|
-
get(): Promise<Position.
|
|
460
|
+
/** Get all open positions with P&L metrics merged. */
|
|
461
|
+
get(): Promise<Position.Full[]>;
|
|
446
462
|
/** Close a position. Supports partial closes by specifying a quantity smaller than the full position size. */
|
|
447
463
|
close(params: Position.Close): Promise<void>;
|
|
448
464
|
/** Close all open positions with market orders. */
|
|
449
465
|
closeAll(): Promise<void>;
|
|
450
|
-
/**
|
|
451
|
-
|
|
452
|
-
/** Stream real-time position updates. Requires connect(). Returns unsubscribe function. */
|
|
453
|
-
stream(callback: (positions: Position.Get[]) => void): () => void;
|
|
466
|
+
/** Stream real-time position updates with P&L metrics. Requires connect(). Returns unsubscribe function. */
|
|
467
|
+
stream(callback: (positions: Position.Full[]) => void): () => void;
|
|
454
468
|
}
|
|
455
469
|
declare class OrdersDomain {
|
|
456
470
|
private _ctx;
|
|
@@ -519,6 +533,8 @@ declare class OhlcDomain {
|
|
|
519
533
|
* @param params.priceField - "bid" or "ask" (default: "bid")
|
|
520
534
|
*/
|
|
521
535
|
get(params: OHLC.Params): Promise<OHLC.Bar[]>;
|
|
536
|
+
/** Stream real-time OHLC bar updates. Requires connect(). Returns unsubscribe function. */
|
|
537
|
+
stream(params: OHLC.Params, callback: (bars: OHLC.Bar[]) => void): Promise<() => void>;
|
|
522
538
|
}
|
|
523
539
|
declare class AssessmentsDomain {
|
|
524
540
|
private _ctx;
|
|
@@ -554,7 +570,7 @@ declare class DxtradeClient {
|
|
|
554
570
|
readonly symbols: SymbolsDomain;
|
|
555
571
|
/** Instrument operations: get (with optional filtering). */
|
|
556
572
|
readonly instruments: InstrumentsDomain;
|
|
557
|
-
/** OHLC price bar operations: get. */
|
|
573
|
+
/** OHLC price bar operations: get, stream. */
|
|
558
574
|
readonly ohlc: OhlcDomain;
|
|
559
575
|
/** PnL assessment operations: get. */
|
|
560
576
|
readonly assessments: AssessmentsDomain;
|
package/dist/index.js
CHANGED
|
@@ -152,6 +152,7 @@ var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
|
|
|
152
152
|
let SUBTOPIC;
|
|
153
153
|
((SUBTOPIC2) => {
|
|
154
154
|
SUBTOPIC2["BIG_CHART_COMPONENT"] = "BigChartComponentPresenter-4";
|
|
155
|
+
SUBTOPIC2["OHLC_STREAM"] = "OHLCStreamPresenter-0";
|
|
155
156
|
})(SUBTOPIC = WS_MESSAGE2.SUBTOPIC || (WS_MESSAGE2.SUBTOPIC = {}));
|
|
156
157
|
})(WS_MESSAGE || (WS_MESSAGE = {}));
|
|
157
158
|
|
|
@@ -488,6 +489,95 @@ async function getInstruments(ctx, params = {}, timeout = 3e4) {
|
|
|
488
489
|
|
|
489
490
|
// src/domains/ohlc/ohlc.ts
|
|
490
491
|
var import_ws4 = __toESM(require("ws"));
|
|
492
|
+
async function streamOHLC(ctx, params, callback) {
|
|
493
|
+
if (!ctx.wsManager) {
|
|
494
|
+
ctx.throwError(
|
|
495
|
+
"STREAM_REQUIRES_CONNECT" /* STREAM_REQUIRES_CONNECT */,
|
|
496
|
+
"Streaming requires a persistent WebSocket. Use connect() instead of auth()."
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
|
|
500
|
+
const subtopic = WS_MESSAGE.SUBTOPIC.OHLC_STREAM;
|
|
501
|
+
const headers = authHeaders(ctx.csrf, Cookies.serialize(ctx.cookies));
|
|
502
|
+
const snapshotBars = [];
|
|
503
|
+
let snapshotDone = false;
|
|
504
|
+
let resolveSnapshot = null;
|
|
505
|
+
const onChartFeed = (body) => {
|
|
506
|
+
if (body?.subtopic !== subtopic) return;
|
|
507
|
+
const data = body.data;
|
|
508
|
+
if (!Array.isArray(data)) return;
|
|
509
|
+
if (!snapshotDone) {
|
|
510
|
+
snapshotBars.push(...data);
|
|
511
|
+
if (body.snapshotEnd) {
|
|
512
|
+
snapshotDone = true;
|
|
513
|
+
callback([...snapshotBars]);
|
|
514
|
+
resolveSnapshot?.();
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
callback(data);
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
ctx.wsManager.on("chartFeedSubtopic" /* CHART_FEED_SUBTOPIC */, onChartFeed);
|
|
521
|
+
try {
|
|
522
|
+
await retryRequest(
|
|
523
|
+
{
|
|
524
|
+
method: "PUT",
|
|
525
|
+
url: endpoints.subscribeInstruments(ctx.broker),
|
|
526
|
+
data: { instruments: [symbol] },
|
|
527
|
+
headers
|
|
528
|
+
},
|
|
529
|
+
ctx.retries
|
|
530
|
+
);
|
|
531
|
+
await retryRequest(
|
|
532
|
+
{
|
|
533
|
+
method: "PUT",
|
|
534
|
+
url: endpoints.charts(ctx.broker),
|
|
535
|
+
data: {
|
|
536
|
+
chartIds: [],
|
|
537
|
+
requests: [
|
|
538
|
+
{
|
|
539
|
+
aggregationPeriodSeconds: resolution,
|
|
540
|
+
extendedSession: true,
|
|
541
|
+
forexPriceField: priceField,
|
|
542
|
+
id: 0,
|
|
543
|
+
maxBarsCount: maxBars,
|
|
544
|
+
range,
|
|
545
|
+
studySubscription: [],
|
|
546
|
+
subtopic,
|
|
547
|
+
symbol
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
},
|
|
551
|
+
headers
|
|
552
|
+
},
|
|
553
|
+
ctx.retries
|
|
554
|
+
);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
ctx.wsManager.removeListener("chartFeedSubtopic" /* CHART_FEED_SUBTOPIC */, onChartFeed);
|
|
557
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
558
|
+
ctx.throwError("OHLC_ERROR" /* OHLC_ERROR */, `OHLC stream subscription error: ${message}`);
|
|
559
|
+
}
|
|
560
|
+
await new Promise((resolve, reject) => {
|
|
561
|
+
if (snapshotDone) return resolve();
|
|
562
|
+
const timer = setTimeout(() => {
|
|
563
|
+
if (snapshotBars.length > 0) {
|
|
564
|
+
snapshotDone = true;
|
|
565
|
+
callback([...snapshotBars]);
|
|
566
|
+
resolve();
|
|
567
|
+
} else {
|
|
568
|
+
ctx.wsManager?.removeListener("chartFeedSubtopic" /* CHART_FEED_SUBTOPIC */, onChartFeed);
|
|
569
|
+
reject(new DxtradeError("OHLC_TIMEOUT" /* OHLC_TIMEOUT */, "OHLC stream snapshot timed out"));
|
|
570
|
+
}
|
|
571
|
+
}, 3e4);
|
|
572
|
+
resolveSnapshot = () => {
|
|
573
|
+
clearTimeout(timer);
|
|
574
|
+
resolve();
|
|
575
|
+
};
|
|
576
|
+
});
|
|
577
|
+
return () => {
|
|
578
|
+
ctx.wsManager?.removeListener("chartFeedSubtopic" /* CHART_FEED_SUBTOPIC */, onChartFeed);
|
|
579
|
+
};
|
|
580
|
+
}
|
|
491
581
|
async function getOHLC(ctx, params, timeout = 3e4) {
|
|
492
582
|
ctx.ensureSession();
|
|
493
583
|
const { symbol, resolution = 60, range = 432e3, maxBars = 3500, priceField = "bid" } = params;
|
|
@@ -892,6 +982,23 @@ async function submitOrder(ctx, params) {
|
|
|
892
982
|
|
|
893
983
|
// src/domains/position/position.ts
|
|
894
984
|
var import_ws7 = __toESM(require("ws"));
|
|
985
|
+
function mergePositionsWithMetrics(positions, metrics) {
|
|
986
|
+
const metricsMap = new Map(metrics.map((m) => [m.uid, m]));
|
|
987
|
+
return positions.map((pos) => {
|
|
988
|
+
const m = metricsMap.get(pos.uid);
|
|
989
|
+
return {
|
|
990
|
+
...pos,
|
|
991
|
+
margin: m?.margin ?? 0,
|
|
992
|
+
plOpen: m?.plOpen ?? 0,
|
|
993
|
+
plClosed: m?.plClosed ?? 0,
|
|
994
|
+
totalCommissions: m?.totalCommissions ?? 0,
|
|
995
|
+
totalFinancing: m?.totalFinancing ?? 0,
|
|
996
|
+
plRate: m?.plRate ?? 0,
|
|
997
|
+
averagePrice: m?.averagePrice ?? 0,
|
|
998
|
+
marketValue: m?.marketValue ?? 0
|
|
999
|
+
};
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
895
1002
|
function streamPositions(ctx, callback) {
|
|
896
1003
|
if (!ctx.wsManager) {
|
|
897
1004
|
ctx.throwError(
|
|
@@ -899,25 +1006,38 @@ function streamPositions(ctx, callback) {
|
|
|
899
1006
|
"Streaming requires a persistent WebSocket. Use connect() instead of auth()."
|
|
900
1007
|
);
|
|
901
1008
|
}
|
|
902
|
-
const
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1009
|
+
const emit = () => {
|
|
1010
|
+
const positions = ctx.wsManager.getCached("POSITIONS" /* POSITIONS */);
|
|
1011
|
+
const metrics = ctx.wsManager.getCached("POSITION_METRICS" /* POSITION_METRICS */);
|
|
1012
|
+
if (positions && metrics) {
|
|
1013
|
+
callback(mergePositionsWithMetrics(positions, metrics));
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
const onPositions = () => emit();
|
|
1017
|
+
const onMetrics = () => emit();
|
|
1018
|
+
ctx.wsManager.on("POSITIONS" /* POSITIONS */, onPositions);
|
|
1019
|
+
ctx.wsManager.on("POSITION_METRICS" /* POSITION_METRICS */, onMetrics);
|
|
1020
|
+
emit();
|
|
908
1021
|
return () => {
|
|
909
|
-
ctx.wsManager?.removeListener("POSITIONS" /* POSITIONS */,
|
|
1022
|
+
ctx.wsManager?.removeListener("POSITIONS" /* POSITIONS */, onPositions);
|
|
1023
|
+
ctx.wsManager?.removeListener("POSITION_METRICS" /* POSITION_METRICS */, onMetrics);
|
|
910
1024
|
};
|
|
911
1025
|
}
|
|
912
1026
|
async function getPositions(ctx) {
|
|
913
1027
|
ctx.ensureSession();
|
|
914
1028
|
if (ctx.wsManager) {
|
|
915
|
-
|
|
1029
|
+
const [positions, metrics] = await Promise.all([
|
|
1030
|
+
ctx.wsManager.waitFor("POSITIONS" /* POSITIONS */),
|
|
1031
|
+
ctx.wsManager.waitFor("POSITION_METRICS" /* POSITION_METRICS */)
|
|
1032
|
+
]);
|
|
1033
|
+
return mergePositionsWithMetrics(positions, metrics);
|
|
916
1034
|
}
|
|
917
1035
|
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
918
1036
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
919
1037
|
return new Promise((resolve, reject) => {
|
|
920
1038
|
const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
1039
|
+
let positions = null;
|
|
1040
|
+
let metrics = null;
|
|
921
1041
|
const timer = setTimeout(() => {
|
|
922
1042
|
ws.close();
|
|
923
1043
|
reject(new DxtradeError("ACCOUNT_POSITIONS_TIMEOUT" /* ACCOUNT_POSITIONS_TIMEOUT */, "Account positions timed out"));
|
|
@@ -927,45 +1047,21 @@ async function getPositions(ctx) {
|
|
|
927
1047
|
if (shouldLog(msg, ctx.debug)) debugLog(msg);
|
|
928
1048
|
if (typeof msg === "string") return;
|
|
929
1049
|
if (msg.type === "POSITIONS" /* POSITIONS */) {
|
|
930
|
-
|
|
931
|
-
ws.close();
|
|
932
|
-
resolve(msg.body);
|
|
1050
|
+
positions = msg.body;
|
|
933
1051
|
}
|
|
934
|
-
});
|
|
935
|
-
ws.on("error", (error) => {
|
|
936
|
-
clearTimeout(timer);
|
|
937
|
-
ws.close();
|
|
938
|
-
reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR" /* ACCOUNT_POSITIONS_ERROR */, `Account positions error: ${error.message}`));
|
|
939
|
-
});
|
|
940
|
-
});
|
|
941
|
-
}
|
|
942
|
-
async function getPositionMetrics(ctx, timeout = 3e4) {
|
|
943
|
-
ctx.ensureSession();
|
|
944
|
-
if (ctx.wsManager) {
|
|
945
|
-
return ctx.wsManager.waitFor("POSITION_METRICS" /* POSITION_METRICS */, timeout);
|
|
946
|
-
}
|
|
947
|
-
const wsUrl = endpoints.websocket(ctx.broker, ctx.atmosphereId);
|
|
948
|
-
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
949
|
-
return new Promise((resolve, reject) => {
|
|
950
|
-
const ws = new import_ws7.default(wsUrl, { headers: { Cookie: cookieStr } });
|
|
951
|
-
const timer = setTimeout(() => {
|
|
952
|
-
ws.close();
|
|
953
|
-
reject(new DxtradeError("POSITION_METRICS_TIMEOUT" /* POSITION_METRICS_TIMEOUT */, "Position metrics timed out"));
|
|
954
|
-
}, timeout);
|
|
955
|
-
ws.on("message", (data) => {
|
|
956
|
-
const msg = parseWsData(data);
|
|
957
|
-
if (shouldLog(msg, ctx.debug)) debugLog(msg);
|
|
958
|
-
if (typeof msg === "string") return;
|
|
959
1052
|
if (msg.type === "POSITION_METRICS" /* POSITION_METRICS */) {
|
|
1053
|
+
metrics = msg.body;
|
|
1054
|
+
}
|
|
1055
|
+
if (positions && metrics) {
|
|
960
1056
|
clearTimeout(timer);
|
|
961
1057
|
ws.close();
|
|
962
|
-
resolve(
|
|
1058
|
+
resolve(mergePositionsWithMetrics(positions, metrics));
|
|
963
1059
|
}
|
|
964
1060
|
});
|
|
965
1061
|
ws.on("error", (error) => {
|
|
966
1062
|
clearTimeout(timer);
|
|
967
1063
|
ws.close();
|
|
968
|
-
reject(new DxtradeError("
|
|
1064
|
+
reject(new DxtradeError("ACCOUNT_POSITIONS_ERROR" /* ACCOUNT_POSITIONS_ERROR */, `Account positions error: ${error.message}`));
|
|
969
1065
|
});
|
|
970
1066
|
});
|
|
971
1067
|
}
|
|
@@ -1152,7 +1248,7 @@ var PositionsDomain = class {
|
|
|
1152
1248
|
constructor(_ctx) {
|
|
1153
1249
|
this._ctx = _ctx;
|
|
1154
1250
|
}
|
|
1155
|
-
/** Get all open positions
|
|
1251
|
+
/** Get all open positions with P&L metrics merged. */
|
|
1156
1252
|
get() {
|
|
1157
1253
|
return getPositions(this._ctx);
|
|
1158
1254
|
}
|
|
@@ -1164,11 +1260,7 @@ var PositionsDomain = class {
|
|
|
1164
1260
|
closeAll() {
|
|
1165
1261
|
return closeAllPositions(this._ctx);
|
|
1166
1262
|
}
|
|
1167
|
-
/**
|
|
1168
|
-
metrics() {
|
|
1169
|
-
return getPositionMetrics(this._ctx);
|
|
1170
|
-
}
|
|
1171
|
-
/** Stream real-time position updates. Requires connect(). Returns unsubscribe function. */
|
|
1263
|
+
/** Stream real-time position updates with P&L metrics. Requires connect(). Returns unsubscribe function. */
|
|
1172
1264
|
stream(callback) {
|
|
1173
1265
|
return streamPositions(this._ctx, callback);
|
|
1174
1266
|
}
|
|
@@ -1263,6 +1355,10 @@ var OhlcDomain = class {
|
|
|
1263
1355
|
get(params) {
|
|
1264
1356
|
return getOHLC(this._ctx, params);
|
|
1265
1357
|
}
|
|
1358
|
+
/** Stream real-time OHLC bar updates. Requires connect(). Returns unsubscribe function. */
|
|
1359
|
+
stream(params, callback) {
|
|
1360
|
+
return streamOHLC(this._ctx, params, callback);
|
|
1361
|
+
}
|
|
1266
1362
|
};
|
|
1267
1363
|
var AssessmentsDomain = class {
|
|
1268
1364
|
constructor(_ctx) {
|
|
@@ -1285,7 +1381,7 @@ var DxtradeClient = class {
|
|
|
1285
1381
|
symbols;
|
|
1286
1382
|
/** Instrument operations: get (with optional filtering). */
|
|
1287
1383
|
instruments;
|
|
1288
|
-
/** OHLC price bar operations: get. */
|
|
1384
|
+
/** OHLC price bar operations: get, stream. */
|
|
1289
1385
|
ohlc;
|
|
1290
1386
|
/** PnL assessment operations: get. */
|
|
1291
1387
|
assessments;
|