@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imbingox/acex",
3
- "version": "0.3.0-beta.2",
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 { MarketDefinition } from "../../types/index.ts";
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 { AccountCredentials, PositionSide } from "../../types/index.ts";
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 { AccountCredentials } from "../../types/index.ts";
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,
@@ -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>,
@@ -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 privateAdapters: Map<string, PrivateUserDataAdapter>;
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
+ }
@@ -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(