@imbingox/acex 0.1.0-beta.0 → 0.1.0-beta.1

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.
Files changed (64) hide show
  1. package/README.md +12 -54
  2. package/index.ts +1 -0
  3. package/package.json +15 -24
  4. package/src/adapters/binance/adapter.ts +53 -0
  5. package/src/adapters/binance/book-ticker.ts +123 -0
  6. package/src/adapters/binance/market-catalog.ts +251 -0
  7. package/src/adapters/types.ts +43 -0
  8. package/src/client/context.ts +60 -0
  9. package/src/client/create-client.ts +6 -0
  10. package/src/client/runtime.ts +283 -0
  11. package/src/errors.ts +20 -0
  12. package/src/index.ts +4 -0
  13. package/src/internal/async-event-bus.ts +100 -0
  14. package/src/internal/filters.ts +119 -0
  15. package/src/internal/managed-websocket.ts +258 -0
  16. package/src/managers/account-manager.ts +315 -0
  17. package/src/managers/market-manager.ts +642 -0
  18. package/src/managers/order-manager.ts +304 -0
  19. package/src/types/account.ts +160 -0
  20. package/src/types/client.ts +79 -0
  21. package/src/types/index.ts +5 -0
  22. package/src/types/market.ts +136 -0
  23. package/src/types/order.ts +142 -0
  24. package/src/types/shared.ts +78 -0
  25. package/dist/adapters/ccxt/aster-ccxt-adapter.d.ts +0 -157
  26. package/dist/adapters/ccxt/aster-ccxt-adapter.js +0 -272
  27. package/dist/adapters/ccxt/binance-usdm-ccxt-adapter.d.ts +0 -179
  28. package/dist/adapters/ccxt/binance-usdm-ccxt-adapter.js +0 -537
  29. package/dist/adapters/fake/fake-aster-adapter.d.ts +0 -130
  30. package/dist/adapters/fake/fake-aster-adapter.js +0 -283
  31. package/dist/adapters/types.d.ts +0 -210
  32. package/dist/adapters/types.js +0 -1
  33. package/dist/core/client.d.ts +0 -37
  34. package/dist/core/client.js +0 -45
  35. package/dist/core/recovery.d.ts +0 -22
  36. package/dist/core/recovery.js +0 -18
  37. package/dist/core/runtime.d.ts +0 -26
  38. package/dist/core/runtime.js +0 -150
  39. package/dist/errors/acex-error.d.ts +0 -25
  40. package/dist/errors/acex-error.js +0 -54
  41. package/dist/index.d.ts +0 -5
  42. package/dist/index.js +0 -3
  43. package/dist/managers/account-manager.d.ts +0 -41
  44. package/dist/managers/account-manager.js +0 -80
  45. package/dist/managers/market-manager.d.ts +0 -16
  46. package/dist/managers/market-manager.js +0 -28
  47. package/dist/managers/order-manager.d.ts +0 -87
  48. package/dist/managers/order-manager.js +0 -122
  49. package/dist/runtime/async-queue.d.ts +0 -8
  50. package/dist/runtime/async-queue.js +0 -88
  51. package/dist/runtime/request-id.d.ts +0 -1
  52. package/dist/runtime/request-id.js +0 -5
  53. package/dist/store/account-store.d.ts +0 -52
  54. package/dist/store/account-store.js +0 -18
  55. package/dist/store/health-store.d.ts +0 -16
  56. package/dist/store/health-store.js +0 -29
  57. package/dist/store/market-store.d.ts +0 -42
  58. package/dist/store/market-store.js +0 -51
  59. package/dist/store/order-store.d.ts +0 -38
  60. package/dist/store/order-store.js +0 -49
  61. package/dist/testing/create-fake-runtime.d.ts +0 -5
  62. package/dist/testing/create-fake-runtime.js +0 -7
  63. package/dist/types/public.d.ts +0 -11
  64. package/dist/types/public.js +0 -1
@@ -0,0 +1,304 @@
1
+ import type {
2
+ AccountAwareManager,
3
+ ClientContext,
4
+ HealthReporter,
5
+ ManagerLifecycle,
6
+ } from "../client/context.ts";
7
+ import { AsyncEventBus } from "../internal/async-event-bus.ts";
8
+ import { matchesOrderFilter } from "../internal/filters.ts";
9
+ import type {
10
+ Exchange,
11
+ GetOrderInput,
12
+ OrderDataStatus,
13
+ OrderEvent,
14
+ OrderEventStreams,
15
+ OrderManager,
16
+ OrderSnapshot,
17
+ OrderSnapshotReplacedEvent,
18
+ OrderStatusChangedEvent,
19
+ SubscribeOrdersInput,
20
+ UnsubscribeOrdersInput,
21
+ } from "../types/index.ts";
22
+
23
+ interface OrderRecord {
24
+ accountId: string;
25
+ exchange: Exchange;
26
+ subscribed: boolean;
27
+ snapshots: Map<string, OrderSnapshot>;
28
+ status: OrderDataStatus;
29
+ }
30
+
31
+ function cloneOrderStatus(status: OrderDataStatus): OrderDataStatus {
32
+ return { ...status };
33
+ }
34
+
35
+ export class OrderManagerImpl
36
+ implements
37
+ OrderManager,
38
+ ManagerLifecycle,
39
+ AccountAwareManager,
40
+ HealthReporter<OrderDataStatus>
41
+ {
42
+ readonly events: OrderEventStreams;
43
+
44
+ private readonly context: ClientContext;
45
+ private readonly orderBus = new AsyncEventBus<OrderEvent>();
46
+ private readonly orderStatusBus =
47
+ new AsyncEventBus<OrderStatusChangedEvent>();
48
+ private readonly records = new Map<string, OrderRecord>();
49
+
50
+ constructor(context: ClientContext) {
51
+ this.context = context;
52
+
53
+ this.events = {
54
+ status: (filter) =>
55
+ this.orderStatusBus.stream((event) =>
56
+ matchesOrderFilter(
57
+ { accountId: event.accountId, exchange: event.exchange },
58
+ filter,
59
+ ),
60
+ ),
61
+ updates: (filter) =>
62
+ this.orderBus.stream((event) =>
63
+ matchesOrderFilter(
64
+ {
65
+ accountId: event.accountId,
66
+ exchange: event.exchange,
67
+ symbol: "symbol" in event ? event.symbol : undefined,
68
+ },
69
+ filter,
70
+ ),
71
+ ),
72
+ };
73
+ }
74
+
75
+ // --- OrderManager public API ---
76
+
77
+ async subscribeOrders(input: SubscribeOrdersInput): Promise<void> {
78
+ this.context.assertStarted();
79
+ const account = this.context.getRegisteredAccount(input.accountId);
80
+ this.context.ensurePrivateCredentials(input.accountId);
81
+
82
+ const record = this.getOrCreateRecord(input.accountId, account.exchange);
83
+ record.subscribed = true;
84
+ record.status = {
85
+ ...this.createStatus(input.accountId, account.exchange, "active"),
86
+ ready: true,
87
+ runtimeStatus: "healthy",
88
+ lastReceivedAt: this.context.now(),
89
+ lastReadyAt: this.context.now(),
90
+ };
91
+
92
+ const event: OrderSnapshotReplacedEvent = {
93
+ type: "order.snapshot_replaced",
94
+ accountId: record.accountId,
95
+ exchange: record.exchange,
96
+ snapshot: [...record.snapshots.values()],
97
+ ts: this.context.now(),
98
+ };
99
+
100
+ this.orderBus.publish(event);
101
+ this.publishStatus(record);
102
+ }
103
+
104
+ async unsubscribeOrders(input: UnsubscribeOrdersInput): Promise<void> {
105
+ const record = this.records.get(input.accountId);
106
+ if (!record?.subscribed) {
107
+ return;
108
+ }
109
+
110
+ record.subscribed = false;
111
+ record.status = {
112
+ ...record.status,
113
+ activity: "inactive",
114
+ runtimeStatus: "stopped",
115
+ inactiveSince: this.context.now(),
116
+ };
117
+ this.publishStatus(record);
118
+ }
119
+
120
+ getOrder(input: GetOrderInput): OrderSnapshot | undefined {
121
+ const record = this.records.get(input.accountId);
122
+ if (!record) {
123
+ return undefined;
124
+ }
125
+
126
+ if (!input.orderId && !input.clientOrderId) {
127
+ return undefined;
128
+ }
129
+
130
+ for (const snapshot of record.snapshots.values()) {
131
+ if (input.orderId && snapshot.orderId === input.orderId) {
132
+ return snapshot;
133
+ }
134
+
135
+ if (
136
+ input.clientOrderId &&
137
+ snapshot.clientOrderId === input.clientOrderId
138
+ ) {
139
+ return snapshot;
140
+ }
141
+ }
142
+
143
+ return undefined;
144
+ }
145
+
146
+ getOpenOrders(accountId: string, symbol?: string): OrderSnapshot[] {
147
+ const record = this.records.get(accountId);
148
+ if (!record) {
149
+ return [];
150
+ }
151
+
152
+ return [...record.snapshots.values()].filter((snapshot) => {
153
+ if (symbol && snapshot.symbol !== symbol) {
154
+ return false;
155
+ }
156
+
157
+ return (
158
+ snapshot.status === "open" || snapshot.status === "partially_filled"
159
+ );
160
+ });
161
+ }
162
+
163
+ getOrderStatus(accountId: string): OrderDataStatus | undefined {
164
+ const status = this.records.get(accountId)?.status;
165
+ return status ? cloneOrderStatus(status) : undefined;
166
+ }
167
+
168
+ // --- ManagerLifecycle ---
169
+
170
+ onClientStarted(): void {
171
+ const now = this.context.now();
172
+
173
+ for (const [accountId, record] of this.records) {
174
+ if (!record.subscribed) {
175
+ continue;
176
+ }
177
+
178
+ const account = this.context.getRegisteredAccount(accountId);
179
+ const creds = account.credentials;
180
+ if (!creds?.apiKey || !creds.secret) {
181
+ continue;
182
+ }
183
+
184
+ record.status = {
185
+ ...this.createStatus(accountId, account.exchange, "active"),
186
+ ready: true,
187
+ runtimeStatus: "healthy",
188
+ lastReceivedAt: now,
189
+ lastReadyAt: now,
190
+ };
191
+ this.publishStatus(record);
192
+ }
193
+ }
194
+
195
+ onClientStopping(now: number): void {
196
+ for (const record of this.records.values()) {
197
+ if (!record.subscribed) {
198
+ continue;
199
+ }
200
+
201
+ record.status = {
202
+ ...record.status,
203
+ activity: "inactive",
204
+ runtimeStatus: "stopped",
205
+ inactiveSince: now,
206
+ };
207
+ this.publishStatus(record);
208
+ }
209
+ }
210
+
211
+ // --- AccountAwareManager ---
212
+
213
+ onAccountRemoved(accountId: string, now: number): void {
214
+ const record = this.records.get(accountId);
215
+ if (!record) {
216
+ return;
217
+ }
218
+
219
+ record.subscribed = false;
220
+ record.status = {
221
+ ...record.status,
222
+ activity: "inactive",
223
+ runtimeStatus: "stopped",
224
+ inactiveSince: now,
225
+ };
226
+ this.publishStatus(record);
227
+ this.records.delete(accountId);
228
+ }
229
+
230
+ onCredentialsUpdated(accountId: string, exchange: Exchange): void {
231
+ const record = this.records.get(accountId);
232
+ if (!record?.subscribed) {
233
+ return;
234
+ }
235
+
236
+ record.status = this.createStatus(accountId, exchange, "active");
237
+ record.status.ready = true;
238
+ record.status.runtimeStatus = "healthy";
239
+ record.status.lastReadyAt = this.context.now();
240
+ this.publishStatus(record);
241
+ }
242
+
243
+ // --- HealthReporter ---
244
+
245
+ getStatuses(): OrderDataStatus[] {
246
+ return [...this.records.values()]
247
+ .map((record) => cloneOrderStatus(record.status))
248
+ .sort((left, right) =>
249
+ `${left.exchange}:${left.accountId}`.localeCompare(
250
+ `${right.exchange}:${right.accountId}`,
251
+ ),
252
+ );
253
+ }
254
+
255
+ // --- Internal helpers ---
256
+
257
+ private getOrCreateRecord(
258
+ accountId: string,
259
+ exchange: Exchange,
260
+ ): OrderRecord {
261
+ const existing = this.records.get(accountId);
262
+ if (existing) {
263
+ return existing;
264
+ }
265
+
266
+ const record: OrderRecord = {
267
+ accountId,
268
+ exchange,
269
+ subscribed: false,
270
+ snapshots: new Map(),
271
+ status: this.createStatus(accountId, exchange, "inactive"),
272
+ };
273
+
274
+ this.records.set(accountId, record);
275
+ return record;
276
+ }
277
+
278
+ private createStatus(
279
+ accountId: string,
280
+ exchange: Exchange,
281
+ activity: "active" | "inactive",
282
+ ): OrderDataStatus {
283
+ return {
284
+ accountId,
285
+ exchange,
286
+ activity,
287
+ ready: false,
288
+ runtimeStatus: activity === "active" ? "bootstrap_pending" : "stopped",
289
+ };
290
+ }
291
+
292
+ private publishStatus(record: OrderRecord): void {
293
+ const event: OrderStatusChangedEvent = {
294
+ type: "order.status_changed",
295
+ accountId: record.accountId,
296
+ exchange: record.exchange,
297
+ status: cloneOrderStatus(record.status),
298
+ ts: this.context.now(),
299
+ };
300
+
301
+ this.orderStatusBus.publish(event);
302
+ this.context.publishHealthEvent(event);
303
+ }
304
+ }
@@ -0,0 +1,160 @@
1
+ import type {
2
+ Exchange,
3
+ PrivateRuntimeStatus,
4
+ SubscriptionActivity,
5
+ } from "./shared.ts";
6
+
7
+ export interface AccountDataStatus {
8
+ accountId: string;
9
+ exchange: Exchange;
10
+ activity: SubscriptionActivity;
11
+ ready: boolean;
12
+ runtimeStatus?: PrivateRuntimeStatus;
13
+ lastReceivedAt?: number;
14
+ lastReadyAt?: number;
15
+ inactiveSince?: number;
16
+ reason?:
17
+ | "credentials_missing"
18
+ | "auth_failed"
19
+ | "ws_disconnected"
20
+ | "heartbeat_timeout"
21
+ | "reconciling";
22
+ }
23
+
24
+ export interface AccountStatusChangedEvent {
25
+ type: "account.status_changed";
26
+ accountId: string;
27
+ exchange: Exchange;
28
+ status: AccountDataStatus;
29
+ ts: number;
30
+ }
31
+
32
+ export type PositionSide = "long" | "short" | "net";
33
+
34
+ export interface SubscribeAccountInput {
35
+ accountId: string;
36
+ }
37
+
38
+ export interface UnsubscribeAccountInput {
39
+ accountId: string;
40
+ }
41
+
42
+ export interface PositionKeyInput {
43
+ accountId: string;
44
+ symbol: string;
45
+ side?: PositionSide;
46
+ }
47
+
48
+ export interface AccountEventFilter {
49
+ accountId?: string;
50
+ exchange?: Exchange;
51
+ symbol?: string;
52
+ }
53
+
54
+ export interface BalanceSnapshot {
55
+ accountId: string;
56
+ exchange: Exchange;
57
+ asset: string;
58
+ free: string;
59
+ used: string;
60
+ total: string;
61
+ exchangeTs?: number;
62
+ receivedAt: number;
63
+ updatedAt: number;
64
+ seq: number;
65
+ }
66
+
67
+ export interface PositionSnapshot {
68
+ accountId: string;
69
+ exchange: Exchange;
70
+ symbol: string;
71
+ side: PositionSide;
72
+ size: string;
73
+ entryPrice?: string;
74
+ markPrice?: string;
75
+ unrealizedPnl?: string;
76
+ leverage?: string;
77
+ liquidationPrice?: string;
78
+ exchangeTs?: number;
79
+ receivedAt: number;
80
+ updatedAt: number;
81
+ seq: number;
82
+ }
83
+
84
+ export interface RiskSnapshot {
85
+ accountId: string;
86
+ exchange: Exchange;
87
+ equity?: string;
88
+ marginRatio?: string;
89
+ initialMargin?: string;
90
+ maintenanceMargin?: string;
91
+ exchangeTs?: number;
92
+ receivedAt: number;
93
+ updatedAt: number;
94
+ seq: number;
95
+ }
96
+
97
+ export interface AccountSnapshot {
98
+ accountId: string;
99
+ exchange: Exchange;
100
+ balances: Record<string, BalanceSnapshot>;
101
+ positions: PositionSnapshot[];
102
+ risk?: RiskSnapshot;
103
+ exchangeTs?: number;
104
+ receivedAt: number;
105
+ updatedAt: number;
106
+ }
107
+
108
+ export interface AccountEventBase {
109
+ accountId: string;
110
+ exchange: Exchange;
111
+ ts: number;
112
+ }
113
+
114
+ export interface BalanceUpdatedEvent extends AccountEventBase {
115
+ type: "balance.updated";
116
+ asset: string;
117
+ snapshot: BalanceSnapshot;
118
+ }
119
+
120
+ export interface PositionUpdatedEvent extends AccountEventBase {
121
+ type: "position.updated";
122
+ symbol: string;
123
+ snapshot: PositionSnapshot;
124
+ }
125
+
126
+ export interface RiskUpdatedEvent extends AccountEventBase {
127
+ type: "risk.updated";
128
+ snapshot: RiskSnapshot;
129
+ }
130
+
131
+ export interface AccountSnapshotReplacedEvent extends AccountEventBase {
132
+ type: "account.snapshot_replaced";
133
+ snapshot: AccountSnapshot;
134
+ }
135
+
136
+ export type AccountEvent =
137
+ | BalanceUpdatedEvent
138
+ | PositionUpdatedEvent
139
+ | RiskUpdatedEvent
140
+ | AccountSnapshotReplacedEvent;
141
+
142
+ export interface AccountEventStreams {
143
+ updates(filter?: AccountEventFilter): AsyncIterable<AccountEvent>;
144
+ status(filter?: AccountEventFilter): AsyncIterable<AccountStatusChangedEvent>;
145
+ }
146
+
147
+ export interface AccountManager {
148
+ readonly events: AccountEventStreams;
149
+
150
+ subscribeAccount(input: SubscribeAccountInput): Promise<void>;
151
+ unsubscribeAccount(input: UnsubscribeAccountInput): Promise<void>;
152
+
153
+ getAccountSnapshot(accountId: string): AccountSnapshot | undefined;
154
+ getBalances(accountId: string): BalanceSnapshot[];
155
+ getBalance(accountId: string, asset: string): BalanceSnapshot | undefined;
156
+ getPositions(accountId: string, symbol?: string): PositionSnapshot[];
157
+ getPosition(input: PositionKeyInput): PositionSnapshot | undefined;
158
+ getRiskSnapshot(accountId: string): RiskSnapshot | undefined;
159
+ getAccountStatus(accountId: string): AccountDataStatus | undefined;
160
+ }
@@ -0,0 +1,79 @@
1
+ import type {
2
+ AccountDataStatus,
3
+ AccountManager,
4
+ AccountStatusChangedEvent,
5
+ } from "./account.ts";
6
+ import type {
7
+ MarketDataStatus,
8
+ MarketManager,
9
+ MarketStatusChangedEvent,
10
+ } from "./market.ts";
11
+ import type {
12
+ OrderDataStatus,
13
+ OrderManager,
14
+ OrderStatusChangedEvent,
15
+ } from "./order.ts";
16
+ import type {
17
+ AccountCredentials,
18
+ AcexInternalError,
19
+ ClientStatus,
20
+ CreateClientOptions,
21
+ Exchange,
22
+ RegisterAccountInput,
23
+ RegisterAccountResult,
24
+ StopOptions,
25
+ } from "./shared.ts";
26
+
27
+ export interface ClientHealthSnapshot {
28
+ clientStatus: ClientStatus;
29
+ markets: MarketDataStatus[];
30
+ accounts: AccountDataStatus[];
31
+ orders: OrderDataStatus[];
32
+ updatedAt: number;
33
+ }
34
+
35
+ export interface ClientStatusChangedEvent {
36
+ type: "client.status_changed";
37
+ status: ClientStatus;
38
+ ts: number;
39
+ }
40
+
41
+ export type HealthEvent =
42
+ | ClientStatusChangedEvent
43
+ | MarketStatusChangedEvent
44
+ | AccountStatusChangedEvent
45
+ | OrderStatusChangedEvent;
46
+
47
+ export interface HealthEventFilter {
48
+ scope?: "client" | "market" | "account" | "order";
49
+ exchange?: Exchange;
50
+ accountId?: string;
51
+ symbol?: string;
52
+ }
53
+
54
+ export interface ClientEventStreams {
55
+ health(filter?: HealthEventFilter): AsyncIterable<HealthEvent>;
56
+ errors(): AsyncIterable<AcexInternalError>;
57
+ }
58
+
59
+ export interface AcexClient {
60
+ readonly market: MarketManager;
61
+ readonly account: AccountManager;
62
+ readonly order: OrderManager;
63
+ readonly events: ClientEventStreams;
64
+
65
+ getStatus(): ClientStatus;
66
+ getHealth(): ClientHealthSnapshot;
67
+
68
+ registerAccount(input: RegisterAccountInput): Promise<RegisterAccountResult>;
69
+ updateAccountCredentials(
70
+ accountId: string,
71
+ credentials: AccountCredentials,
72
+ ): Promise<void>;
73
+ removeAccount(accountId: string): Promise<void>;
74
+
75
+ start(): Promise<void>;
76
+ stop(options?: StopOptions): Promise<void>;
77
+ }
78
+
79
+ export type CreateClient = (options?: CreateClientOptions) => AcexClient;
@@ -0,0 +1,5 @@
1
+ export * from "./account.ts";
2
+ export * from "./client.ts";
3
+ export * from "./market.ts";
4
+ export * from "./order.ts";
5
+ export * from "./shared.ts";
@@ -0,0 +1,136 @@
1
+ import type {
2
+ Exchange,
3
+ MarketFreshness,
4
+ SubscriptionActivity,
5
+ } from "./shared.ts";
6
+
7
+ export type MarketType = "spot" | "swap" | "future";
8
+
9
+ export interface MarketDefinition {
10
+ exchange: Exchange;
11
+ symbol: string;
12
+ id: string;
13
+ type: MarketType;
14
+ base: string;
15
+ quote: string;
16
+ settle?: string;
17
+ active: boolean;
18
+ contract: boolean;
19
+ linear?: boolean;
20
+ inverse?: boolean;
21
+ contractSize?: string;
22
+ pricePrecision: number;
23
+ amountPrecision: number;
24
+ priceStep: string;
25
+ amountStep: string;
26
+ minAmount?: string;
27
+ minNotional?: string;
28
+ expiry?: number;
29
+ raw: Record<string, unknown>;
30
+ }
31
+
32
+ export interface MarketDataStatus {
33
+ exchange: Exchange;
34
+ symbol: string;
35
+ activity: SubscriptionActivity;
36
+ ready: boolean;
37
+ freshness?: MarketFreshness;
38
+ lastReceivedAt?: number;
39
+ lastReadyAt?: number;
40
+ inactiveSince?: number;
41
+ reason?: "ws_disconnected" | "heartbeat_timeout" | "reconciling";
42
+ }
43
+
44
+ export interface MarketKeyInput {
45
+ exchange: Exchange;
46
+ symbol: string;
47
+ }
48
+
49
+ export interface SubscribeL1BookInput extends MarketKeyInput {}
50
+
51
+ export interface SubscribeFundingRateInput extends MarketKeyInput {}
52
+
53
+ export interface MarketEventFilter {
54
+ exchange?: Exchange;
55
+ symbol?: string;
56
+ }
57
+
58
+ export interface L1Book {
59
+ exchange: Exchange;
60
+ symbol: string;
61
+ bidPrice: string;
62
+ bidSize: string;
63
+ askPrice: string;
64
+ askSize: string;
65
+ exchangeTs?: number;
66
+ receivedAt: number;
67
+ updatedAt: number;
68
+ version: number;
69
+ }
70
+
71
+ export interface FundingRateSnapshot {
72
+ exchange: Exchange;
73
+ symbol: string;
74
+ fundingRate: string;
75
+ nextFundingTime?: number;
76
+ markPrice?: string;
77
+ indexPrice?: string;
78
+ exchangeTs?: number;
79
+ receivedAt: number;
80
+ updatedAt: number;
81
+ version: number;
82
+ }
83
+
84
+ export interface MarketStatusChangedEvent {
85
+ type: "market.status_changed";
86
+ exchange: Exchange;
87
+ symbol: string;
88
+ status: MarketDataStatus;
89
+ ts: number;
90
+ }
91
+
92
+ export interface L1BookUpdatedEvent {
93
+ type: "l1_book.updated";
94
+ exchange: Exchange;
95
+ symbol: string;
96
+ snapshot: L1Book;
97
+ ts: number;
98
+ }
99
+
100
+ export interface FundingRateUpdatedEvent {
101
+ type: "funding_rate.updated";
102
+ exchange: Exchange;
103
+ symbol: string;
104
+ snapshot: FundingRateSnapshot;
105
+ ts: number;
106
+ }
107
+
108
+ export type MarketEvent =
109
+ | L1BookUpdatedEvent
110
+ | FundingRateUpdatedEvent
111
+ | MarketStatusChangedEvent;
112
+
113
+ export interface MarketEventStreams {
114
+ l1BookUpdates(filter?: MarketEventFilter): AsyncIterable<L1BookUpdatedEvent>;
115
+ fundingRateUpdates(
116
+ filter?: MarketEventFilter,
117
+ ): AsyncIterable<FundingRateUpdatedEvent>;
118
+ status(filter?: MarketEventFilter): AsyncIterable<MarketStatusChangedEvent>;
119
+ all(filter?: MarketEventFilter): AsyncIterable<MarketEvent>;
120
+ }
121
+
122
+ export interface MarketManager {
123
+ readonly events: MarketEventStreams;
124
+
125
+ loadMarkets(): Promise<void>;
126
+ subscribeL1Book(input: SubscribeL1BookInput): Promise<void>;
127
+ unsubscribeL1Book(input: SubscribeL1BookInput): Promise<void>;
128
+ subscribeFundingRate(input: SubscribeFundingRateInput): Promise<void>;
129
+ unsubscribeFundingRate(input: SubscribeFundingRateInput): Promise<void>;
130
+
131
+ getMarket(symbol: string): MarketDefinition | undefined;
132
+ listMarkets(): MarketDefinition[];
133
+ getL1Book(key: MarketKeyInput): L1Book | undefined;
134
+ getFundingRate(key: MarketKeyInput): FundingRateSnapshot | undefined;
135
+ getMarketStatus(key: MarketKeyInput): MarketDataStatus | undefined;
136
+ }