@danielgroen/dxtrade-api 1.0.21 → 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 +15 -5
- package/dist/index.d.mts +72 -2
- package/dist/index.d.ts +72 -2
- package/dist/index.js +177 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +177 -5
- package/dist/index.mjs.map +1 -1
- package/llms.txt +7 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -21,18 +21,18 @@ npm install dxtrade-api
|
|
|
21
21
|
|
|
22
22
|
- [x] Authentication & session management
|
|
23
23
|
- [x] Submit orders (market, limit, stop)
|
|
24
|
-
- [x]
|
|
25
|
-
- [x]
|
|
24
|
+
- [x] Get & cancel orders
|
|
25
|
+
- [x] Positions (get, close, close all)
|
|
26
|
+
- [x] Position metrics (per-position P&L)
|
|
27
|
+
- [x] Account metrics, trade journal & trade history
|
|
26
28
|
- [x] Symbol search & instrument info
|
|
27
29
|
- [x] OHLC / price bar data
|
|
28
30
|
- [x] PnL assessments
|
|
29
31
|
- [x] Multi-broker support (FTMO, Eightcap, Lark Funding)
|
|
30
32
|
- [x] Full TypeScript support
|
|
31
33
|
- [ ] Batch orders
|
|
32
|
-
- [ ] Close whole position helper
|
|
33
34
|
- [ ] Modify existing orders
|
|
34
35
|
- [ ] Real-time price streaming
|
|
35
|
-
- [ ] Order history
|
|
36
36
|
|
|
37
37
|
## Quick Start
|
|
38
38
|
|
|
@@ -105,16 +105,22 @@ BROKER.FTMO // "https://dxtrade.ftmo.com"
|
|
|
105
105
|
### Trading
|
|
106
106
|
|
|
107
107
|
- `client.submitOrder(params)` — Submit an order and wait for WebSocket confirmation
|
|
108
|
+
- `client.getOrders()` — Get all pending/open orders via WebSocket
|
|
109
|
+
- `client.cancelOrder(orderChainId)` — Cancel a single pending order
|
|
110
|
+
- `client.cancelAllOrders()` — Cancel all pending orders
|
|
108
111
|
|
|
109
112
|
### Positions
|
|
110
113
|
|
|
111
114
|
- `client.getPositions()` — Get all open positions via WebSocket
|
|
112
|
-
- `client.closePosition(params)` — Close a position
|
|
115
|
+
- `client.closePosition(params)` — Close a position (supports partial closes via the quantity field)
|
|
116
|
+
- `client.closeAllPositions()` — Close all open positions with market orders
|
|
117
|
+
- `client.getPositionMetrics()` — Get position-level P&L metrics via WebSocket
|
|
113
118
|
|
|
114
119
|
### Account
|
|
115
120
|
|
|
116
121
|
- `client.getAccountMetrics()` — Get account metrics (equity, balance, margin, open P&L, etc.)
|
|
117
122
|
- `client.getTradeJournal({ from, to })` — Fetch trade journal entries for a date range (Unix timestamps)
|
|
123
|
+
- `client.getTradeHistory({ from, to })` — Fetch trade history for a date range (Unix timestamps)
|
|
118
124
|
|
|
119
125
|
### Analytics
|
|
120
126
|
|
|
@@ -152,8 +158,11 @@ const client = new DxtradeClient({
|
|
|
152
158
|
cp .env.example .env # fill in credentials
|
|
153
159
|
npm run example:connect
|
|
154
160
|
npm run example:order
|
|
161
|
+
npm run example:orders
|
|
155
162
|
npm run example:positions
|
|
156
163
|
npm run example:close-position
|
|
164
|
+
npm run example:close-all-positions
|
|
165
|
+
npm run example:position-metrics
|
|
157
166
|
npm run example:assessments
|
|
158
167
|
npm run example:assessments:btc
|
|
159
168
|
npm run example:account
|
|
@@ -163,6 +172,7 @@ npm run example:instruments:forex
|
|
|
163
172
|
npm run example:symbol
|
|
164
173
|
npm run example:symbol:btc
|
|
165
174
|
npm run example:trade-journal
|
|
175
|
+
npm run example:trade-history
|
|
166
176
|
npm run example:debug
|
|
167
177
|
```
|
|
168
178
|
|
package/dist/index.d.mts
CHANGED
|
@@ -11,12 +11,17 @@ declare const endpoints: {
|
|
|
11
11
|
instrumentInfo: (base: string, symbol: string, tzOffset: number) => string;
|
|
12
12
|
submitOrder: (base: string) => string;
|
|
13
13
|
closePosition: (base: string) => string;
|
|
14
|
+
cancelOrder: (base: string, accountId: string, orderChainId: number) => string;
|
|
14
15
|
assessments: (base: string) => string;
|
|
15
16
|
websocket: (base: string, atmosphereId?: string | null) => string;
|
|
16
17
|
tradeJournal: (base: string, params: {
|
|
17
18
|
from: number;
|
|
18
19
|
to: number;
|
|
19
20
|
}) => string;
|
|
21
|
+
tradeHistory: (base: string, params: {
|
|
22
|
+
from: number;
|
|
23
|
+
to: number;
|
|
24
|
+
}) => string;
|
|
20
25
|
subscribeInstruments: (base: string) => string;
|
|
21
26
|
charts: (base: string) => string;
|
|
22
27
|
};
|
|
@@ -57,12 +62,18 @@ declare enum ERROR {
|
|
|
57
62
|
OHLC_TIMEOUT = "OHLC_TIMEOUT",
|
|
58
63
|
OHLC_ERROR = "OHLC_ERROR",
|
|
59
64
|
ORDER_ERROR = "ORDER_ERROR",
|
|
65
|
+
ORDERS_TIMEOUT = "ORDERS_TIMEOUT",
|
|
66
|
+
ORDERS_ERROR = "ORDERS_ERROR",
|
|
67
|
+
CANCEL_ORDER_ERROR = "CANCEL_ORDER_ERROR",
|
|
60
68
|
POSITION_CLOSE_ERROR = "POSITION_CLOSE_ERROR",
|
|
69
|
+
POSITION_METRICS_TIMEOUT = "POSITION_METRICS_TIMEOUT",
|
|
70
|
+
POSITION_METRICS_ERROR = "POSITION_METRICS_ERROR",
|
|
61
71
|
ACCOUNT_METRICS_TIMEOUT = "ACCOUNT_METRICS_TIMEOUT",
|
|
62
72
|
ACCOUNT_METRICS_ERROR = "ACCOUNT_METRICS_ERROR",
|
|
63
73
|
ACCOUNT_POSITIONS_TIMEOUT = "ACCOUNT_POSITIONS_TIMEOUT",
|
|
64
74
|
ACCOUNT_POSITIONS_ERROR = "ACCOUNT_POSITIONS_ERROR",
|
|
65
75
|
TRADE_JOURNAL_ERROR = "TRADE_JOURNAL_ERROR",
|
|
76
|
+
TRADE_HISTORY_ERROR = "TRADE_HISTORY_ERROR",
|
|
66
77
|
ASSESSMENTS_ERROR = "ASSESSMENTS_ERROR"
|
|
67
78
|
}
|
|
68
79
|
declare enum WS_MESSAGE {
|
|
@@ -71,11 +82,11 @@ declare enum WS_MESSAGE {
|
|
|
71
82
|
AVAILABLE_WATCHLISTS = "AVAILABLE_WATCHLISTS",
|
|
72
83
|
CHART_FEED_SUBTOPIC = "chartFeedSubtopic",
|
|
73
84
|
INSTRUMENTS = "INSTRUMENTS",
|
|
74
|
-
INSTRUMENT_METRICS = "INSTRUMENT_METRICS",
|
|
75
85
|
LIMITS = "LIMITS",
|
|
76
86
|
MESSAGE = "MESSAGE",
|
|
77
87
|
ORDERS = "ORDERS",
|
|
78
88
|
POSITIONS = "POSITIONS",
|
|
89
|
+
POSITION_METRICS = "POSITION_METRICS",
|
|
79
90
|
POSITION_CASH_TRANSFERS = "POSITION_CASH_TRANSFERS",
|
|
80
91
|
PRIVATE_LAYOUT_NAMES = "PRIVATE_LAYOUT_NAMES",
|
|
81
92
|
SHARED_PROPERTIES_MESSAGE = "SHARED_PROPERTIES_MESSAGE",
|
|
@@ -94,6 +105,22 @@ declare class DxtradeError extends Error {
|
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
declare namespace Order {
|
|
108
|
+
interface Get {
|
|
109
|
+
account: string;
|
|
110
|
+
orderId: number;
|
|
111
|
+
orderCode: string;
|
|
112
|
+
version: number;
|
|
113
|
+
type: ORDER_TYPE;
|
|
114
|
+
instrument: string;
|
|
115
|
+
status: string;
|
|
116
|
+
finalStatus: boolean;
|
|
117
|
+
side: SIDE;
|
|
118
|
+
tif: TIF;
|
|
119
|
+
legs: Leg[];
|
|
120
|
+
issueTime: string;
|
|
121
|
+
transactionTime: string;
|
|
122
|
+
[key: string]: unknown;
|
|
123
|
+
}
|
|
97
124
|
interface SubmitParams {
|
|
98
125
|
symbol: string;
|
|
99
126
|
side: SIDE;
|
|
@@ -207,6 +234,20 @@ interface WsPayload {
|
|
|
207
234
|
}
|
|
208
235
|
|
|
209
236
|
declare namespace Account {
|
|
237
|
+
interface TradeHistory {
|
|
238
|
+
orderId: number;
|
|
239
|
+
orderCode: string;
|
|
240
|
+
instrument: string;
|
|
241
|
+
side: string;
|
|
242
|
+
type: string;
|
|
243
|
+
status: string;
|
|
244
|
+
quantity: number;
|
|
245
|
+
filledQuantity: number;
|
|
246
|
+
price: number;
|
|
247
|
+
averagePrice: number;
|
|
248
|
+
time: string;
|
|
249
|
+
[key: string]: unknown;
|
|
250
|
+
}
|
|
210
251
|
interface Metrics {
|
|
211
252
|
availableFunds: number;
|
|
212
253
|
marginCallLevel: number | string;
|
|
@@ -318,6 +359,14 @@ declare namespace Position {
|
|
|
318
359
|
takeProfit: number | null;
|
|
319
360
|
stopLoss: number | null;
|
|
320
361
|
}
|
|
362
|
+
interface Metrics {
|
|
363
|
+
positionCode: string;
|
|
364
|
+
openPl: number;
|
|
365
|
+
openPlPerLot: number;
|
|
366
|
+
currentPrice: number;
|
|
367
|
+
convertedOpenPl: number;
|
|
368
|
+
[key: string]: unknown;
|
|
369
|
+
}
|
|
321
370
|
interface Close {
|
|
322
371
|
legs: {
|
|
323
372
|
instrumentId: number;
|
|
@@ -398,12 +447,24 @@ declare class DxtradeClient {
|
|
|
398
447
|
* Supports market, limit, and stop orders with optional stop loss and take profit.
|
|
399
448
|
*/
|
|
400
449
|
submitOrder(params: Order.SubmitParams): Promise<Order.Update>;
|
|
450
|
+
/** Get all pending/open orders via WebSocket. */
|
|
451
|
+
getOrders(): Promise<Order.Get[]>;
|
|
452
|
+
/** Cancel a single pending order by its order chain ID. */
|
|
453
|
+
cancelOrder(orderChainId: number): Promise<void>;
|
|
454
|
+
/** Cancel all pending orders. */
|
|
455
|
+
cancelAllOrders(): Promise<void>;
|
|
401
456
|
/** Get account metrics including equity, balance, margin, and open P&L. */
|
|
402
457
|
getAccountMetrics(): Promise<Account.Metrics>;
|
|
403
458
|
/** Get all open positions via WebSocket. */
|
|
404
459
|
getPositions(): Promise<Position.Get[]>;
|
|
405
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Close a position. Supports partial closes by specifying a quantity smaller than the full position size.
|
|
462
|
+
*/
|
|
406
463
|
closePosition(position: Position.Close): Promise<void>;
|
|
464
|
+
/** Close all open positions with market orders. */
|
|
465
|
+
closeAllPositions(): Promise<void>;
|
|
466
|
+
/** Get position-level P&L metrics via WebSocket. */
|
|
467
|
+
getPositionMetrics(): Promise<Position.Metrics[]>;
|
|
407
468
|
/**
|
|
408
469
|
* Fetch trade journal entries for a date range.
|
|
409
470
|
* @param params.from - Start timestamp (Unix ms)
|
|
@@ -413,6 +474,15 @@ declare class DxtradeClient {
|
|
|
413
474
|
from: number;
|
|
414
475
|
to: number;
|
|
415
476
|
}): Promise<any>;
|
|
477
|
+
/**
|
|
478
|
+
* Fetch trade history for a date range.
|
|
479
|
+
* @param params.from - Start timestamp (Unix ms)
|
|
480
|
+
* @param params.to - End timestamp (Unix ms)
|
|
481
|
+
*/
|
|
482
|
+
getTradeHistory(params: {
|
|
483
|
+
from: number;
|
|
484
|
+
to: number;
|
|
485
|
+
}): Promise<Account.TradeHistory[]>;
|
|
416
486
|
/** Get all available instruments, optionally filtered by partial match (e.g. `{ type: "FOREX" }`). */
|
|
417
487
|
getInstruments(params?: Partial<Instrument.Info>): Promise<Instrument.Info[]>;
|
|
418
488
|
/** Fetch PnL assessments for an instrument within a date range. */
|
package/dist/index.d.ts
CHANGED
|
@@ -11,12 +11,17 @@ declare const endpoints: {
|
|
|
11
11
|
instrumentInfo: (base: string, symbol: string, tzOffset: number) => string;
|
|
12
12
|
submitOrder: (base: string) => string;
|
|
13
13
|
closePosition: (base: string) => string;
|
|
14
|
+
cancelOrder: (base: string, accountId: string, orderChainId: number) => string;
|
|
14
15
|
assessments: (base: string) => string;
|
|
15
16
|
websocket: (base: string, atmosphereId?: string | null) => string;
|
|
16
17
|
tradeJournal: (base: string, params: {
|
|
17
18
|
from: number;
|
|
18
19
|
to: number;
|
|
19
20
|
}) => string;
|
|
21
|
+
tradeHistory: (base: string, params: {
|
|
22
|
+
from: number;
|
|
23
|
+
to: number;
|
|
24
|
+
}) => string;
|
|
20
25
|
subscribeInstruments: (base: string) => string;
|
|
21
26
|
charts: (base: string) => string;
|
|
22
27
|
};
|
|
@@ -57,12 +62,18 @@ declare enum ERROR {
|
|
|
57
62
|
OHLC_TIMEOUT = "OHLC_TIMEOUT",
|
|
58
63
|
OHLC_ERROR = "OHLC_ERROR",
|
|
59
64
|
ORDER_ERROR = "ORDER_ERROR",
|
|
65
|
+
ORDERS_TIMEOUT = "ORDERS_TIMEOUT",
|
|
66
|
+
ORDERS_ERROR = "ORDERS_ERROR",
|
|
67
|
+
CANCEL_ORDER_ERROR = "CANCEL_ORDER_ERROR",
|
|
60
68
|
POSITION_CLOSE_ERROR = "POSITION_CLOSE_ERROR",
|
|
69
|
+
POSITION_METRICS_TIMEOUT = "POSITION_METRICS_TIMEOUT",
|
|
70
|
+
POSITION_METRICS_ERROR = "POSITION_METRICS_ERROR",
|
|
61
71
|
ACCOUNT_METRICS_TIMEOUT = "ACCOUNT_METRICS_TIMEOUT",
|
|
62
72
|
ACCOUNT_METRICS_ERROR = "ACCOUNT_METRICS_ERROR",
|
|
63
73
|
ACCOUNT_POSITIONS_TIMEOUT = "ACCOUNT_POSITIONS_TIMEOUT",
|
|
64
74
|
ACCOUNT_POSITIONS_ERROR = "ACCOUNT_POSITIONS_ERROR",
|
|
65
75
|
TRADE_JOURNAL_ERROR = "TRADE_JOURNAL_ERROR",
|
|
76
|
+
TRADE_HISTORY_ERROR = "TRADE_HISTORY_ERROR",
|
|
66
77
|
ASSESSMENTS_ERROR = "ASSESSMENTS_ERROR"
|
|
67
78
|
}
|
|
68
79
|
declare enum WS_MESSAGE {
|
|
@@ -71,11 +82,11 @@ declare enum WS_MESSAGE {
|
|
|
71
82
|
AVAILABLE_WATCHLISTS = "AVAILABLE_WATCHLISTS",
|
|
72
83
|
CHART_FEED_SUBTOPIC = "chartFeedSubtopic",
|
|
73
84
|
INSTRUMENTS = "INSTRUMENTS",
|
|
74
|
-
INSTRUMENT_METRICS = "INSTRUMENT_METRICS",
|
|
75
85
|
LIMITS = "LIMITS",
|
|
76
86
|
MESSAGE = "MESSAGE",
|
|
77
87
|
ORDERS = "ORDERS",
|
|
78
88
|
POSITIONS = "POSITIONS",
|
|
89
|
+
POSITION_METRICS = "POSITION_METRICS",
|
|
79
90
|
POSITION_CASH_TRANSFERS = "POSITION_CASH_TRANSFERS",
|
|
80
91
|
PRIVATE_LAYOUT_NAMES = "PRIVATE_LAYOUT_NAMES",
|
|
81
92
|
SHARED_PROPERTIES_MESSAGE = "SHARED_PROPERTIES_MESSAGE",
|
|
@@ -94,6 +105,22 @@ declare class DxtradeError extends Error {
|
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
declare namespace Order {
|
|
108
|
+
interface Get {
|
|
109
|
+
account: string;
|
|
110
|
+
orderId: number;
|
|
111
|
+
orderCode: string;
|
|
112
|
+
version: number;
|
|
113
|
+
type: ORDER_TYPE;
|
|
114
|
+
instrument: string;
|
|
115
|
+
status: string;
|
|
116
|
+
finalStatus: boolean;
|
|
117
|
+
side: SIDE;
|
|
118
|
+
tif: TIF;
|
|
119
|
+
legs: Leg[];
|
|
120
|
+
issueTime: string;
|
|
121
|
+
transactionTime: string;
|
|
122
|
+
[key: string]: unknown;
|
|
123
|
+
}
|
|
97
124
|
interface SubmitParams {
|
|
98
125
|
symbol: string;
|
|
99
126
|
side: SIDE;
|
|
@@ -207,6 +234,20 @@ interface WsPayload {
|
|
|
207
234
|
}
|
|
208
235
|
|
|
209
236
|
declare namespace Account {
|
|
237
|
+
interface TradeHistory {
|
|
238
|
+
orderId: number;
|
|
239
|
+
orderCode: string;
|
|
240
|
+
instrument: string;
|
|
241
|
+
side: string;
|
|
242
|
+
type: string;
|
|
243
|
+
status: string;
|
|
244
|
+
quantity: number;
|
|
245
|
+
filledQuantity: number;
|
|
246
|
+
price: number;
|
|
247
|
+
averagePrice: number;
|
|
248
|
+
time: string;
|
|
249
|
+
[key: string]: unknown;
|
|
250
|
+
}
|
|
210
251
|
interface Metrics {
|
|
211
252
|
availableFunds: number;
|
|
212
253
|
marginCallLevel: number | string;
|
|
@@ -318,6 +359,14 @@ declare namespace Position {
|
|
|
318
359
|
takeProfit: number | null;
|
|
319
360
|
stopLoss: number | null;
|
|
320
361
|
}
|
|
362
|
+
interface Metrics {
|
|
363
|
+
positionCode: string;
|
|
364
|
+
openPl: number;
|
|
365
|
+
openPlPerLot: number;
|
|
366
|
+
currentPrice: number;
|
|
367
|
+
convertedOpenPl: number;
|
|
368
|
+
[key: string]: unknown;
|
|
369
|
+
}
|
|
321
370
|
interface Close {
|
|
322
371
|
legs: {
|
|
323
372
|
instrumentId: number;
|
|
@@ -398,12 +447,24 @@ declare class DxtradeClient {
|
|
|
398
447
|
* Supports market, limit, and stop orders with optional stop loss and take profit.
|
|
399
448
|
*/
|
|
400
449
|
submitOrder(params: Order.SubmitParams): Promise<Order.Update>;
|
|
450
|
+
/** Get all pending/open orders via WebSocket. */
|
|
451
|
+
getOrders(): Promise<Order.Get[]>;
|
|
452
|
+
/** Cancel a single pending order by its order chain ID. */
|
|
453
|
+
cancelOrder(orderChainId: number): Promise<void>;
|
|
454
|
+
/** Cancel all pending orders. */
|
|
455
|
+
cancelAllOrders(): Promise<void>;
|
|
401
456
|
/** Get account metrics including equity, balance, margin, and open P&L. */
|
|
402
457
|
getAccountMetrics(): Promise<Account.Metrics>;
|
|
403
458
|
/** Get all open positions via WebSocket. */
|
|
404
459
|
getPositions(): Promise<Position.Get[]>;
|
|
405
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Close a position. Supports partial closes by specifying a quantity smaller than the full position size.
|
|
462
|
+
*/
|
|
406
463
|
closePosition(position: Position.Close): Promise<void>;
|
|
464
|
+
/** Close all open positions with market orders. */
|
|
465
|
+
closeAllPositions(): Promise<void>;
|
|
466
|
+
/** Get position-level P&L metrics via WebSocket. */
|
|
467
|
+
getPositionMetrics(): Promise<Position.Metrics[]>;
|
|
407
468
|
/**
|
|
408
469
|
* Fetch trade journal entries for a date range.
|
|
409
470
|
* @param params.from - Start timestamp (Unix ms)
|
|
@@ -413,6 +474,15 @@ declare class DxtradeClient {
|
|
|
413
474
|
from: number;
|
|
414
475
|
to: number;
|
|
415
476
|
}): Promise<any>;
|
|
477
|
+
/**
|
|
478
|
+
* Fetch trade history for a date range.
|
|
479
|
+
* @param params.from - Start timestamp (Unix ms)
|
|
480
|
+
* @param params.to - End timestamp (Unix ms)
|
|
481
|
+
*/
|
|
482
|
+
getTradeHistory(params: {
|
|
483
|
+
from: number;
|
|
484
|
+
to: number;
|
|
485
|
+
}): Promise<Account.TradeHistory[]>;
|
|
416
486
|
/** Get all available instruments, optionally filtered by partial match (e.g. `{ type: "FOREX" }`). */
|
|
417
487
|
getInstruments(params?: Partial<Instrument.Info>): Promise<Instrument.Info[]>;
|
|
418
488
|
/** Fetch PnL assessments for an instrument within a date range. */
|
package/dist/index.js
CHANGED
|
@@ -62,9 +62,11 @@ var endpoints = {
|
|
|
62
62
|
instrumentInfo: (base, symbol, tzOffset) => `${base}/api/instruments/info?symbol=${symbol}&timezoneOffset=${tzOffset}&withExDividends=true`,
|
|
63
63
|
submitOrder: (base) => `${base}/api/orders/single`,
|
|
64
64
|
closePosition: (base) => `${base}/api/positions/close`,
|
|
65
|
+
cancelOrder: (base, accountId, orderChainId) => `${base}/api/orders/cancel?accountId=${accountId}&orderChainId=${orderChainId}`,
|
|
65
66
|
assessments: (base) => `${base}/api/assessments`,
|
|
66
67
|
websocket: (base, atmosphereId) => `wss://${base.split("//")[1]}/client/connector` + websocketQuery(atmosphereId),
|
|
67
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=`,
|
|
68
70
|
subscribeInstruments: (base) => `${base}/api/instruments/subscribeInstrumentSymbols`,
|
|
69
71
|
charts: (base) => `${base}/api/charts`
|
|
70
72
|
};
|
|
@@ -110,12 +112,18 @@ var ERROR = /* @__PURE__ */ ((ERROR2) => {
|
|
|
110
112
|
ERROR2["OHLC_TIMEOUT"] = "OHLC_TIMEOUT";
|
|
111
113
|
ERROR2["OHLC_ERROR"] = "OHLC_ERROR";
|
|
112
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";
|
|
113
118
|
ERROR2["POSITION_CLOSE_ERROR"] = "POSITION_CLOSE_ERROR";
|
|
119
|
+
ERROR2["POSITION_METRICS_TIMEOUT"] = "POSITION_METRICS_TIMEOUT";
|
|
120
|
+
ERROR2["POSITION_METRICS_ERROR"] = "POSITION_METRICS_ERROR";
|
|
114
121
|
ERROR2["ACCOUNT_METRICS_TIMEOUT"] = "ACCOUNT_METRICS_TIMEOUT";
|
|
115
122
|
ERROR2["ACCOUNT_METRICS_ERROR"] = "ACCOUNT_METRICS_ERROR";
|
|
116
123
|
ERROR2["ACCOUNT_POSITIONS_TIMEOUT"] = "ACCOUNT_POSITIONS_TIMEOUT";
|
|
117
124
|
ERROR2["ACCOUNT_POSITIONS_ERROR"] = "ACCOUNT_POSITIONS_ERROR";
|
|
118
125
|
ERROR2["TRADE_JOURNAL_ERROR"] = "TRADE_JOURNAL_ERROR";
|
|
126
|
+
ERROR2["TRADE_HISTORY_ERROR"] = "TRADE_HISTORY_ERROR";
|
|
119
127
|
ERROR2["ASSESSMENTS_ERROR"] = "ASSESSMENTS_ERROR";
|
|
120
128
|
return ERROR2;
|
|
121
129
|
})(ERROR || {});
|
|
@@ -125,11 +133,11 @@ var WS_MESSAGE = /* @__PURE__ */ ((WS_MESSAGE2) => {
|
|
|
125
133
|
WS_MESSAGE2["AVAILABLE_WATCHLISTS"] = "AVAILABLE_WATCHLISTS";
|
|
126
134
|
WS_MESSAGE2["CHART_FEED_SUBTOPIC"] = "chartFeedSubtopic";
|
|
127
135
|
WS_MESSAGE2["INSTRUMENTS"] = "INSTRUMENTS";
|
|
128
|
-
WS_MESSAGE2["INSTRUMENT_METRICS"] = "INSTRUMENT_METRICS";
|
|
129
136
|
WS_MESSAGE2["LIMITS"] = "LIMITS";
|
|
130
137
|
WS_MESSAGE2["MESSAGE"] = "MESSAGE";
|
|
131
138
|
WS_MESSAGE2["ORDERS"] = "ORDERS";
|
|
132
139
|
WS_MESSAGE2["POSITIONS"] = "POSITIONS";
|
|
140
|
+
WS_MESSAGE2["POSITION_METRICS"] = "POSITION_METRICS";
|
|
133
141
|
WS_MESSAGE2["POSITION_CASH_TRANSFERS"] = "POSITION_CASH_TRANSFERS";
|
|
134
142
|
WS_MESSAGE2["PRIVATE_LAYOUT_NAMES"] = "PRIVATE_LAYOUT_NAMES";
|
|
135
143
|
WS_MESSAGE2["SHARED_PROPERTIES_MESSAGE"] = "SHARED_PROPERTIES_MESSAGE";
|
|
@@ -279,6 +287,32 @@ async function getAccountMetrics(ctx, timeout = 3e4) {
|
|
|
279
287
|
});
|
|
280
288
|
});
|
|
281
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
|
+
}
|
|
282
316
|
async function getTradeJournal(ctx, params) {
|
|
283
317
|
ctx.ensureSession();
|
|
284
318
|
try {
|
|
@@ -630,6 +664,61 @@ function createOrderListener(wsUrl, cookieStr, timeout = 3e4, debug = false) {
|
|
|
630
664
|
});
|
|
631
665
|
return { promise, ready };
|
|
632
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
|
+
}
|
|
633
722
|
async function submitOrder(ctx, params) {
|
|
634
723
|
ctx.ensureSession();
|
|
635
724
|
const {
|
|
@@ -752,6 +841,54 @@ async function getPositions(ctx) {
|
|
|
752
841
|
});
|
|
753
842
|
});
|
|
754
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
|
+
}
|
|
755
892
|
async function closePosition(ctx, data) {
|
|
756
893
|
try {
|
|
757
894
|
await retryRequest(
|
|
@@ -790,7 +927,7 @@ function waitForHandshake(wsUrl, cookieStr, timeout = 3e4, debug = false) {
|
|
|
790
927
|
if (msg.accountId) {
|
|
791
928
|
clearTimeout(timer);
|
|
792
929
|
ws.close();
|
|
793
|
-
resolve(atmosphereId);
|
|
930
|
+
resolve({ atmosphereId, accountId: msg.accountId });
|
|
794
931
|
}
|
|
795
932
|
});
|
|
796
933
|
ws.on("error", (error) => {
|
|
@@ -875,15 +1012,19 @@ async function connect(ctx) {
|
|
|
875
1012
|
await fetchCsrf(ctx);
|
|
876
1013
|
if (ctx.debug) clearDebugLog();
|
|
877
1014
|
const cookieStr = Cookies.serialize(ctx.cookies);
|
|
878
|
-
|
|
1015
|
+
const handshake = await waitForHandshake(endpoints.websocket(ctx.broker), cookieStr, 3e4, ctx.debug);
|
|
1016
|
+
ctx.atmosphereId = handshake.atmosphereId;
|
|
1017
|
+
ctx.accountId = handshake.accountId;
|
|
879
1018
|
if (ctx.config.accountId) {
|
|
880
1019
|
await switchAccount(ctx, ctx.config.accountId);
|
|
881
|
-
|
|
1020
|
+
const reconnect = await waitForHandshake(
|
|
882
1021
|
endpoints.websocket(ctx.broker, ctx.atmosphereId),
|
|
883
1022
|
Cookies.serialize(ctx.cookies),
|
|
884
1023
|
3e4,
|
|
885
1024
|
ctx.debug
|
|
886
1025
|
);
|
|
1026
|
+
ctx.atmosphereId = reconnect.atmosphereId;
|
|
1027
|
+
ctx.accountId = reconnect.accountId;
|
|
887
1028
|
}
|
|
888
1029
|
}
|
|
889
1030
|
|
|
@@ -897,6 +1038,7 @@ var DxtradeClient = class {
|
|
|
897
1038
|
callbacks,
|
|
898
1039
|
cookies: {},
|
|
899
1040
|
csrf: null,
|
|
1041
|
+
accountId: config.accountId ?? null,
|
|
900
1042
|
atmosphereId: null,
|
|
901
1043
|
broker: config.broker,
|
|
902
1044
|
retries: config.retries ?? 3,
|
|
@@ -951,6 +1093,18 @@ var DxtradeClient = class {
|
|
|
951
1093
|
async submitOrder(params) {
|
|
952
1094
|
return submitOrder(this._ctx, params);
|
|
953
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
|
+
}
|
|
954
1108
|
/** Get account metrics including equity, balance, margin, and open P&L. */
|
|
955
1109
|
async getAccountMetrics() {
|
|
956
1110
|
return getAccountMetrics(this._ctx);
|
|
@@ -959,10 +1113,20 @@ var DxtradeClient = class {
|
|
|
959
1113
|
async getPositions() {
|
|
960
1114
|
return getPositions(this._ctx);
|
|
961
1115
|
}
|
|
962
|
-
/**
|
|
1116
|
+
/**
|
|
1117
|
+
* Close a position. Supports partial closes by specifying a quantity smaller than the full position size.
|
|
1118
|
+
*/
|
|
963
1119
|
async closePosition(position) {
|
|
964
1120
|
return closePosition(this._ctx, position);
|
|
965
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
|
+
}
|
|
966
1130
|
/**
|
|
967
1131
|
* Fetch trade journal entries for a date range.
|
|
968
1132
|
* @param params.from - Start timestamp (Unix ms)
|
|
@@ -971,6 +1135,14 @@ var DxtradeClient = class {
|
|
|
971
1135
|
async getTradeJournal(params) {
|
|
972
1136
|
return getTradeJournal(this._ctx, params);
|
|
973
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
|
+
}
|
|
974
1146
|
/** Get all available instruments, optionally filtered by partial match (e.g. `{ type: "FOREX" }`). */
|
|
975
1147
|
async getInstruments(params = {}) {
|
|
976
1148
|
return getInstruments(this._ctx, params);
|