@imbingox/acex 0.3.0-beta.2 → 0.3.0-beta.3
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 +17 -0
- package/docs/api.md +1457 -0
- package/package.json +3 -2
- package/src/adapters/binance/adapter.ts +10 -1
- package/src/adapters/binance/private-adapter.ts +36 -1
- package/src/adapters/juplend/private-adapter.ts +35 -1
- package/src/adapters/types.ts +8 -0
- package/src/client/runtime.ts +23 -1
- package/src/client/venue-capabilities.ts +109 -0
- package/src/types/client.ts +71 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imbingox/acex",
|
|
3
|
-
"version": "0.3.0-beta.
|
|
3
|
+
"version": "0.3.0-beta.3",
|
|
4
4
|
"description": "Multi-exchange trading SDK for market data, account, and order management",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"index.ts",
|
|
19
|
-
"src/"
|
|
19
|
+
"src/",
|
|
20
|
+
"docs/api.md"
|
|
20
21
|
],
|
|
21
22
|
"scripts": {
|
|
22
23
|
"changeset": "changeset",
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
MarketDefinition,
|
|
3
|
+
VenueMarketCapabilities,
|
|
4
|
+
} from "../../types/index.ts";
|
|
2
5
|
import type {
|
|
3
6
|
FundingRateStreamCallbacks,
|
|
4
7
|
FundingRateStreamOptions,
|
|
@@ -16,6 +19,12 @@ import {
|
|
|
16
19
|
|
|
17
20
|
export class BinanceMarketAdapter implements MarketAdapter {
|
|
18
21
|
readonly venue = "binance" as const;
|
|
22
|
+
readonly marketCapabilities: VenueMarketCapabilities = {
|
|
23
|
+
catalog: "supported",
|
|
24
|
+
l1Book: "supported",
|
|
25
|
+
fundingRate: "market_dependent",
|
|
26
|
+
marketTypes: ["spot", "swap", "future"],
|
|
27
|
+
};
|
|
19
28
|
|
|
20
29
|
private readonly definitions = new Map<string, BinanceMarketDefinition>();
|
|
21
30
|
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { createHmac } from "node:crypto";
|
|
2
2
|
import BigNumber from "bignumber.js";
|
|
3
3
|
import { createManagedWebSocket } from "../../internal/managed-websocket.ts";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
AccountCredentials,
|
|
6
|
+
PositionSide,
|
|
7
|
+
VenueAccountCapabilities,
|
|
8
|
+
VenueOrderCapabilities,
|
|
9
|
+
} from "../../types/index.ts";
|
|
5
10
|
import type {
|
|
6
11
|
CancelAllOrdersRequest,
|
|
7
12
|
CancelOrderRequest,
|
|
@@ -479,6 +484,36 @@ async function readJson<T>(response: Response, url: string): Promise<T> {
|
|
|
479
484
|
|
|
480
485
|
export class BinancePrivateAdapter implements PrivateUserDataAdapter {
|
|
481
486
|
readonly venue = "binance" as const;
|
|
487
|
+
readonly readOnly = false;
|
|
488
|
+
readonly notes = [
|
|
489
|
+
"Capabilities describe the current SDK runtime, not Binance's full exchange API surface.",
|
|
490
|
+
"Funding rate support depends on the market type.",
|
|
491
|
+
"Order commands currently target Binance PAPI UM USD-M symbols; venue-level order.supported does not mean every Binance market type is orderable.",
|
|
492
|
+
];
|
|
493
|
+
readonly accountCapabilities: VenueAccountCapabilities = {
|
|
494
|
+
register: "supported",
|
|
495
|
+
snapshot: "supported",
|
|
496
|
+
updates: "websocket",
|
|
497
|
+
balances: "supported",
|
|
498
|
+
positions: "supported",
|
|
499
|
+
risk: "supported",
|
|
500
|
+
lending: "unsupported",
|
|
501
|
+
credentialsRequired: true,
|
|
502
|
+
};
|
|
503
|
+
readonly orderCapabilities: VenueOrderCapabilities = {
|
|
504
|
+
supported: true,
|
|
505
|
+
openOrders: "supported",
|
|
506
|
+
updates: "websocket",
|
|
507
|
+
create: "supported",
|
|
508
|
+
cancel: "supported",
|
|
509
|
+
cancelAll: "symbol",
|
|
510
|
+
orderTypes: ["limit", "market"],
|
|
511
|
+
timeInForce: ["gtc", "post_only"],
|
|
512
|
+
postOnly: true,
|
|
513
|
+
reduceOnly: true,
|
|
514
|
+
positionSide: "required_for_hedge",
|
|
515
|
+
clientOrderId: true,
|
|
516
|
+
};
|
|
482
517
|
|
|
483
518
|
async bootstrapAccount(
|
|
484
519
|
credentials: AccountCredentials,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
2
|
import { AcexError } from "../../errors.ts";
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
AccountCredentials,
|
|
5
|
+
VenueAccountCapabilities,
|
|
6
|
+
VenueOrderCapabilities,
|
|
7
|
+
} from "../../types/index.ts";
|
|
4
8
|
import type {
|
|
5
9
|
CancelAllOrdersRequest,
|
|
6
10
|
CancelOrderRequest,
|
|
@@ -361,6 +365,36 @@ function mapAccount(
|
|
|
361
365
|
|
|
362
366
|
export class JuplendPrivateAdapter implements PrivateUserDataAdapter {
|
|
363
367
|
readonly venue = "juplend" as const;
|
|
368
|
+
readonly readOnly = true;
|
|
369
|
+
readonly notes = [
|
|
370
|
+
"Juplend support is limited to read-only lending account views.",
|
|
371
|
+
"Order and market data managers are not supported for this venue.",
|
|
372
|
+
];
|
|
373
|
+
readonly accountCapabilities: VenueAccountCapabilities = {
|
|
374
|
+
register: "supported",
|
|
375
|
+
snapshot: "supported",
|
|
376
|
+
updates: "polling",
|
|
377
|
+
balances: "supported",
|
|
378
|
+
positions: "unsupported",
|
|
379
|
+
risk: "supported",
|
|
380
|
+
lending: "supported",
|
|
381
|
+
credentialsRequired: true,
|
|
382
|
+
};
|
|
383
|
+
readonly orderCapabilities: VenueOrderCapabilities = {
|
|
384
|
+
supported: false,
|
|
385
|
+
openOrders: "unsupported",
|
|
386
|
+
updates: "unsupported",
|
|
387
|
+
create: "unsupported",
|
|
388
|
+
cancel: "unsupported",
|
|
389
|
+
cancelAll: "unsupported",
|
|
390
|
+
orderTypes: [],
|
|
391
|
+
timeInForce: [],
|
|
392
|
+
postOnly: false,
|
|
393
|
+
reduceOnly: false,
|
|
394
|
+
positionSide: "unsupported",
|
|
395
|
+
clientOrderId: false,
|
|
396
|
+
reason: "read_only",
|
|
397
|
+
};
|
|
364
398
|
|
|
365
399
|
async bootstrapAccount(
|
|
366
400
|
credentials: AccountCredentials,
|
package/src/adapters/types.ts
CHANGED
|
@@ -6,6 +6,9 @@ import type {
|
|
|
6
6
|
OrderStatus,
|
|
7
7
|
PositionSide,
|
|
8
8
|
Venue,
|
|
9
|
+
VenueAccountCapabilities,
|
|
10
|
+
VenueMarketCapabilities,
|
|
11
|
+
VenueOrderCapabilities,
|
|
9
12
|
} from "../types/index.ts";
|
|
10
13
|
|
|
11
14
|
export interface StreamHandle {
|
|
@@ -69,6 +72,7 @@ export interface FundingRateStreamOptions {
|
|
|
69
72
|
|
|
70
73
|
export interface MarketAdapter {
|
|
71
74
|
readonly venue: Venue;
|
|
75
|
+
readonly marketCapabilities: VenueMarketCapabilities;
|
|
72
76
|
loadMarkets(): Promise<MarketDefinition[]>;
|
|
73
77
|
createL1BookStream(
|
|
74
78
|
market: MarketDefinition,
|
|
@@ -210,6 +214,10 @@ export interface PrivateStreamOptions {
|
|
|
210
214
|
|
|
211
215
|
export interface PrivateUserDataAdapter {
|
|
212
216
|
readonly venue: Venue;
|
|
217
|
+
readonly readOnly: boolean;
|
|
218
|
+
readonly notes: string[];
|
|
219
|
+
readonly accountCapabilities: VenueAccountCapabilities;
|
|
220
|
+
readonly orderCapabilities: VenueOrderCapabilities;
|
|
213
221
|
bootstrapAccount(
|
|
214
222
|
credentials: AccountCredentials,
|
|
215
223
|
accountOptions?: Record<string, unknown>,
|
package/src/client/runtime.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
CancelAllOrdersRequest,
|
|
6
6
|
CancelOrderRequest,
|
|
7
7
|
CreateOrderRequest,
|
|
8
|
+
MarketAdapter,
|
|
8
9
|
PrivateUserDataAdapter,
|
|
9
10
|
RawOrderUpdate,
|
|
10
11
|
} from "../adapters/types.ts";
|
|
@@ -35,6 +36,7 @@ import type {
|
|
|
35
36
|
RegisterAccountResult,
|
|
36
37
|
StopOptions,
|
|
37
38
|
Venue,
|
|
39
|
+
VenueCapabilities,
|
|
38
40
|
} from "../types/index.ts";
|
|
39
41
|
import {
|
|
40
42
|
type ClientContext,
|
|
@@ -45,6 +47,10 @@ import {
|
|
|
45
47
|
type RegisteredAccountRecord,
|
|
46
48
|
} from "./context.ts";
|
|
47
49
|
import { PrivateSubscriptionCoordinator } from "./private-subscription-coordinator.ts";
|
|
50
|
+
import {
|
|
51
|
+
getVenueCapabilitiesSnapshot,
|
|
52
|
+
listVenueCapabilitiesSnapshots,
|
|
53
|
+
} from "./venue-capabilities.ts";
|
|
48
54
|
|
|
49
55
|
const activeClients = new Set<AcexClientImpl>();
|
|
50
56
|
|
|
@@ -89,13 +95,15 @@ export class AcexClientImpl implements AcexClient, ClientContext {
|
|
|
89
95
|
private readonly marketManager: MarketManagerImpl;
|
|
90
96
|
private readonly accountManager: AccountManagerImpl;
|
|
91
97
|
private readonly orderManager: OrderManagerImpl;
|
|
92
|
-
private readonly
|
|
98
|
+
private readonly marketAdapters: Map<Venue, MarketAdapter>;
|
|
99
|
+
private readonly privateAdapters: Map<Venue, PrivateUserDataAdapter>;
|
|
93
100
|
private readonly privateCoordinator: PrivateSubscriptionCoordinator;
|
|
94
101
|
|
|
95
102
|
constructor(options: CreateClientOptions = {}) {
|
|
96
103
|
activeClients.add(this);
|
|
97
104
|
|
|
98
105
|
const marketAdapter = new BinanceMarketAdapter();
|
|
106
|
+
this.marketAdapters = new Map([[marketAdapter.venue, marketAdapter]]);
|
|
99
107
|
const privateAdapters = [
|
|
100
108
|
new BinancePrivateAdapter(),
|
|
101
109
|
new JuplendPrivateAdapter(),
|
|
@@ -142,6 +150,20 @@ export class AcexClientImpl implements AcexClient, ClientContext {
|
|
|
142
150
|
};
|
|
143
151
|
}
|
|
144
152
|
|
|
153
|
+
getVenueCapabilities(venue: Venue): VenueCapabilities {
|
|
154
|
+
return getVenueCapabilitiesSnapshot(venue, {
|
|
155
|
+
marketAdapters: this.marketAdapters,
|
|
156
|
+
privateAdapters: this.privateAdapters,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
listVenueCapabilities(): VenueCapabilities[] {
|
|
161
|
+
return listVenueCapabilitiesSnapshots({
|
|
162
|
+
marketAdapters: this.marketAdapters,
|
|
163
|
+
privateAdapters: this.privateAdapters,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
145
167
|
async registerAccount(
|
|
146
168
|
input: RegisterAccountInput,
|
|
147
169
|
): Promise<RegisterAccountResult> {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MarketAdapter,
|
|
3
|
+
PrivateUserDataAdapter,
|
|
4
|
+
} from "../adapters/types.ts";
|
|
5
|
+
import type {
|
|
6
|
+
VenueAccountCapabilities,
|
|
7
|
+
VenueCapabilities,
|
|
8
|
+
VenueMarketCapabilities,
|
|
9
|
+
VenueOrderCapabilities,
|
|
10
|
+
} from "../types/client.ts";
|
|
11
|
+
import { SUPPORTED_VENUES, type Venue } from "../types/shared.ts";
|
|
12
|
+
|
|
13
|
+
const unsupportedAccount: VenueAccountCapabilities = {
|
|
14
|
+
register: "unsupported",
|
|
15
|
+
snapshot: "unsupported",
|
|
16
|
+
updates: "unsupported",
|
|
17
|
+
balances: "unsupported",
|
|
18
|
+
positions: "unsupported",
|
|
19
|
+
risk: "unsupported",
|
|
20
|
+
lending: "unsupported",
|
|
21
|
+
credentialsRequired: false,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const unsupportedOrder: Omit<VenueOrderCapabilities, "reason"> = {
|
|
25
|
+
supported: false,
|
|
26
|
+
openOrders: "unsupported",
|
|
27
|
+
updates: "unsupported",
|
|
28
|
+
create: "unsupported",
|
|
29
|
+
cancel: "unsupported",
|
|
30
|
+
cancelAll: "unsupported",
|
|
31
|
+
orderTypes: [],
|
|
32
|
+
timeInForce: [],
|
|
33
|
+
postOnly: false,
|
|
34
|
+
reduceOnly: false,
|
|
35
|
+
positionSide: "unsupported",
|
|
36
|
+
clientOrderId: false,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const typeOnlyNotes = [
|
|
40
|
+
"Venue is declared in public types but has no runtime adapter yet.",
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const unsupportedMarket: VenueMarketCapabilities = {
|
|
44
|
+
catalog: "unsupported",
|
|
45
|
+
l1Book: "unsupported",
|
|
46
|
+
fundingRate: "unsupported",
|
|
47
|
+
marketTypes: [],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export interface VenueCapabilityAdapterRegistry {
|
|
51
|
+
marketAdapters: ReadonlyMap<Venue, MarketAdapter>;
|
|
52
|
+
privateAdapters: ReadonlyMap<Venue, PrivateUserDataAdapter>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function getVenueCapabilitiesSnapshot(
|
|
56
|
+
venue: Venue,
|
|
57
|
+
registry: VenueCapabilityAdapterRegistry,
|
|
58
|
+
): VenueCapabilities {
|
|
59
|
+
const marketAdapter = registry.marketAdapters.get(venue);
|
|
60
|
+
const privateAdapter = registry.privateAdapters.get(venue);
|
|
61
|
+
|
|
62
|
+
return cloneVenueCapabilities({
|
|
63
|
+
venue,
|
|
64
|
+
runtimeStatus: marketAdapter || privateAdapter ? "available" : "type_only",
|
|
65
|
+
readOnly: privateAdapter?.readOnly ?? false,
|
|
66
|
+
notes:
|
|
67
|
+
privateAdapter?.notes ??
|
|
68
|
+
(marketAdapter
|
|
69
|
+
? [
|
|
70
|
+
"Capabilities describe the current SDK runtime, not the venue's full API surface.",
|
|
71
|
+
]
|
|
72
|
+
: typeOnlyNotes),
|
|
73
|
+
market: marketAdapter?.marketCapabilities ?? unsupportedMarket,
|
|
74
|
+
account: privateAdapter?.accountCapabilities ?? unsupportedAccount,
|
|
75
|
+
order: privateAdapter?.orderCapabilities ?? {
|
|
76
|
+
...unsupportedOrder,
|
|
77
|
+
reason: "not_implemented",
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function listVenueCapabilitiesSnapshots(
|
|
83
|
+
registry: VenueCapabilityAdapterRegistry,
|
|
84
|
+
): VenueCapabilities[] {
|
|
85
|
+
return SUPPORTED_VENUES.map((venue) =>
|
|
86
|
+
getVenueCapabilitiesSnapshot(venue, registry),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function cloneVenueCapabilities(
|
|
91
|
+
capabilities: VenueCapabilities,
|
|
92
|
+
): VenueCapabilities {
|
|
93
|
+
return {
|
|
94
|
+
...capabilities,
|
|
95
|
+
notes: [...capabilities.notes],
|
|
96
|
+
market: {
|
|
97
|
+
...capabilities.market,
|
|
98
|
+
marketTypes: [...capabilities.market.marketTypes],
|
|
99
|
+
},
|
|
100
|
+
account: {
|
|
101
|
+
...capabilities.account,
|
|
102
|
+
},
|
|
103
|
+
order: {
|
|
104
|
+
...capabilities.order,
|
|
105
|
+
orderTypes: [...capabilities.order.orderTypes],
|
|
106
|
+
timeInForce: [...capabilities.order.timeInForce],
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
package/src/types/client.ts
CHANGED
|
@@ -7,8 +7,10 @@ import type {
|
|
|
7
7
|
MarketDataStatus,
|
|
8
8
|
MarketManager,
|
|
9
9
|
MarketStatusChangedEvent,
|
|
10
|
+
MarketType,
|
|
10
11
|
} from "./market.ts";
|
|
11
12
|
import type {
|
|
13
|
+
CreateOrderType,
|
|
12
14
|
OrderDataStatus,
|
|
13
15
|
OrderManager,
|
|
14
16
|
OrderStatusChangedEvent,
|
|
@@ -56,6 +58,73 @@ export interface ClientEventStreams {
|
|
|
56
58
|
errors(): AsyncIterable<AcexInternalError>;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
export type VenueRuntimeStatus = "available" | "type_only" | "reserved";
|
|
62
|
+
|
|
63
|
+
export type VenueCapabilitySupport = "supported" | "unsupported";
|
|
64
|
+
|
|
65
|
+
export type VenueCapabilityReason =
|
|
66
|
+
| "not_implemented"
|
|
67
|
+
| "read_only"
|
|
68
|
+
| "market_type_unsupported"
|
|
69
|
+
| "sdk_reserved";
|
|
70
|
+
|
|
71
|
+
export type FundingRateCapability = VenueCapabilitySupport | "market_dependent";
|
|
72
|
+
|
|
73
|
+
export type PrivateUpdateCapability = "websocket" | "polling" | "unsupported";
|
|
74
|
+
|
|
75
|
+
export type CancelAllOrdersCapability = "symbol" | "account" | "unsupported";
|
|
76
|
+
|
|
77
|
+
export type PositionSideCapability =
|
|
78
|
+
| "optional"
|
|
79
|
+
| "required_for_hedge"
|
|
80
|
+
| "unsupported";
|
|
81
|
+
|
|
82
|
+
export type OrderTimeInForceCapability = "gtc" | "post_only";
|
|
83
|
+
|
|
84
|
+
export interface VenueMarketCapabilities {
|
|
85
|
+
catalog: VenueCapabilitySupport;
|
|
86
|
+
l1Book: VenueCapabilitySupport;
|
|
87
|
+
fundingRate: FundingRateCapability;
|
|
88
|
+
marketTypes: MarketType[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface VenueAccountCapabilities {
|
|
92
|
+
register: VenueCapabilitySupport;
|
|
93
|
+
snapshot: VenueCapabilitySupport;
|
|
94
|
+
updates: PrivateUpdateCapability;
|
|
95
|
+
balances: VenueCapabilitySupport;
|
|
96
|
+
positions: VenueCapabilitySupport;
|
|
97
|
+
risk: VenueCapabilitySupport;
|
|
98
|
+
lending: VenueCapabilitySupport;
|
|
99
|
+
credentialsRequired: boolean;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface VenueOrderCapabilities {
|
|
103
|
+
supported: boolean;
|
|
104
|
+
openOrders: VenueCapabilitySupport;
|
|
105
|
+
updates: PrivateUpdateCapability;
|
|
106
|
+
create: VenueCapabilitySupport;
|
|
107
|
+
cancel: VenueCapabilitySupport;
|
|
108
|
+
cancelAll: CancelAllOrdersCapability;
|
|
109
|
+
orderTypes: CreateOrderType[];
|
|
110
|
+
timeInForce: OrderTimeInForceCapability[];
|
|
111
|
+
postOnly: boolean;
|
|
112
|
+
reduceOnly: boolean;
|
|
113
|
+
positionSide: PositionSideCapability;
|
|
114
|
+
clientOrderId: boolean;
|
|
115
|
+
reason?: VenueCapabilityReason;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface VenueCapabilities {
|
|
119
|
+
venue: Venue;
|
|
120
|
+
runtimeStatus: VenueRuntimeStatus;
|
|
121
|
+
readOnly: boolean;
|
|
122
|
+
notes: string[];
|
|
123
|
+
market: VenueMarketCapabilities;
|
|
124
|
+
account: VenueAccountCapabilities;
|
|
125
|
+
order: VenueOrderCapabilities;
|
|
126
|
+
}
|
|
127
|
+
|
|
59
128
|
export interface AcexClient {
|
|
60
129
|
readonly market: MarketManager;
|
|
61
130
|
readonly account: AccountManager;
|
|
@@ -64,6 +133,8 @@ export interface AcexClient {
|
|
|
64
133
|
|
|
65
134
|
getStatus(): ClientStatus;
|
|
66
135
|
getHealth(): ClientHealthSnapshot;
|
|
136
|
+
getVenueCapabilities(venue: Venue): VenueCapabilities;
|
|
137
|
+
listVenueCapabilities(): VenueCapabilities[];
|
|
67
138
|
|
|
68
139
|
registerAccount(input: RegisterAccountInput): Promise<RegisterAccountResult>;
|
|
69
140
|
updateAccountCredentials(
|