@n1xyz/nord-ts 0.1.0 → 0.1.2
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/dist/gen/nord_pb.d.ts +196 -105
- package/dist/gen/nord_pb.js +117 -89
- package/dist/gen/openapi.d.ts +149 -7
- package/dist/nord/api/actions.d.ts +22 -1
- package/dist/nord/api/actions.js +85 -17
- package/dist/nord/api/triggers.d.ts +7 -0
- package/dist/nord/api/triggers.js +38 -0
- package/dist/nord/client/Nord.d.ts +10 -1
- package/dist/nord/client/Nord.js +21 -0
- package/dist/nord/client/NordUser.d.ts +54 -1
- package/dist/nord/client/NordUser.js +97 -0
- package/dist/types.d.ts +16 -3
- package/dist/types.js +30 -4
- package/dist/utils.js +1 -0
- package/package.json +2 -2
- package/src/gen/nord_pb.ts +268 -173
- package/src/gen/openapi.ts +149 -7
- package/src/nord/api/actions.ts +121 -19
- package/src/nord/api/triggers.ts +57 -0
- package/src/nord/client/Nord.ts +27 -0
- package/src/nord/client/NordUser.ts +160 -1
- package/src/types.ts +34 -3
- package/src/utils.ts +1 -0
- package/src/gen/nord.ts +0 -7593
package/src/gen/openapi.ts
CHANGED
|
@@ -84,8 +84,12 @@ export interface paths {
|
|
|
84
84
|
get: {
|
|
85
85
|
parameters: {
|
|
86
86
|
query: {
|
|
87
|
+
/** @description Start action ID (exclusive) */
|
|
87
88
|
from: number;
|
|
89
|
+
/** @description End action ID (inclusive) */
|
|
88
90
|
to: number;
|
|
91
|
+
/** @description Optionally provided binary version of client, so nord server can ensure all actions provided are executable by client. */
|
|
92
|
+
clientVersion?: components["schemas"]["ExecutableVersion"] | null;
|
|
89
93
|
};
|
|
90
94
|
header?: never;
|
|
91
95
|
path?: never;
|
|
@@ -109,6 +113,14 @@ export interface paths {
|
|
|
109
113
|
"application/json": components["schemas"]["RangeTooLarge"];
|
|
110
114
|
};
|
|
111
115
|
};
|
|
116
|
+
501: {
|
|
117
|
+
headers: {
|
|
118
|
+
[name: string]: unknown;
|
|
119
|
+
};
|
|
120
|
+
content: {
|
|
121
|
+
"application/json": components["schemas"]["NotImplemented"];
|
|
122
|
+
};
|
|
123
|
+
};
|
|
112
124
|
};
|
|
113
125
|
};
|
|
114
126
|
put?: never;
|
|
@@ -137,6 +149,14 @@ export interface paths {
|
|
|
137
149
|
"application/octet-stream": unknown;
|
|
138
150
|
};
|
|
139
151
|
};
|
|
152
|
+
413: {
|
|
153
|
+
headers: {
|
|
154
|
+
[name: string]: unknown;
|
|
155
|
+
};
|
|
156
|
+
content: {
|
|
157
|
+
"application/json": components["schemas"]["PayloadTooLarge"];
|
|
158
|
+
};
|
|
159
|
+
};
|
|
140
160
|
415: {
|
|
141
161
|
headers: {
|
|
142
162
|
/**
|
|
@@ -779,7 +799,7 @@ export interface paths {
|
|
|
779
799
|
[name: string]: unknown;
|
|
780
800
|
};
|
|
781
801
|
content: {
|
|
782
|
-
"application/json": components["schemas"]["
|
|
802
|
+
"application/json": components["schemas"]["AccountTriggerInfo"][] | null;
|
|
783
803
|
};
|
|
784
804
|
};
|
|
785
805
|
};
|
|
@@ -976,6 +996,79 @@ export interface paths {
|
|
|
976
996
|
patch?: never;
|
|
977
997
|
trace?: never;
|
|
978
998
|
};
|
|
999
|
+
"/state/download": {
|
|
1000
|
+
parameters: {
|
|
1001
|
+
query?: never;
|
|
1002
|
+
header?: never;
|
|
1003
|
+
path?: never;
|
|
1004
|
+
cookie?: never;
|
|
1005
|
+
};
|
|
1006
|
+
/** @description Returns state download link and metadata, as defined by nearest(up to equality) snapshot `time` or `action_id`` or `timestamp`. If not specified, returns latest snapshot. Example: /state/download?actionId=1 /state/download?time&2025-09-22T12:34:56Z /state/download?timestamp&1695380000 - Does not implemented yet. To get the latest snap use: /state/download - w/o any params.
|
|
1007
|
+
*
|
|
1008
|
+
* The link from responce can be inserted to search bar in browser to download. */
|
|
1009
|
+
get: {
|
|
1010
|
+
parameters: {
|
|
1011
|
+
query?: never;
|
|
1012
|
+
header?: never;
|
|
1013
|
+
path?: never;
|
|
1014
|
+
cookie?: never;
|
|
1015
|
+
};
|
|
1016
|
+
requestBody?: never;
|
|
1017
|
+
responses: {
|
|
1018
|
+
200: {
|
|
1019
|
+
headers: {
|
|
1020
|
+
[name: string]: unknown;
|
|
1021
|
+
};
|
|
1022
|
+
content: {
|
|
1023
|
+
"application/json": components["schemas"]["StateDownloadMeta"];
|
|
1024
|
+
};
|
|
1025
|
+
};
|
|
1026
|
+
501: {
|
|
1027
|
+
headers: {
|
|
1028
|
+
[name: string]: unknown;
|
|
1029
|
+
};
|
|
1030
|
+
content: {
|
|
1031
|
+
"application/json": components["schemas"]["NotImplemented"];
|
|
1032
|
+
};
|
|
1033
|
+
};
|
|
1034
|
+
};
|
|
1035
|
+
};
|
|
1036
|
+
put?: never;
|
|
1037
|
+
post?: never;
|
|
1038
|
+
delete?: never;
|
|
1039
|
+
options?: never;
|
|
1040
|
+
head?: never;
|
|
1041
|
+
patch?: never;
|
|
1042
|
+
trace?: never;
|
|
1043
|
+
};
|
|
1044
|
+
"/state/download/{snapshot_id}": {
|
|
1045
|
+
parameters: {
|
|
1046
|
+
query?: never;
|
|
1047
|
+
header?: never;
|
|
1048
|
+
path?: never;
|
|
1049
|
+
cookie?: never;
|
|
1050
|
+
};
|
|
1051
|
+
/** @description Typical HTTP file download endpoint. Actually same as provided by S3 storages. Means supports Range header, Content-Length, Content-Type, ETag and so on, and relevant headers. */
|
|
1052
|
+
get: {
|
|
1053
|
+
parameters: {
|
|
1054
|
+
query?: never;
|
|
1055
|
+
header?: never;
|
|
1056
|
+
path: {
|
|
1057
|
+
snapshot_id: string;
|
|
1058
|
+
};
|
|
1059
|
+
cookie?: never;
|
|
1060
|
+
};
|
|
1061
|
+
requestBody?: never;
|
|
1062
|
+
responses: never;
|
|
1063
|
+
};
|
|
1064
|
+
put?: never;
|
|
1065
|
+
post?: never;
|
|
1066
|
+
delete?: never;
|
|
1067
|
+
options?: never;
|
|
1068
|
+
head?: never;
|
|
1069
|
+
patch?: never;
|
|
1070
|
+
trace?: never;
|
|
1071
|
+
};
|
|
979
1072
|
"/tv": {
|
|
980
1073
|
parameters: {
|
|
981
1074
|
query?: never;
|
|
@@ -1911,12 +2004,25 @@ export interface components {
|
|
|
1911
2004
|
AcceptedMediaType: {
|
|
1912
2005
|
expected: string;
|
|
1913
2006
|
};
|
|
2007
|
+
PayloadTooLarge: {
|
|
2008
|
+
/** Format: uint */
|
|
2009
|
+
limit: number;
|
|
2010
|
+
};
|
|
1914
2011
|
ActionsQuery: {
|
|
1915
|
-
/**
|
|
2012
|
+
/**
|
|
2013
|
+
* Format: uint64
|
|
2014
|
+
* @description Start action ID (exclusive)
|
|
2015
|
+
*/
|
|
1916
2016
|
from: number;
|
|
1917
|
-
/**
|
|
2017
|
+
/**
|
|
2018
|
+
* Format: uint64
|
|
2019
|
+
* @description End action ID (inclusive)
|
|
2020
|
+
*/
|
|
1918
2021
|
to: number;
|
|
2022
|
+
/** @description Optionally provided binary version of client, so nord server can ensure all actions provided are executable by client. */
|
|
2023
|
+
clientVersion?: components["schemas"]["ExecutableVersion"] | null;
|
|
1919
2024
|
};
|
|
2025
|
+
ExecutableVersion: string;
|
|
1920
2026
|
ActionsItem: {
|
|
1921
2027
|
/** Format: uint64 */
|
|
1922
2028
|
actionId: number;
|
|
@@ -1929,6 +2035,10 @@ export interface components {
|
|
|
1929
2035
|
/** Format: uint16 */
|
|
1930
2036
|
maximal: number;
|
|
1931
2037
|
};
|
|
2038
|
+
NotImplemented: {
|
|
2039
|
+
/** @description Human readable message describing what to expect next. */
|
|
2040
|
+
message: string;
|
|
2041
|
+
};
|
|
1932
2042
|
ActionNotFound: null;
|
|
1933
2043
|
/** @description Returns fee parts per market per balance change per action per account. Fee is taken from user without return. Please note that some operations need some deposit which will be returned - these are not part of fees. */
|
|
1934
2044
|
FillRole: "maker" | "taker";
|
|
@@ -2259,14 +2369,23 @@ export interface components {
|
|
|
2259
2369
|
/** @enum {string} */
|
|
2260
2370
|
TriggerKind: "stopLoss" | "takeProfit";
|
|
2261
2371
|
/** @enum {string} */
|
|
2262
|
-
TriggerStatus: "
|
|
2263
|
-
|
|
2372
|
+
TriggerStatus: "Active" | "Success" | "Removed" | "Canceled";
|
|
2373
|
+
/** @description Trigger into per account. */
|
|
2374
|
+
AccountTriggerInfo: {
|
|
2264
2375
|
/** Format: uint32 */
|
|
2265
2376
|
marketId: number;
|
|
2377
|
+
key: components["schemas"]["TriggerKey"];
|
|
2378
|
+
triggerPrices: components["schemas"]["TriggerPrice"];
|
|
2379
|
+
/** Format: uint64 */
|
|
2380
|
+
actionId: number;
|
|
2381
|
+
};
|
|
2382
|
+
TriggerKey: {
|
|
2266
2383
|
side: components["schemas"]["Side"];
|
|
2267
2384
|
kind: components["schemas"]["TriggerKind"];
|
|
2268
|
-
|
|
2269
|
-
|
|
2385
|
+
};
|
|
2386
|
+
TriggerPrice: {
|
|
2387
|
+
trigger: components["schemas"]["PositivePriceMantissa"];
|
|
2388
|
+
settlement?: components["schemas"]["PositivePriceMantissa"] | null;
|
|
2270
2389
|
};
|
|
2271
2390
|
/**
|
|
2272
2391
|
* Format: uint64
|
|
@@ -2334,6 +2453,29 @@ export interface components {
|
|
|
2334
2453
|
*/
|
|
2335
2454
|
pageSize: number | null;
|
|
2336
2455
|
};
|
|
2456
|
+
DownloadFilter: components["schemas"]["Op_for_DataDateTime"] | components["schemas"]["Op_for_uint64"] | components["schemas"]["Op_for_uint64"] | null;
|
|
2457
|
+
/** @description Parses tag (anycase), and value in round braces using `from_str`. */
|
|
2458
|
+
Op_for_DataDateTime: {
|
|
2459
|
+
le: components["schemas"]["DataDateTime"];
|
|
2460
|
+
};
|
|
2461
|
+
DataDateTime: string;
|
|
2462
|
+
/** @description Parses tag (anycase), and value in round braces using `from_str`. */
|
|
2463
|
+
Op_for_uint64: {
|
|
2464
|
+
/** Format: uint64 */
|
|
2465
|
+
le: number;
|
|
2466
|
+
};
|
|
2467
|
+
StateDownloadMeta: {
|
|
2468
|
+
/** @description Hash of the state file. Used as ETag. */
|
|
2469
|
+
hash: number[];
|
|
2470
|
+
/**
|
|
2471
|
+
* Format: uri
|
|
2472
|
+
* @description Link to download the state file.
|
|
2473
|
+
*/
|
|
2474
|
+
link: string;
|
|
2475
|
+
/** @description Version of binary which produced this state snapshot. So can decide whether it is compatible with client. todo(repl): After upgrade release make it non-optional. */
|
|
2476
|
+
version?: components["schemas"]["BinaryId"] | null;
|
|
2477
|
+
};
|
|
2478
|
+
BinaryId: string;
|
|
2337
2479
|
/** @description TV config query response https://www.tradingview.com/charting-library-docs/latest/connecting_data/UDF/#data-feed-configuration-data */
|
|
2338
2480
|
TvConfigResponse: {
|
|
2339
2481
|
supported_resolutions: components["schemas"]["Resolution"][];
|
package/src/nord/api/actions.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Decimal from "decimal.js";
|
|
2
2
|
import * as proto from "../../gen/nord_pb";
|
|
3
|
-
import { paths
|
|
3
|
+
import { paths } from "../../gen/openapi";
|
|
4
4
|
import createClient from "openapi-fetch";
|
|
5
5
|
|
|
6
6
|
import { create } from "@bufbuild/protobuf";
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
KeyType,
|
|
11
11
|
Side,
|
|
12
12
|
QuoteSize,
|
|
13
|
+
TriggerKind,
|
|
13
14
|
} from "../../types";
|
|
14
15
|
import {
|
|
15
16
|
assert,
|
|
16
17
|
BigIntValue,
|
|
17
|
-
checkedFetch,
|
|
18
18
|
checkPubKeyLength,
|
|
19
19
|
decodeLengthDelimited,
|
|
20
20
|
SESSION_TTL,
|
|
@@ -55,7 +55,6 @@ async function sendAction(
|
|
|
55
55
|
serverUrl: string,
|
|
56
56
|
makeSignedMessage: (message: Uint8Array) => Promise<Uint8Array>,
|
|
57
57
|
action: proto.Action,
|
|
58
|
-
actionErrorDesc: string,
|
|
59
58
|
): Promise<proto.Receipt> {
|
|
60
59
|
const body = await prepareAction(action, makeSignedMessage);
|
|
61
60
|
// NOTE: restructure and reuse client as it is in Nord.ts
|
|
@@ -67,13 +66,19 @@ async function sendAction(
|
|
|
67
66
|
},
|
|
68
67
|
},
|
|
69
68
|
body: body,
|
|
69
|
+
// NOTE: openapi-fetch ignores headers and types/const headers in schema, and always assume all things are JSON
|
|
70
|
+
// to handle multi type bodies, need these overrides and later adhoc parsing
|
|
71
|
+
bodySerializer: (body) => body,
|
|
72
|
+
parseAs: "stream",
|
|
70
73
|
});
|
|
71
74
|
|
|
72
75
|
if (response.error) {
|
|
73
|
-
throw new Error(
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Failed to ${action.kind.case}, HTTP status ${JSON.stringify(response.error)}`,
|
|
78
|
+
);
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
const rawResp = new Uint8Array(await response.response.
|
|
81
|
+
const rawResp = new Uint8Array(await response.response.bytes());
|
|
77
82
|
|
|
78
83
|
const resp: proto.Receipt = decodeLengthDelimited(
|
|
79
84
|
rawResp,
|
|
@@ -82,7 +87,7 @@ async function sendAction(
|
|
|
82
87
|
|
|
83
88
|
if (resp.kind?.case === "err") {
|
|
84
89
|
throw new Error(
|
|
85
|
-
`Could not ${
|
|
90
|
+
`Could not execute ${action.kind.case}, reason: ${proto.Error[resp.kind.value]}`,
|
|
86
91
|
);
|
|
87
92
|
}
|
|
88
93
|
|
|
@@ -96,14 +101,21 @@ export async function prepareAction(
|
|
|
96
101
|
makeSignedMessage: (message: Uint8Array) => Promise<Uint8Array>,
|
|
97
102
|
) {
|
|
98
103
|
const encoded = sizeDelimitedEncode(proto.ActionSchema, action);
|
|
99
|
-
// NOTE(agent): keep in sync with
|
|
100
|
-
const
|
|
101
|
-
if (encoded.byteLength >
|
|
104
|
+
// NOTE(agent): keep in sync with MAX_ENCODED_ACTION_SIZE in Rust code
|
|
105
|
+
const MAX_ENCODED_ACTION_SIZE = 1024;
|
|
106
|
+
if (encoded.byteLength > MAX_ENCODED_ACTION_SIZE) {
|
|
107
|
+
console.warn("Encoded message:", encoded);
|
|
102
108
|
throw new Error(
|
|
103
|
-
`Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${
|
|
109
|
+
`Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_ENCODED_ACTION_SIZE} bytes).`,
|
|
104
110
|
);
|
|
105
111
|
}
|
|
106
112
|
const body = await makeSignedMessage(encoded);
|
|
113
|
+
if (body.byteLength > MAX_ENCODED_ACTION_SIZE) {
|
|
114
|
+
console.warn("Encoded length:", encoded.byteLength);
|
|
115
|
+
throw new Error(
|
|
116
|
+
`Signed message size (${body.byteLength} bytes) is greater than max payload size (${MAX_ENCODED_ACTION_SIZE} bytes).`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
107
119
|
return body;
|
|
108
120
|
}
|
|
109
121
|
|
|
@@ -147,7 +159,6 @@ export async function createSession(
|
|
|
147
159
|
serverUrl,
|
|
148
160
|
(m) => walletSign(walletSignFn, m),
|
|
149
161
|
action,
|
|
150
|
-
"create a new session",
|
|
151
162
|
);
|
|
152
163
|
|
|
153
164
|
if (resp.kind?.case === "createSessionResult") {
|
|
@@ -180,7 +191,6 @@ export async function revokeSession(
|
|
|
180
191
|
serverUrl,
|
|
181
192
|
(m) => walletSign(walletSignFn, m),
|
|
182
193
|
action,
|
|
183
|
-
"revoke session",
|
|
184
194
|
);
|
|
185
195
|
|
|
186
196
|
return { actionId: resp.actionId };
|
|
@@ -217,7 +227,6 @@ export async function withdraw(
|
|
|
217
227
|
serverUrl,
|
|
218
228
|
(m) => sessionSign(signFn, m),
|
|
219
229
|
action,
|
|
220
|
-
"withdraw",
|
|
221
230
|
);
|
|
222
231
|
|
|
223
232
|
if (resp.kind?.case === "withdrawResult") {
|
|
@@ -257,7 +266,7 @@ export async function placeOrder(
|
|
|
257
266
|
const size = toScaledU64(params.size ?? 0, params.sizeDecimals);
|
|
258
267
|
|
|
259
268
|
const scaledQuote = params.quoteSize
|
|
260
|
-
? params.quoteSize.
|
|
269
|
+
? params.quoteSize.toWire(params.priceDecimals, params.sizeDecimals)
|
|
261
270
|
: undefined;
|
|
262
271
|
|
|
263
272
|
assert(
|
|
@@ -295,7 +304,6 @@ export async function placeOrder(
|
|
|
295
304
|
serverUrl,
|
|
296
305
|
(m) => sessionSign(signFn, m),
|
|
297
306
|
action,
|
|
298
|
-
"place order",
|
|
299
307
|
);
|
|
300
308
|
|
|
301
309
|
if (resp.kind?.case === "placeOrderResult") {
|
|
@@ -339,7 +347,6 @@ export async function cancelOrder(
|
|
|
339
347
|
serverUrl,
|
|
340
348
|
(m) => sessionSign(signFn, m),
|
|
341
349
|
action,
|
|
342
|
-
"cancel order",
|
|
343
350
|
);
|
|
344
351
|
|
|
345
352
|
if (resp.kind?.case === "cancelOrderResult") {
|
|
@@ -389,7 +396,6 @@ export async function transfer(
|
|
|
389
396
|
serverUrl,
|
|
390
397
|
(m) => sessionSign(signFn, m),
|
|
391
398
|
action,
|
|
392
|
-
"transfer",
|
|
393
399
|
);
|
|
394
400
|
|
|
395
401
|
if (resp.kind?.case === "transferred") {
|
|
@@ -406,6 +412,103 @@ export async function transfer(
|
|
|
406
412
|
}
|
|
407
413
|
}
|
|
408
414
|
|
|
415
|
+
export async function addTrigger(
|
|
416
|
+
serverUrl: string,
|
|
417
|
+
signFn: (message: Uint8Array) => Promise<Uint8Array>,
|
|
418
|
+
currentTimestamp: bigint,
|
|
419
|
+
nonce: number,
|
|
420
|
+
params: {
|
|
421
|
+
sessionId: BigIntValue;
|
|
422
|
+
marketId: number;
|
|
423
|
+
side: Side;
|
|
424
|
+
kind: TriggerKind;
|
|
425
|
+
priceDecimals: number;
|
|
426
|
+
triggerPrice: Decimal.Value;
|
|
427
|
+
limitPrice?: Decimal.Value;
|
|
428
|
+
accountId?: number;
|
|
429
|
+
},
|
|
430
|
+
): Promise<{ actionId: bigint }> {
|
|
431
|
+
const triggerPrice = toScaledU64(params.triggerPrice, params.priceDecimals);
|
|
432
|
+
assert(triggerPrice > 0n, "Trigger price must be positive");
|
|
433
|
+
const limitPrice =
|
|
434
|
+
params.limitPrice === undefined
|
|
435
|
+
? undefined
|
|
436
|
+
: toScaledU64(params.limitPrice, params.priceDecimals);
|
|
437
|
+
if (limitPrice !== undefined) {
|
|
438
|
+
assert(limitPrice > 0n, "Limit price must be positive");
|
|
439
|
+
}
|
|
440
|
+
const key = create(proto.TriggerKeySchema, {
|
|
441
|
+
kind:
|
|
442
|
+
params.kind === TriggerKind.StopLoss
|
|
443
|
+
? proto.TriggerKind.STOP_LOSS
|
|
444
|
+
: proto.TriggerKind.TAKE_PROFIT,
|
|
445
|
+
side: params.side === Side.Bid ? proto.Side.BID : proto.Side.ASK,
|
|
446
|
+
});
|
|
447
|
+
const prices = create(proto.Action_TriggerPricesSchema, {
|
|
448
|
+
triggerPrice,
|
|
449
|
+
limitPrice,
|
|
450
|
+
});
|
|
451
|
+
const action = createAction(currentTimestamp, nonce, {
|
|
452
|
+
case: "addTrigger",
|
|
453
|
+
value: create(proto.Action_AddTriggerSchema, {
|
|
454
|
+
sessionId: BigInt(params.sessionId),
|
|
455
|
+
marketId: params.marketId,
|
|
456
|
+
key,
|
|
457
|
+
prices,
|
|
458
|
+
accountId: params.accountId,
|
|
459
|
+
}),
|
|
460
|
+
});
|
|
461
|
+
const resp = await sendAction(
|
|
462
|
+
serverUrl,
|
|
463
|
+
(m) => sessionSign(signFn, m),
|
|
464
|
+
action,
|
|
465
|
+
);
|
|
466
|
+
if (resp.kind?.case === "triggerAdded") {
|
|
467
|
+
return { actionId: resp.actionId };
|
|
468
|
+
}
|
|
469
|
+
throw new Error(`Unexpected receipt kind ${resp.kind?.case}`);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export async function removeTrigger(
|
|
473
|
+
serverUrl: string,
|
|
474
|
+
signFn: (message: Uint8Array) => Promise<Uint8Array>,
|
|
475
|
+
currentTimestamp: bigint,
|
|
476
|
+
nonce: number,
|
|
477
|
+
params: {
|
|
478
|
+
sessionId: BigIntValue;
|
|
479
|
+
marketId: number;
|
|
480
|
+
side: Side;
|
|
481
|
+
kind: TriggerKind;
|
|
482
|
+
accountId?: number;
|
|
483
|
+
},
|
|
484
|
+
): Promise<{ actionId: bigint }> {
|
|
485
|
+
const key = create(proto.TriggerKeySchema, {
|
|
486
|
+
kind:
|
|
487
|
+
params.kind === TriggerKind.StopLoss
|
|
488
|
+
? proto.TriggerKind.STOP_LOSS
|
|
489
|
+
: proto.TriggerKind.TAKE_PROFIT,
|
|
490
|
+
side: params.side === Side.Bid ? proto.Side.BID : proto.Side.ASK,
|
|
491
|
+
});
|
|
492
|
+
const action = createAction(currentTimestamp, nonce, {
|
|
493
|
+
case: "removeTrigger",
|
|
494
|
+
value: create(proto.Action_RemoveTriggerSchema, {
|
|
495
|
+
sessionId: BigInt(params.sessionId),
|
|
496
|
+
marketId: params.marketId,
|
|
497
|
+
key,
|
|
498
|
+
accountId: params.accountId,
|
|
499
|
+
}),
|
|
500
|
+
});
|
|
501
|
+
const resp = await sendAction(
|
|
502
|
+
serverUrl,
|
|
503
|
+
(m) => sessionSign(signFn, m),
|
|
504
|
+
action,
|
|
505
|
+
);
|
|
506
|
+
if (resp.kind?.case === "triggerRemoved") {
|
|
507
|
+
return { actionId: resp.actionId };
|
|
508
|
+
}
|
|
509
|
+
throw new Error(`Unexpected receipt kind ${resp.kind?.case}`);
|
|
510
|
+
}
|
|
511
|
+
|
|
409
512
|
export type AtomicSubaction =
|
|
410
513
|
| {
|
|
411
514
|
kind: "place";
|
|
@@ -452,7 +555,7 @@ export async function atomic(
|
|
|
452
555
|
const price = toScaledU64(a.price ?? 0, a.priceDecimals);
|
|
453
556
|
const size = toScaledU64(a.size ?? 0, a.sizeDecimals);
|
|
454
557
|
const scaledQuote = a.quoteSize
|
|
455
|
-
? a.quoteSize.
|
|
558
|
+
? a.quoteSize.toWire(a.priceDecimals, a.sizeDecimals)
|
|
456
559
|
: undefined;
|
|
457
560
|
|
|
458
561
|
// Require at least one limit to be set (non-zero size, non-zero price, or quoteSize)
|
|
@@ -510,7 +613,6 @@ export async function atomic(
|
|
|
510
613
|
serverUrl,
|
|
511
614
|
(m) => sessionSign(signFn, m),
|
|
512
615
|
action,
|
|
513
|
-
"execute atomic action",
|
|
514
616
|
);
|
|
515
617
|
if (resp.kind?.case === "atomic") {
|
|
516
618
|
return {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import createClient from "openapi-fetch";
|
|
2
|
+
|
|
3
|
+
import { paths, components } from "../../gen/openapi";
|
|
4
|
+
|
|
5
|
+
type AccountTriggerInfo = components["schemas"]["AccountTriggerInfo"];
|
|
6
|
+
type TriggerHistoryPage =
|
|
7
|
+
components["schemas"]["PageResult_for_uint64_and_HistoryTriggerInfo"];
|
|
8
|
+
type HistoryTriggerQuery = components["schemas"]["AccountTriggersQuery"];
|
|
9
|
+
|
|
10
|
+
export type { AccountTriggerInfo, TriggerHistoryPage, HistoryTriggerQuery };
|
|
11
|
+
|
|
12
|
+
export async function getAccountTriggers(
|
|
13
|
+
serverUrl: string,
|
|
14
|
+
accountId: number,
|
|
15
|
+
): Promise<AccountTriggerInfo[]> {
|
|
16
|
+
const client = createClient<paths>({ baseUrl: serverUrl });
|
|
17
|
+
const response = await client.GET("/account/{account_id}/triggers", {
|
|
18
|
+
params: {
|
|
19
|
+
path: { account_id: accountId },
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (response.data === undefined) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Failed to fetch triggers for account ${accountId}: HTTP ${response.response.status}`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return response.data ?? [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getAccountTriggerHistory(
|
|
33
|
+
serverUrl: string,
|
|
34
|
+
accountId: number,
|
|
35
|
+
options: HistoryTriggerQuery,
|
|
36
|
+
): Promise<TriggerHistoryPage> {
|
|
37
|
+
const client = createClient<paths>({ baseUrl: serverUrl });
|
|
38
|
+
const response = await client.GET("/account/{account_id}/triggers/history", {
|
|
39
|
+
params: {
|
|
40
|
+
path: { account_id: accountId },
|
|
41
|
+
query: {
|
|
42
|
+
since: options.since,
|
|
43
|
+
until: options.until,
|
|
44
|
+
pageSize: options.pageSize,
|
|
45
|
+
startInclusive: options.startInclusive,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (!response.data) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Failed to fetch trigger history for account ${accountId}: HTTP ${response.response.status}`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return response.data;
|
|
57
|
+
}
|
package/src/nord/client/Nord.ts
CHANGED
|
@@ -6,6 +6,8 @@ import * as proto from "../../gen/nord_pb";
|
|
|
6
6
|
import type { paths } from "../../gen/openapi.ts";
|
|
7
7
|
import {
|
|
8
8
|
Account,
|
|
9
|
+
AccountPnlPage,
|
|
10
|
+
AccountPnlQuery,
|
|
9
11
|
ActionResponse,
|
|
10
12
|
AggregateMetrics,
|
|
11
13
|
Info,
|
|
@@ -636,6 +638,31 @@ export class Nord {
|
|
|
636
638
|
});
|
|
637
639
|
}
|
|
638
640
|
|
|
641
|
+
/**
|
|
642
|
+
* Get profit and loss history for an account
|
|
643
|
+
*
|
|
644
|
+
* @param accountId - Account ID to query
|
|
645
|
+
* @param query - Optional time and pagination filters
|
|
646
|
+
* @returns Page of PnL entries ordered from latest to oldest
|
|
647
|
+
* @throws {NordError} If the request fails
|
|
648
|
+
*/
|
|
649
|
+
public async getAccountPnl(
|
|
650
|
+
accountId: number,
|
|
651
|
+
query?: Partial<AccountPnlQuery>,
|
|
652
|
+
): Promise<AccountPnlPage> {
|
|
653
|
+
return await this.GET("/account/{account_id}/pnl", {
|
|
654
|
+
params: {
|
|
655
|
+
path: { account_id: accountId },
|
|
656
|
+
query: {
|
|
657
|
+
since: query?.since,
|
|
658
|
+
until: query?.until,
|
|
659
|
+
startInclusive: query?.startInclusive,
|
|
660
|
+
pageSize: query?.pageSize,
|
|
661
|
+
},
|
|
662
|
+
},
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
|
|
639
666
|
/**
|
|
640
667
|
* Get market statistics (alias for marketsStats for backward compatibility)
|
|
641
668
|
*
|