@polyester/sdk 0.8.0 → 0.9.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.
- package/CHANGELOG.md +22 -0
- package/dist/catalogs/decimal.js +6 -4
- package/dist/catalogs/decimal.js.map +1 -1
- package/dist/catalogs/readers.js +1 -1
- package/dist/gen/auth/v1/policies_pb.d.ts +28 -10
- package/dist/gen/auth/v1/policies_pb.d.ts.map +1 -1
- package/dist/gen/auth/v1/policies_pb.js +37 -31
- package/dist/gen/auth/v1/policies_pb.js.map +1 -1
- package/dist/gen/fees/v1/fees_pb.d.ts +0 -6
- package/dist/gen/fees/v1/fees_pb.d.ts.map +1 -1
- package/dist/gen/fees/v1/fees_pb.js +1 -1
- package/dist/gen/fees/v1/fees_pb.js.map +1 -1
- package/dist/gen/marketoverview/v1/marketoverview_pb.d.ts +6 -11
- package/dist/gen/marketoverview/v1/marketoverview_pb.d.ts.map +1 -1
- package/dist/gen/marketoverview/v1/marketoverview_pb.js +1 -1
- package/dist/gen/marketoverview/v1/marketoverview_pb.js.map +1 -1
- package/dist/gen/orderbook/v1/orderbook_pb.d.ts +3 -3
- package/dist/gen/orderbook/v1/orderbook_pb.js +1 -1
- package/dist/gen/orderbook/v1/orderbook_pb.js.map +1 -1
- package/dist/gen/orders/v1/orders_pb.d.ts +11 -11
- package/dist/gen/orders/v1/orders_pb.js +1 -1
- package/dist/gen/orders/v1/orders_pb.js.map +1 -1
- package/dist/gen/triggers/v1/triggers_pb.d.ts +6 -12
- package/dist/gen/triggers/v1/triggers_pb.d.ts.map +1 -1
- package/dist/gen/triggers/v1/triggers_pb.js +1 -1
- package/dist/gen/triggers/v1/triggers_pb.js.map +1 -1
- package/dist/services/fees/fees.schemas.d.ts +2 -3
- package/dist/services/fees/fees.schemas.d.ts.map +1 -1
- package/dist/services/fees/fees.schemas.js +3 -4
- package/dist/services/fees/fees.schemas.js.map +1 -1
- package/dist/services/lifecycle/lifecycle.schemas.d.ts +42 -42
- package/dist/services/market-data/market-data.schemas.js +1 -1
- package/dist/services/market-overview/market-overview.d.ts +1 -1
- package/dist/services/market-overview/market-overview.js +1 -1
- package/dist/services/market-overview/market-overview.js.map +1 -1
- package/dist/services/market-overview/market-overview.schemas.d.ts +20 -7
- package/dist/services/market-overview/market-overview.schemas.d.ts.map +1 -1
- package/dist/services/market-overview/market-overview.schemas.js +8 -6
- package/dist/services/market-overview/market-overview.schemas.js.map +1 -1
- package/dist/services/orderbook/orderbook.d.ts +3 -4
- package/dist/services/orderbook/orderbook.d.ts.map +1 -1
- package/dist/services/orderbook/orderbook.js +13 -10
- package/dist/services/orderbook/orderbook.js.map +1 -1
- package/dist/services/orderbook/orderbook.schemas.d.ts +8 -9
- package/dist/services/orderbook/orderbook.schemas.d.ts.map +1 -1
- package/dist/services/orderbook/orderbook.schemas.js +9 -8
- package/dist/services/orderbook/orderbook.schemas.js.map +1 -1
- package/dist/services/orders/orders-batch.schemas.d.ts +209 -35
- package/dist/services/orders/orders-batch.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-batch.schemas.js +11 -9
- package/dist/services/orders/orders-batch.schemas.js.map +1 -1
- package/dist/services/orders/orders-input.schemas.d.ts +50 -50
- package/dist/services/orders/orders-input.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-input.schemas.js +12 -12
- package/dist/services/orders/orders-input.schemas.js.map +1 -1
- package/dist/services/orders/orders-modify.schemas.d.ts +18 -18
- package/dist/services/orders/orders-modify.schemas.js +1 -1
- package/dist/services/orders/orders-output.schemas.d.ts +6 -6
- package/dist/services/orders/orders-risk.schemas.d.ts +12 -12
- package/dist/services/orders/orders-risk.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-risk.schemas.js +8 -7
- package/dist/services/orders/orders-risk.schemas.js.map +1 -1
- package/dist/services/orders/orders.d.ts +4 -4
- package/dist/services/orders/orders.d.ts.map +1 -1
- package/dist/services/orders/orders.js +7 -7
- package/dist/services/orders/orders.js.map +1 -1
- package/dist/services/policies/api-key-policies/api-key-policies.schemas.d.ts +15 -15
- package/dist/services/policies/shared.d.ts.map +1 -1
- package/dist/services/policies/shared.js +2 -1
- package/dist/services/policies/shared.js.map +1 -1
- package/dist/services/policies/subaccount-policies/subaccount-policies.schemas.d.ts +9 -9
- package/dist/services/shared.js +4 -1
- package/dist/services/shared.js.map +1 -1
- package/dist/services/subaccounts/subaccounts.schemas.d.ts +1 -1
- package/dist/services/trades/trades.schemas.js +1 -1
- package/dist/services/trailing-oneof-inputs.js +1 -1
- package/dist/services/triggers/trigger-child-order.schemas.js +5 -3
- package/dist/services/triggers/trigger-child-order.schemas.js.map +1 -1
- package/dist/services/triggers/trigger-input.schemas.d.ts +36 -32
- package/dist/services/triggers/trigger-input.schemas.d.ts.map +1 -1
- package/dist/services/triggers/trigger-input.schemas.js +8 -8
- package/dist/services/triggers/trigger-input.schemas.js.map +1 -1
- package/dist/services/triggers/triggers-output.schemas.d.ts +17 -18
- package/dist/services/triggers/triggers-output.schemas.d.ts.map +1 -1
- package/dist/services/triggers/triggers-output.schemas.js +3 -3
- package/dist/services/triggers/triggers-output.schemas.js.map +1 -1
- package/dist/services/triggers/triggers.d.ts +2 -2
- package/dist/services/triggers/triggers.js +2 -2
- package/dist/services/triggers/triggers.js.map +1 -1
- package/dist/shared/decimal-surface.d.ts.map +1 -1
- package/dist/shared/decimal-surface.js +2 -2
- package/dist/shared/decimal-surface.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market-overview.schemas.js","names":["Proto.SparklineInterval"],"sources":["../../../src/services/market-overview/market-overview.schemas.ts"],"sourcesContent":["import * as Proto from \"../../gen/marketoverview/v1/marketoverview_pb.js\";\nimport * as v from \"valibot\";\nimport { tsNsToMs } from \"../../utils/time.js\";\nimport type { DecodedEnum } from \"../../utils/types.js\";\nimport { requiredEnumLabel } from \"../../shared/proto-enum-codec.js\";\nimport { scaledToDecimalOutput, type SdkScales } from \"../../shared/decimal-surface.js\";\nimport {\n SPARKLINE_INTERVAL_VALUES,\n MARKET_OVERVIEW_ORDER_BY_VALUES,\n MARKET_OVERVIEW_SORT_VALUES,\n SparklineIntervalCodec,\n MarketOverviewOrderByCodec,\n MarketOverviewSortCodec,\n} from \"./market-overview.codecs.js\";\n\nexport {\n SPARKLINE_INTERVAL_VALUES,\n MARKET_OVERVIEW_ORDER_BY_VALUES,\n MARKET_OVERVIEW_SORT_VALUES,\n} from \"./market-overview.codecs.js\";\n\nexport {\n MarketOrderBy,\n SortDirection,\n SparklineInterval,\n} from \"../../gen/marketoverview/v1/marketoverview_pb.js\";\n\nexport const SparklineIntervalSchema = v.picklist(SPARKLINE_INTERVAL_VALUES);\n\nexport type SparklineIntervalName = v.InferOutput<typeof SparklineIntervalSchema>;\n\nconst MarketOverviewSparklineRawSchema = v.object({\n interval: v.pipe(\n v.enum(Proto.SparklineInterval),\n v.transform((value) =>\n requiredEnumLabel(\n SparklineIntervalCodec.protoToOutput,\n value,\n \"MarketOverviewSparklineSchema\",\n \"interval\",\n ),\n ),\n ),\n closeTicks: v.array(v.bigint()),\n});\n\nexport type MarketOverviewSparkline = {\n interval: DecodedEnum<SparklineIntervalName>;\n close: string[];\n};\n\nexport const MarketOverviewOrderBySchema = v.picklist(MARKET_OVERVIEW_ORDER_BY_VALUES);\n\nexport type MarketOverviewOrderBy = v.InferOutput<typeof MarketOverviewOrderBySchema>;\n\nexport const MarketOverviewSortSchema = v.picklist(MARKET_OVERVIEW_SORT_VALUES);\n\nexport type MarketOverviewSort = v.InferOutput<typeof MarketOverviewSortSchema>;\n\nconst MarketOverviewRawSchema = v.object({\n symbolId:
|
|
1
|
+
{"version":3,"file":"market-overview.schemas.js","names":["Proto.SparklineInterval"],"sources":["../../../src/services/market-overview/market-overview.schemas.ts"],"sourcesContent":["import * as Proto from \"../../gen/marketoverview/v1/marketoverview_pb.js\";\nimport * as v from \"valibot\";\nimport { tsNsToMs } from \"../../utils/time.js\";\nimport type { DecodedEnum } from \"../../utils/types.js\";\nimport { requiredEnumLabel } from \"../../shared/proto-enum-codec.js\";\nimport { scaledToDecimalOutput, type SdkScales } from \"../../shared/decimal-surface.js\";\nimport { SymbolIdInputSchema } from \"../shared.js\";\nimport {\n SPARKLINE_INTERVAL_VALUES,\n MARKET_OVERVIEW_ORDER_BY_VALUES,\n MARKET_OVERVIEW_SORT_VALUES,\n SparklineIntervalCodec,\n MarketOverviewOrderByCodec,\n MarketOverviewSortCodec,\n} from \"./market-overview.codecs.js\";\n\nexport {\n SPARKLINE_INTERVAL_VALUES,\n MARKET_OVERVIEW_ORDER_BY_VALUES,\n MARKET_OVERVIEW_SORT_VALUES,\n} from \"./market-overview.codecs.js\";\n\nexport {\n MarketOrderBy,\n SortDirection,\n SparklineInterval,\n} from \"../../gen/marketoverview/v1/marketoverview_pb.js\";\n\nexport const SparklineIntervalSchema = v.picklist(SPARKLINE_INTERVAL_VALUES);\n\nexport type SparklineIntervalName = v.InferOutput<typeof SparklineIntervalSchema>;\n\nconst MarketOverviewSparklineRawSchema = v.object({\n interval: v.pipe(\n v.enum(Proto.SparklineInterval),\n v.transform((value) =>\n requiredEnumLabel(\n SparklineIntervalCodec.protoToOutput,\n value,\n \"MarketOverviewSparklineSchema\",\n \"interval\",\n ),\n ),\n ),\n closeTicks: v.array(v.bigint()),\n});\n\nexport type MarketOverviewSparkline = {\n interval: DecodedEnum<SparklineIntervalName>;\n close: string[];\n};\n\nexport const MarketOverviewOrderBySchema = v.picklist(MARKET_OVERVIEW_ORDER_BY_VALUES);\n\nexport type MarketOverviewOrderBy = v.InferOutput<typeof MarketOverviewOrderBySchema>;\n\nexport const MarketOverviewSortSchema = v.picklist(MARKET_OVERVIEW_SORT_VALUES);\n\nexport type MarketOverviewSort = v.InferOutput<typeof MarketOverviewSortSchema>;\n\nconst MarketOverviewRawSchema = v.object({\n symbolId: SymbolIdInputSchema,\n lastPriceTicks: v.bigint(),\n lastTradeTsNs: v.optional(v.bigint(), 0n),\n change24hBps: v.number(),\n high24hTicks: v.bigint(),\n low24hTicks: v.bigint(),\n volume24hBaseScaled: v.bigint(),\n volume24hQuoteScaled: v.bigint(),\n listedTsNs: v.optional(v.bigint(), 0n),\n bestBidTicks: v.bigint(),\n bestBidQtyScaled: v.bigint(),\n bestAskTicks: v.bigint(),\n bestAskQtyScaled: v.bigint(),\n sparklines: v.optional(v.array(MarketOverviewSparklineRawSchema), []),\n indexPriceTicks: v.bigint(),\n});\n\nexport function createMarketOverviewSchema(scales: SdkScales) {\n return v.pipe(\n MarketOverviewRawSchema,\n v.transform((m) => {\n const priceScale = scales.price();\n const baseQtyScale = scales.baseQty(m.symbolId);\n const quoteAmountScale = scales.quoteAmount(m.symbolId);\n return {\n symbolId: m.symbolId,\n lastPrice: scaledToDecimalOutput(m.lastPriceTicks, priceScale),\n lastTradeTsMs: tsNsToMs(m.lastTradeTsNs),\n change24hBps: m.change24hBps,\n high24h: scaledToDecimalOutput(m.high24hTicks, priceScale),\n low24h: scaledToDecimalOutput(m.low24hTicks, priceScale),\n volume24hBase: scaledToDecimalOutput(m.volume24hBaseScaled, baseQtyScale),\n volume24hQuote: scaledToDecimalOutput(m.volume24hQuoteScaled, quoteAmountScale),\n listedTsMs: tsNsToMs(m.listedTsNs),\n bestBid: scaledToDecimalOutput(m.bestBidTicks, priceScale),\n bestBidQty: scaledToDecimalOutput(m.bestBidQtyScaled, baseQtyScale),\n bestAsk: scaledToDecimalOutput(m.bestAskTicks, priceScale),\n bestAskQty: scaledToDecimalOutput(m.bestAskQtyScaled, baseQtyScale),\n indexPrice:\n m.indexPriceTicks > 0n\n ? scaledToDecimalOutput(m.indexPriceTicks, priceScale)\n : undefined,\n sparklines: (m.sparklines ?? []).map(\n (s): MarketOverviewSparkline => ({\n interval: s.interval,\n close: s.closeTicks\n .map((tick) => scaledToDecimalOutput(tick, priceScale))\n .reverse(),\n }),\n ),\n };\n }),\n );\n}\n\nexport type MarketOverview = v.InferOutput<ReturnType<typeof createMarketOverviewSchema>>;\n\nconst MS_PER_24H = 86_400_000;\n\nfunction change24hBpsFromSparklineFirstLast(sparklines: MarketOverview[\"sparklines\"]): number {\n const s = sparklines.find((e) => e.interval === \"24h\") ?? sparklines[0];\n if (!s || s.close.length < 2) return 0;\n const first = Number(s.close[0] ?? 0);\n const last = Number(s.close.at(-1) ?? 0);\n if (!Number.isFinite(first) || !Number.isFinite(last)) return 0;\n if (first === 0) return 0;\n return Math.round(((last - first) / first) * 10_000);\n}\n\n/**\n * Formats the 24-hour market change percentage for display.\n */\nexport function getMarketOverview24hChangeDisplay(\n market: Pick<MarketOverview, \"change24hBps\" | \"listedTsMs\" | \"sparklines\">,\n nowMs: number = Date.now(),\n): { change24hBps: number; showNewListingSparklineInfo: boolean } {\n const api = market.change24hBps;\n const newish = api === 0 && market.listedTsMs > 0 && nowMs - market.listedTsMs < MS_PER_24H;\n if (!newish) {\n return { change24hBps: api, showNewListingSparklineInfo: false };\n }\n return {\n change24hBps: change24hBpsFromSparklineFirstLast(market.sparklines),\n showNewListingSparklineInfo: true,\n };\n}\n\nexport type MarketOverviewBatch = {\n markets: MarketOverview[];\n tsNs: bigint;\n};\n\nexport const ListMarketOverviewInputSchema = v.pipe(\n v.strictObject({\n symbolIds: v.optional(v.array(SymbolIdInputSchema), []),\n limit: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 500),\n pageToken: v.optional(v.pipe(v.string(), v.trim()), \"\"),\n orderBy: v.pipe(\n v.optional(MarketOverviewOrderBySchema, \"volume_24h_quote\"),\n v.transform((v) => MarketOverviewOrderByCodec.inputToProto[v ?? \"volume_24h_quote\"]),\n ),\n sort: v.pipe(\n v.optional(MarketOverviewSortSchema, \"desc\"),\n v.transform((v) => MarketOverviewSortCodec.inputToProto[v ?? \"desc\"]),\n ),\n includeSparklines: v.optional(v.boolean(), true),\n sparklineIntervals: v.pipe(\n v.optional(v.array(SparklineIntervalSchema), [\"24h\"]),\n v.transform((intervals) =>\n (intervals ?? [\"24h\"]).map((v) => SparklineIntervalCodec.inputToProto[v]),\n ),\n ),\n }),\n v.transform(({ symbolIds, ...input }) => ({ symbolId: symbolIds, ...input })),\n);\n\nexport type ListMarketOverviewInput = v.InferInput<typeof ListMarketOverviewInputSchema>;\n"],"mappings":"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"}
|
|
@@ -7,7 +7,6 @@ import { Transport } from "@connectrpc/connect";
|
|
|
7
7
|
import * as v from "valibot";
|
|
8
8
|
//#region src/services/orderbook/orderbook.d.ts
|
|
9
9
|
interface SubscribeOrderbookInput extends BaseSubscribeInput<OrderbookData> {
|
|
10
|
-
symbol: string;
|
|
11
10
|
symbolId: number;
|
|
12
11
|
depth?: number;
|
|
13
12
|
bucket?: string | null;
|
|
@@ -17,7 +16,7 @@ interface OrderbookSubscription {
|
|
|
17
16
|
unsubscribe: () => void;
|
|
18
17
|
setBucket: (bucket: string | null | undefined) => void;
|
|
19
18
|
}
|
|
20
|
-
interface CreateOrderbookSubscriptionInput extends OrderbookStreamHandlers, Pick<SubscribeOrderbookInput, "
|
|
19
|
+
interface CreateOrderbookSubscriptionInput extends OrderbookStreamHandlers, Pick<SubscribeOrderbookInput, "symbolId" | "depth" | "bucket"> {}
|
|
21
20
|
/**
|
|
22
21
|
* Reads spot order book snapshots and maintains realtime local order book state from public delta channels.
|
|
23
22
|
*/
|
|
@@ -25,11 +24,11 @@ declare class OrderbookService {
|
|
|
25
24
|
#private;
|
|
26
25
|
constructor(transport: Transport, realtime: PolyesterRealtime, scales: SdkScales);
|
|
27
26
|
/**
|
|
28
|
-
* Fetches a spot order book depth snapshot for a symbol and requested depth, returning best bids and asks with the backend book sequence.
|
|
27
|
+
* Fetches a spot order book depth snapshot for a symbol ID and requested depth, returning best bids and asks with the backend book sequence.
|
|
29
28
|
*/
|
|
30
29
|
get(input: v.InferInput<typeof GetOrderbookInputSchema>, options?: PolyesterRequestOptions): Promise<OrderbookData>;
|
|
31
30
|
/**
|
|
32
|
-
* Subscribes to the managed order book stream for a symbol and forwards reconstructed snapshots to onEvent. This is a convenience wrapper around createSubscription().unsubscribe.
|
|
31
|
+
* Subscribes to the managed order book stream for a symbol ID and forwards reconstructed snapshots to onEvent. This is a convenience wrapper around createSubscription().unsubscribe.
|
|
33
32
|
*/
|
|
34
33
|
subscribe(input: SubscribeOrderbookInput): () => void;
|
|
35
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orderbook.d.ts","names":[],"sources":["../../../src/services/orderbook/orderbook.ts"],"mappings":";;;;;;;;UAgCU,gCAAgC,mBAAmB;EACzD;EACA;EACA
|
|
1
|
+
{"version":3,"file":"orderbook.d.ts","names":[],"sources":["../../../src/services/orderbook/orderbook.ts"],"mappings":";;;;;;;;UAgCU,gCAAgC,mBAAmB;EACzD;EACA;EACA;;UAGa,gCAAgC,mBAAmB;UAEnD;EACb;EACA,YAAY;;UAGC,yCAET,yBACA,KAAK;;;;cAOA;;EAKG,YAAA,WAAW,WAAW,UAAU,mBAAmB,QAAQ;;;;EASjE,IACF,OAAO,EAAE,kBAAkB,0BAC3B,UAAU,0BACX,QAAQ;;;;EAmBX,UAAU,OAAO;;;;;;;;EAWjB,mBAAmB,OAAO,mCAAmC"}
|
|
@@ -10,7 +10,6 @@ import { GetOrderbookInputSchema, createOrderbookDataSchema, formatOrderbookLeve
|
|
|
10
10
|
import { toBig } from "../../utils/u128.js";
|
|
11
11
|
import { create } from "@bufbuild/protobuf";
|
|
12
12
|
import { createClient } from "@connectrpc/connect";
|
|
13
|
-
import * as v from "valibot";
|
|
14
13
|
//#region src/services/orderbook/orderbook.ts
|
|
15
14
|
/**
|
|
16
15
|
* Reads spot order book snapshots and maintains realtime local order book state from public delta channels.
|
|
@@ -25,17 +24,17 @@ var OrderbookService = class {
|
|
|
25
24
|
this.#scales = scales;
|
|
26
25
|
}
|
|
27
26
|
/**
|
|
28
|
-
* Fetches a spot order book depth snapshot for a symbol and requested depth, returning best bids and asks with the backend book sequence.
|
|
27
|
+
* Fetches a spot order book depth snapshot for a symbol ID and requested depth, returning best bids and asks with the backend book sequence.
|
|
29
28
|
*/
|
|
30
29
|
async get(input, options) {
|
|
31
30
|
const validated = parse(GetOrderbookInputSchema, input);
|
|
32
31
|
await this.#scales.ready();
|
|
33
32
|
const res = await this.#client.getOrderBook({
|
|
34
|
-
|
|
33
|
+
symbolId: validated.symbolId,
|
|
35
34
|
depth: validated.protoDepth
|
|
36
35
|
}, toConnectCallOptions(options));
|
|
37
|
-
return parse(createOrderbookDataSchema(this.#scales, validated.
|
|
38
|
-
|
|
36
|
+
return parse(createOrderbookDataSchema(this.#scales, validated.symbolId), {
|
|
37
|
+
symbolId: res.symbolId,
|
|
39
38
|
depth: validated.depth,
|
|
40
39
|
bookSeq: res.bookSeq,
|
|
41
40
|
bids: res.bids,
|
|
@@ -43,7 +42,7 @@ var OrderbookService = class {
|
|
|
43
42
|
});
|
|
44
43
|
}
|
|
45
44
|
/**
|
|
46
|
-
* Subscribes to the managed order book stream for a symbol and forwards reconstructed snapshots to onEvent. This is a convenience wrapper around createSubscription().unsubscribe.
|
|
45
|
+
* Subscribes to the managed order book stream for a symbol ID and forwards reconstructed snapshots to onEvent. This is a convenience wrapper around createSubscription().unsubscribe.
|
|
47
46
|
*/
|
|
48
47
|
subscribe(input) {
|
|
49
48
|
return this.createSubscription(input).unsubscribe;
|
|
@@ -56,7 +55,10 @@ var OrderbookService = class {
|
|
|
56
55
|
* Refetching is driven by observed sequence gaps and reconnect events only. A feed that stays subscribed but stops publishing is indistinguishable from a quiet market, so it does not trigger onError or a refetch. Callers that must detect a stalled book need their own idle watchdog plus a REST refetch.
|
|
57
56
|
*/
|
|
58
57
|
createSubscription(input) {
|
|
59
|
-
const symbolId = parse(
|
|
58
|
+
const { symbolId } = parse(GetOrderbookInputSchema, {
|
|
59
|
+
symbolId: input.symbolId,
|
|
60
|
+
depth: input.depth
|
|
61
|
+
});
|
|
60
62
|
const requestedDepth = Math.min(500, Math.max(1, Math.trunc(input.depth ?? 50)));
|
|
61
63
|
const channelDepth = orderbookWsChannelDepth(requestedDepth);
|
|
62
64
|
const channel = `public:spot:orderbook:deltas:depth:${channelDepth}:${symbolId}:proto`;
|
|
@@ -104,7 +106,7 @@ var OrderbookService = class {
|
|
|
104
106
|
function emit() {
|
|
105
107
|
gate.run(() => {
|
|
106
108
|
input.onEvent({
|
|
107
|
-
|
|
109
|
+
symbolId,
|
|
108
110
|
depth: requestedDepth,
|
|
109
111
|
bookSeq: currentBookSeq.toString(),
|
|
110
112
|
bids: sideToUIBucketed(bidsMap, "bids", requestedDepth, bucketTicks),
|
|
@@ -123,17 +125,18 @@ var OrderbookService = class {
|
|
|
123
125
|
}
|
|
124
126
|
async function inputServiceFetch() {
|
|
125
127
|
const validated = parse(GetOrderbookInputSchema, {
|
|
126
|
-
|
|
128
|
+
symbolId,
|
|
127
129
|
depth: channelDepth
|
|
128
130
|
});
|
|
129
131
|
try {
|
|
130
132
|
return await client.getOrderBook({
|
|
131
|
-
|
|
133
|
+
symbolId: validated.symbolId,
|
|
132
134
|
depth: validated.protoDepth
|
|
133
135
|
});
|
|
134
136
|
} catch (error) {
|
|
135
137
|
if (!isResourceNotFoundError(error)) throw error;
|
|
136
138
|
return create(GetOrderBookResponseSchema, {
|
|
139
|
+
symbolId,
|
|
137
140
|
bookSeq: 0n,
|
|
138
141
|
bids: [],
|
|
139
142
|
asks: []
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orderbook.js","names":["#client","Proto.OrderbookService","#realtime","#scales","Proto.GetOrderBookResponseSchema","Proto.OrderBookDeltaSchema"],"sources":["../../../src/services/orderbook/orderbook.ts"],"sourcesContent":["import { create } from \"@bufbuild/protobuf\";\nimport * as Proto from \"../../gen/orderbook/v1/orderbook_pb.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport { publicationHandlerErrorContext } from \"../../shared/subscription-errors.js\";\nimport type { PolyesterRealtime } from \"../../realtime/types.js\";\nimport {\n snapshotThenStream,\n type SnapshotThenStreamSubscription,\n} from \"../../realtime/snapshot-then-stream.js\";\nimport type { BaseSubscribeInput } from \"../../shared/types.js\";\nimport {\n toConnectCallOptions,\n type PolyesterRequestOptions,\n} from \"../../shared/request-options.js\";\nimport {\n createReadyGate,\n decimalInputToScaled,\n type SdkScales,\n} from \"../../shared/decimal-surface.js\";\nimport {\n formatOrderbookLevel,\n GetOrderbookInputSchema,\n createOrderbookDataSchema,\n type OrderbookLevel,\n type OrderbookData,\n} from \"./orderbook.schemas.js\";\nimport { orderbookWsChannelDepth } from \"./orderbook.codecs.js\";\nimport { toBig } from \"../../utils/u128.js\";\nimport { isResourceNotFoundError } from \"../../utils/errors.js\";\nimport * as v from \"valibot\";\nimport { parse } from \"../../shared/validation.js\";\n\ninterface SubscribeOrderbookInput extends BaseSubscribeInput<OrderbookData> {\n symbol: string;\n symbolId: number;\n depth?: number;\n bucket?: string | null;\n}\n\nexport interface OrderbookStreamHandlers extends BaseSubscribeInput<OrderbookData> {}\n\nexport interface OrderbookSubscription {\n unsubscribe: () => void;\n setBucket: (bucket: string | null | undefined) => void;\n}\n\nexport interface CreateOrderbookSubscriptionInput\n extends\n OrderbookStreamHandlers,\n Pick<SubscribeOrderbookInput, \"symbol\" | \"symbolId\" | \"depth\" | \"bucket\"> {}\n\ntype BookSide = Map<bigint, bigint>;\n\n/**\n * Reads spot order book snapshots and maintains realtime local order book state from public delta channels.\n */\nexport class OrderbookService {\n #client: Client<typeof Proto.OrderbookService>;\n #realtime: PolyesterRealtime;\n #scales: SdkScales;\n\n constructor(transport: Transport, realtime: PolyesterRealtime, scales: SdkScales) {\n this.#client = createClient(Proto.OrderbookService, transport);\n this.#realtime = realtime;\n this.#scales = scales;\n }\n\n /**\n * Fetches a spot order book depth snapshot for a symbol and requested depth, returning best bids and asks with the backend book sequence.\n */\n async get(\n input: v.InferInput<typeof GetOrderbookInputSchema>,\n options?: PolyesterRequestOptions,\n ): Promise<OrderbookData> {\n const validated = parse(GetOrderbookInputSchema, input);\n await this.#scales.ready();\n const res = await this.#client.getOrderBook(\n { symbol: validated.symbol, depth: validated.protoDepth },\n toConnectCallOptions(options),\n );\n return parse(createOrderbookDataSchema(this.#scales, validated.symbol), {\n symbol: validated.symbol,\n depth: validated.depth,\n bookSeq: res.bookSeq,\n bids: res.bids,\n asks: res.asks,\n });\n }\n\n /**\n * Subscribes to the managed order book stream for a symbol and forwards reconstructed snapshots to onEvent. This is a convenience wrapper around createSubscription().unsubscribe.\n */\n subscribe(input: SubscribeOrderbookInput): () => void {\n return this.createSubscription(input).unsubscribe;\n }\n\n /**\n * Creates a stateful order book subscription that first fetches a snapshot, buffers proto deltas from public:spot:orderbook:deltas:depth:{depth}:{symbolId}:proto, applies sequence-checked updates, and refetches on observed sequence gaps or reconnects. The returned handle can unsubscribe or change local price bucket aggregation without reconnecting.\n *\n * `depth` is clamped to [1, 500] and rides the smallest published channel depth that covers it (see ORDERBOOK_WS_DEPTHS); levels are sliced back to the requested depth locally.\n *\n * Refetching is driven by observed sequence gaps and reconnect events only. A feed that stays subscribed but stops publishing is indistinguishable from a quiet market, so it does not trigger onError or a refetch. Callers that must detect a stalled book need their own idle watchdog plus a REST refetch.\n */\n createSubscription(input: CreateOrderbookSubscriptionInput): OrderbookSubscription {\n const symbolId = parse(v.pipe(v.number(), v.integer(), v.gtValue(0)), input.symbolId);\n const requestedDepth = Math.min(500, Math.max(1, Math.trunc(input.depth ?? 50)));\n const channelDepth = orderbookWsChannelDepth(requestedDepth);\n const channel = `public:spot:orderbook:deltas:depth:${channelDepth}:${symbolId}:proto`;\n\n const client = this.#client;\n const scales = this.#scales;\n const gate = createReadyGate(\n () => scales.ready(),\n (error) => input.onError?.(publicationHandlerErrorContext(channel, error)),\n );\n\n let bidsMap: BookSide = new Map();\n let asksMap: BookSide = new Map();\n let currentBookSeq = 0n;\n let bucketTicks: bigint | null = null;\n let stream: SnapshotThenStreamSubscription | undefined;\n\n function levelsToMap(levels: Proto.PriceLevel[] | undefined): BookSide {\n const map: BookSide = new Map();\n for (const l of levels ?? []) {\n if (l.qtyScaled === 0n) continue;\n map.set(l.priceTicks, l.qtyScaled);\n }\n return map;\n }\n\n function applySideDelta(map: BookSide, levels: Proto.PriceLevel[] | undefined): void {\n for (const l of levels ?? []) {\n if (l.qtyScaled === 0n) map.delete(l.priceTicks);\n else map.set(l.priceTicks, l.qtyScaled);\n }\n }\n\n function sideToUI(map: BookSide, side: \"bids\" | \"asks\", limit: number): OrderbookLevel[] {\n const entries = Array.from(map.entries());\n entries.sort(([pa], [pb]) => {\n if (pa === pb) return 0;\n return side === \"bids\" ? (pa > pb ? -1 : 1) : pa < pb ? -1 : 1;\n });\n return entries\n .slice(0, limit)\n .map(([priceTicks, qtyScaled]) =>\n formatOrderbookLevel({ priceTicks, qtyScaled }, scales, symbolId),\n );\n }\n\n function sideToUIBucketed(\n map: BookSide,\n side: \"bids\" | \"asks\",\n limit: number,\n bucket: bigint | null,\n ): OrderbookLevel[] {\n if (!bucket || bucket <= 0n) return sideToUI(map, side, limit);\n\n const agg: BookSide = new Map();\n for (const [priceTicks, qtyScaled] of map.entries()) {\n if (qtyScaled <= 0n) continue;\n const bucketPrice = (priceTicks / bucket) * bucket;\n agg.set(bucketPrice, (agg.get(bucketPrice) ?? 0n) + qtyScaled);\n }\n return sideToUI(agg, side, limit);\n }\n\n function emit(): void {\n gate.run(() => {\n input.onEvent({\n symbol: input.symbol,\n depth: requestedDepth,\n bookSeq: currentBookSeq.toString(),\n bids: sideToUIBucketed(bidsMap, \"bids\", requestedDepth, bucketTicks),\n asks: sideToUIBucketed(asksMap, \"asks\", requestedDepth, bucketTicks),\n });\n });\n }\n\n function setBucket(bucket: string | null | undefined): void {\n if (!bucket) {\n bucketTicks = null;\n } else {\n try {\n bucketTicks = decimalInputToScaled(\"bucket\", bucket, scales.price());\n } catch {\n bucketTicks = null;\n }\n }\n if (stream?.isReady()) emit();\n }\n\n async function inputServiceFetch(): Promise<Proto.GetOrderBookResponse> {\n const validated = parse(GetOrderbookInputSchema, {\n symbol: input.symbol,\n depth: channelDepth,\n });\n try {\n return await client.getOrderBook({\n symbol: validated.symbol,\n depth: validated.protoDepth,\n });\n } catch (error: unknown) {\n if (!isResourceNotFoundError(error)) throw error;\n\n return create(Proto.GetOrderBookResponseSchema, {\n bookSeq: 0n,\n bids: [],\n asks: [],\n });\n }\n }\n\n function handleDelta(delta: Proto.OrderBookDelta): void {\n if (delta.reset) {\n bidsMap.clear();\n asksMap.clear();\n currentBookSeq = 0n;\n }\n\n if (currentBookSeq !== 0n && delta.bookSeqStart > currentBookSeq + 1n) {\n stream?.refreshSnapshot();\n return;\n }\n\n if (delta.bookSeqEnd <= currentBookSeq) return;\n\n applySideDelta(bidsMap, delta.bids);\n applySideDelta(asksMap, delta.asks);\n\n currentBookSeq = delta.bookSeqEnd > currentBookSeq ? delta.bookSeqEnd : currentBookSeq;\n emit();\n }\n\n setBucket(input.bucket);\n stream = snapshotThenStream({\n realtime: this.#realtime,\n channel,\n schema: Proto.OrderBookDeltaSchema,\n maxBufferedPublications: 200,\n snapshotErrorLog: \"Failed to fetch orderbook\",\n fetchSnapshot: inputServiceFetch,\n readPublication: (delta) => [delta],\n applySnapshot: (snapshot, bufferedDeltas) => {\n bidsMap = levelsToMap(snapshot.bids);\n asksMap = levelsToMap(snapshot.asks);\n currentBookSeq = toBig(snapshot.bookSeq);\n emit();\n for (const delta of bufferedDeltas) {\n if (stream?.isDisposed()) return;\n handleDelta(delta);\n }\n },\n applyLivePublications: (deltas) => {\n for (const delta of deltas) {\n if (stream?.isDisposed()) return;\n handleDelta(delta);\n }\n },\n onOpen: input.onOpen,\n onClose: input.onClose,\n onError: input.onError,\n });\n\n function dispose(): void {\n stream?.unsubscribe();\n }\n\n return { unsubscribe: dispose, setBucket };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"orderbook.js","names":["#client","Proto.OrderbookService","#realtime","#scales","Proto.GetOrderBookResponseSchema","Proto.OrderBookDeltaSchema"],"sources":["../../../src/services/orderbook/orderbook.ts"],"sourcesContent":["import { create } from \"@bufbuild/protobuf\";\nimport * as Proto from \"../../gen/orderbook/v1/orderbook_pb.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport { publicationHandlerErrorContext } from \"../../shared/subscription-errors.js\";\nimport type { PolyesterRealtime } from \"../../realtime/types.js\";\nimport {\n snapshotThenStream,\n type SnapshotThenStreamSubscription,\n} from \"../../realtime/snapshot-then-stream.js\";\nimport type { BaseSubscribeInput } from \"../../shared/types.js\";\nimport {\n toConnectCallOptions,\n type PolyesterRequestOptions,\n} from \"../../shared/request-options.js\";\nimport {\n createReadyGate,\n decimalInputToScaled,\n type SdkScales,\n} from \"../../shared/decimal-surface.js\";\nimport {\n formatOrderbookLevel,\n GetOrderbookInputSchema,\n createOrderbookDataSchema,\n type OrderbookLevel,\n type OrderbookData,\n} from \"./orderbook.schemas.js\";\nimport { orderbookWsChannelDepth } from \"./orderbook.codecs.js\";\nimport { toBig } from \"../../utils/u128.js\";\nimport { isResourceNotFoundError } from \"../../utils/errors.js\";\nimport type * as v from \"valibot\";\nimport { parse } from \"../../shared/validation.js\";\n\ninterface SubscribeOrderbookInput extends BaseSubscribeInput<OrderbookData> {\n symbolId: number;\n depth?: number;\n bucket?: string | null;\n}\n\nexport interface OrderbookStreamHandlers extends BaseSubscribeInput<OrderbookData> {}\n\nexport interface OrderbookSubscription {\n unsubscribe: () => void;\n setBucket: (bucket: string | null | undefined) => void;\n}\n\nexport interface CreateOrderbookSubscriptionInput\n extends\n OrderbookStreamHandlers,\n Pick<SubscribeOrderbookInput, \"symbolId\" | \"depth\" | \"bucket\"> {}\n\ntype BookSide = Map<bigint, bigint>;\n\n/**\n * Reads spot order book snapshots and maintains realtime local order book state from public delta channels.\n */\nexport class OrderbookService {\n #client: Client<typeof Proto.OrderbookService>;\n #realtime: PolyesterRealtime;\n #scales: SdkScales;\n\n constructor(transport: Transport, realtime: PolyesterRealtime, scales: SdkScales) {\n this.#client = createClient(Proto.OrderbookService, transport);\n this.#realtime = realtime;\n this.#scales = scales;\n }\n\n /**\n * Fetches a spot order book depth snapshot for a symbol ID and requested depth, returning best bids and asks with the backend book sequence.\n */\n async get(\n input: v.InferInput<typeof GetOrderbookInputSchema>,\n options?: PolyesterRequestOptions,\n ): Promise<OrderbookData> {\n const validated = parse(GetOrderbookInputSchema, input);\n await this.#scales.ready();\n const res = await this.#client.getOrderBook(\n { symbolId: validated.symbolId, depth: validated.protoDepth },\n toConnectCallOptions(options),\n );\n return parse(createOrderbookDataSchema(this.#scales, validated.symbolId), {\n symbolId: res.symbolId,\n depth: validated.depth,\n bookSeq: res.bookSeq,\n bids: res.bids,\n asks: res.asks,\n });\n }\n\n /**\n * Subscribes to the managed order book stream for a symbol ID and forwards reconstructed snapshots to onEvent. This is a convenience wrapper around createSubscription().unsubscribe.\n */\n subscribe(input: SubscribeOrderbookInput): () => void {\n return this.createSubscription(input).unsubscribe;\n }\n\n /**\n * Creates a stateful order book subscription that first fetches a snapshot, buffers proto deltas from public:spot:orderbook:deltas:depth:{depth}:{symbolId}:proto, applies sequence-checked updates, and refetches on observed sequence gaps or reconnects. The returned handle can unsubscribe or change local price bucket aggregation without reconnecting.\n *\n * `depth` is clamped to [1, 500] and rides the smallest published channel depth that covers it (see ORDERBOOK_WS_DEPTHS); levels are sliced back to the requested depth locally.\n *\n * Refetching is driven by observed sequence gaps and reconnect events only. A feed that stays subscribed but stops publishing is indistinguishable from a quiet market, so it does not trigger onError or a refetch. Callers that must detect a stalled book need their own idle watchdog plus a REST refetch.\n */\n createSubscription(input: CreateOrderbookSubscriptionInput): OrderbookSubscription {\n const { symbolId } = parse(GetOrderbookInputSchema, {\n symbolId: input.symbolId,\n depth: input.depth,\n });\n const requestedDepth = Math.min(500, Math.max(1, Math.trunc(input.depth ?? 50)));\n const channelDepth = orderbookWsChannelDepth(requestedDepth);\n const channel = `public:spot:orderbook:deltas:depth:${channelDepth}:${symbolId}:proto`;\n\n const client = this.#client;\n const scales = this.#scales;\n const gate = createReadyGate(\n () => scales.ready(),\n (error) => input.onError?.(publicationHandlerErrorContext(channel, error)),\n );\n\n let bidsMap: BookSide = new Map();\n let asksMap: BookSide = new Map();\n let currentBookSeq = 0n;\n let bucketTicks: bigint | null = null;\n let stream: SnapshotThenStreamSubscription | undefined;\n\n function levelsToMap(levels: Proto.PriceLevel[] | undefined): BookSide {\n const map: BookSide = new Map();\n for (const l of levels ?? []) {\n if (l.qtyScaled === 0n) continue;\n map.set(l.priceTicks, l.qtyScaled);\n }\n return map;\n }\n\n function applySideDelta(map: BookSide, levels: Proto.PriceLevel[] | undefined): void {\n for (const l of levels ?? []) {\n if (l.qtyScaled === 0n) map.delete(l.priceTicks);\n else map.set(l.priceTicks, l.qtyScaled);\n }\n }\n\n function sideToUI(map: BookSide, side: \"bids\" | \"asks\", limit: number): OrderbookLevel[] {\n const entries = Array.from(map.entries());\n entries.sort(([pa], [pb]) => {\n if (pa === pb) return 0;\n return side === \"bids\" ? (pa > pb ? -1 : 1) : pa < pb ? -1 : 1;\n });\n return entries\n .slice(0, limit)\n .map(([priceTicks, qtyScaled]) =>\n formatOrderbookLevel({ priceTicks, qtyScaled }, scales, symbolId),\n );\n }\n\n function sideToUIBucketed(\n map: BookSide,\n side: \"bids\" | \"asks\",\n limit: number,\n bucket: bigint | null,\n ): OrderbookLevel[] {\n if (!bucket || bucket <= 0n) return sideToUI(map, side, limit);\n\n const agg: BookSide = new Map();\n for (const [priceTicks, qtyScaled] of map.entries()) {\n if (qtyScaled <= 0n) continue;\n const bucketPrice = (priceTicks / bucket) * bucket;\n agg.set(bucketPrice, (agg.get(bucketPrice) ?? 0n) + qtyScaled);\n }\n return sideToUI(agg, side, limit);\n }\n\n function emit(): void {\n gate.run(() => {\n input.onEvent({\n symbolId,\n depth: requestedDepth,\n bookSeq: currentBookSeq.toString(),\n bids: sideToUIBucketed(bidsMap, \"bids\", requestedDepth, bucketTicks),\n asks: sideToUIBucketed(asksMap, \"asks\", requestedDepth, bucketTicks),\n });\n });\n }\n\n function setBucket(bucket: string | null | undefined): void {\n if (!bucket) {\n bucketTicks = null;\n } else {\n try {\n bucketTicks = decimalInputToScaled(\"bucket\", bucket, scales.price());\n } catch {\n bucketTicks = null;\n }\n }\n if (stream?.isReady()) emit();\n }\n\n async function inputServiceFetch(): Promise<Proto.GetOrderBookResponse> {\n const validated = parse(GetOrderbookInputSchema, {\n symbolId,\n depth: channelDepth,\n });\n try {\n return await client.getOrderBook({\n symbolId: validated.symbolId,\n depth: validated.protoDepth,\n });\n } catch (error: unknown) {\n if (!isResourceNotFoundError(error)) throw error;\n\n return create(Proto.GetOrderBookResponseSchema, {\n symbolId,\n bookSeq: 0n,\n bids: [],\n asks: [],\n });\n }\n }\n\n function handleDelta(delta: Proto.OrderBookDelta): void {\n if (delta.reset) {\n bidsMap.clear();\n asksMap.clear();\n currentBookSeq = 0n;\n }\n\n if (currentBookSeq !== 0n && delta.bookSeqStart > currentBookSeq + 1n) {\n stream?.refreshSnapshot();\n return;\n }\n\n if (delta.bookSeqEnd <= currentBookSeq) return;\n\n applySideDelta(bidsMap, delta.bids);\n applySideDelta(asksMap, delta.asks);\n\n currentBookSeq = delta.bookSeqEnd > currentBookSeq ? delta.bookSeqEnd : currentBookSeq;\n emit();\n }\n\n setBucket(input.bucket);\n stream = snapshotThenStream({\n realtime: this.#realtime,\n channel,\n schema: Proto.OrderBookDeltaSchema,\n maxBufferedPublications: 200,\n snapshotErrorLog: \"Failed to fetch orderbook\",\n fetchSnapshot: inputServiceFetch,\n readPublication: (delta) => [delta],\n applySnapshot: (snapshot, bufferedDeltas) => {\n bidsMap = levelsToMap(snapshot.bids);\n asksMap = levelsToMap(snapshot.asks);\n currentBookSeq = toBig(snapshot.bookSeq);\n emit();\n for (const delta of bufferedDeltas) {\n if (stream?.isDisposed()) return;\n handleDelta(delta);\n }\n },\n applyLivePublications: (deltas) => {\n for (const delta of deltas) {\n if (stream?.isDisposed()) return;\n handleDelta(delta);\n }\n },\n onOpen: input.onOpen,\n onClose: input.onClose,\n onError: input.onError,\n });\n\n function dispose(): void {\n stream?.unsubscribe();\n }\n\n return { unsubscribe: dispose, setBucket };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { PairCatalogKey } from "../../catalogs/types.js";
|
|
2
1
|
import { Depth } from "../../gen/orderbook/v1/orderbook_pb.js";
|
|
3
2
|
import { SdkScales } from "../../shared/decimal-surface.js";
|
|
4
3
|
import * as v from "valibot";
|
|
5
4
|
//#region src/services/orderbook/orderbook.schemas.d.ts
|
|
6
5
|
declare const GetOrderbookInputSchema: v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
7
|
-
readonly
|
|
6
|
+
readonly symbolId: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.GtValueAction<number, 0, undefined>, v.MaxValueAction<number, 4294967295, undefined>]>;
|
|
8
7
|
readonly depth: v.OptionalSchema<v.NumberSchema<undefined>, 50>;
|
|
9
8
|
}, undefined>, v.TransformAction<{
|
|
10
|
-
|
|
9
|
+
symbolId: number;
|
|
11
10
|
depth: number;
|
|
12
11
|
}, {
|
|
13
|
-
|
|
12
|
+
symbolId: number;
|
|
14
13
|
depth: 5 | 10 | 20 | 1 | 200 | 1000 | 500 | 100 | 50;
|
|
15
14
|
protoDepth: Depth;
|
|
16
15
|
}>]>;
|
|
@@ -20,13 +19,13 @@ declare const OrderbookLevelInputSchema: v.ObjectSchema<{
|
|
|
20
19
|
readonly qtyScaled: v.BigintSchema<undefined>;
|
|
21
20
|
}, undefined>;
|
|
22
21
|
type OrderbookLevelInput = v.InferOutput<typeof OrderbookLevelInputSchema>;
|
|
23
|
-
declare function formatOrderbookLevel(level: OrderbookLevelInput, scales: SdkScales,
|
|
22
|
+
declare function formatOrderbookLevel(level: OrderbookLevelInput, scales: SdkScales, symbolId: number): {
|
|
24
23
|
price: string;
|
|
25
24
|
qty: string;
|
|
26
25
|
};
|
|
27
26
|
type OrderbookLevel = ReturnType<typeof formatOrderbookLevel>;
|
|
28
|
-
declare function createOrderbookDataSchema(scales: SdkScales,
|
|
29
|
-
readonly
|
|
27
|
+
declare function createOrderbookDataSchema(scales: SdkScales, symbolId: number): v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
28
|
+
readonly symbolId: v.LiteralSchema<number, undefined>;
|
|
30
29
|
readonly depth: v.NumberSchema<undefined>;
|
|
31
30
|
readonly bookSeq: v.BigintSchema<undefined>;
|
|
32
31
|
readonly bids: v.ArraySchema<v.ObjectSchema<{
|
|
@@ -38,7 +37,7 @@ declare function createOrderbookDataSchema(scales: SdkScales, pair: PairCatalogK
|
|
|
38
37
|
readonly qtyScaled: v.BigintSchema<undefined>;
|
|
39
38
|
}, undefined>, undefined>;
|
|
40
39
|
}, undefined>, v.TransformAction<{
|
|
41
|
-
|
|
40
|
+
symbolId: number;
|
|
42
41
|
depth: number;
|
|
43
42
|
bookSeq: bigint;
|
|
44
43
|
bids: {
|
|
@@ -59,7 +58,7 @@ declare function createOrderbookDataSchema(scales: SdkScales, pair: PairCatalogK
|
|
|
59
58
|
price: string;
|
|
60
59
|
qty: string;
|
|
61
60
|
}[];
|
|
62
|
-
|
|
61
|
+
symbolId: number;
|
|
63
62
|
depth: number;
|
|
64
63
|
}>]>;
|
|
65
64
|
type OrderbookData = v.InferOutput<ReturnType<typeof createOrderbookDataSchema>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orderbook.schemas.d.ts","names":[],"sources":["../../../src/services/orderbook/orderbook.schemas.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"orderbook.schemas.d.ts","names":[],"sources":["../../../src/services/orderbook/orderbook.schemas.ts"],"mappings":";;;;cAKa,yBAAuB,EAAA,yBAAA,EAAA;;;;;;;;;cAAA;;KAexB,oBAAoB,EAAE,kBAAkB;cAE9C,2BAAyB,EAAA;;;;KAKnB,sBAAsB,EAAE,mBAAmB;iBAEvC,qBACZ,OAAO,qBACP,QAAQ,WACR;;;;KAQQ,iBAAiB,kBAAkB;iBAE/B,0BAA0B,QAAQ,WAAW,mBAAgB,EAAA,yBAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkBjE,gBAAgB,EAAE,YAAY,kBAAkB"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { SymbolIdInputSchema } from "../shared.js";
|
|
1
2
|
import { scaledToDecimalOutput } from "../../shared/decimal-surface.js";
|
|
2
3
|
import { normalizeOrderbookDepth } from "./orderbook.codecs.js";
|
|
3
4
|
import * as v from "valibot";
|
|
4
5
|
//#region src/services/orderbook/orderbook.schemas.ts
|
|
5
6
|
const GetOrderbookInputSchema = v.pipe(v.object({
|
|
6
|
-
|
|
7
|
+
symbolId: SymbolIdInputSchema,
|
|
7
8
|
depth: v.optional(v.number(), 50)
|
|
8
9
|
}), v.transform((input) => {
|
|
9
10
|
const depth = normalizeOrderbookDepth(input.depth);
|
|
10
11
|
return {
|
|
11
|
-
|
|
12
|
+
symbolId: input.symbolId,
|
|
12
13
|
depth: depth.levels,
|
|
13
14
|
protoDepth: depth.protoDepth
|
|
14
15
|
};
|
|
@@ -17,15 +18,15 @@ const OrderbookLevelInputSchema = v.object({
|
|
|
17
18
|
priceTicks: v.bigint(),
|
|
18
19
|
qtyScaled: v.bigint()
|
|
19
20
|
});
|
|
20
|
-
function formatOrderbookLevel(level, scales,
|
|
21
|
+
function formatOrderbookLevel(level, scales, symbolId) {
|
|
21
22
|
return {
|
|
22
23
|
price: scaledToDecimalOutput(level.priceTicks, scales.price()),
|
|
23
|
-
qty: scaledToDecimalOutput(level.qtyScaled, scales.baseQty(
|
|
24
|
+
qty: scaledToDecimalOutput(level.qtyScaled, scales.baseQty(symbolId))
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
|
-
function createOrderbookDataSchema(scales,
|
|
27
|
+
function createOrderbookDataSchema(scales, symbolId) {
|
|
27
28
|
return v.pipe(v.object({
|
|
28
|
-
|
|
29
|
+
symbolId: v.literal(symbolId),
|
|
29
30
|
depth: v.number(),
|
|
30
31
|
bookSeq: v.bigint(),
|
|
31
32
|
bids: v.array(OrderbookLevelInputSchema),
|
|
@@ -33,8 +34,8 @@ function createOrderbookDataSchema(scales, pair) {
|
|
|
33
34
|
}), v.transform((d) => ({
|
|
34
35
|
...d,
|
|
35
36
|
bookSeq: d.bookSeq.toString(),
|
|
36
|
-
bids: d.bids.map((level) => formatOrderbookLevel(level, scales,
|
|
37
|
-
asks: d.asks.map((level) => formatOrderbookLevel(level, scales,
|
|
37
|
+
bids: d.bids.map((level) => formatOrderbookLevel(level, scales, symbolId)),
|
|
38
|
+
asks: d.asks.map((level) => formatOrderbookLevel(level, scales, symbolId))
|
|
38
39
|
})));
|
|
39
40
|
}
|
|
40
41
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orderbook.schemas.js","names":[],"sources":["../../../src/services/orderbook/orderbook.schemas.ts"],"sourcesContent":["import * as v from \"valibot\";\nimport type
|
|
1
|
+
{"version":3,"file":"orderbook.schemas.js","names":[],"sources":["../../../src/services/orderbook/orderbook.schemas.ts"],"sourcesContent":["import * as v from \"valibot\";\nimport { scaledToDecimalOutput, type SdkScales } from \"../../shared/decimal-surface.js\";\nimport { SymbolIdInputSchema } from \"../shared.js\";\nimport { normalizeOrderbookDepth } from \"./orderbook.codecs.js\";\n\nexport const GetOrderbookInputSchema = v.pipe(\n v.object({\n symbolId: SymbolIdInputSchema,\n depth: v.optional(v.number(), 50),\n }),\n v.transform((input) => {\n const depth = normalizeOrderbookDepth(input.depth);\n return {\n symbolId: input.symbolId,\n depth: depth.levels,\n protoDepth: depth.protoDepth,\n };\n }),\n);\n\nexport type GetOrderbookInput = v.InferInput<typeof GetOrderbookInputSchema>;\n\nconst OrderbookLevelInputSchema = v.object({\n priceTicks: v.bigint(),\n qtyScaled: v.bigint(),\n});\n\nexport type OrderbookLevelInput = v.InferOutput<typeof OrderbookLevelInputSchema>;\n\nexport function formatOrderbookLevel(\n level: OrderbookLevelInput,\n scales: SdkScales,\n symbolId: number,\n) {\n return {\n price: scaledToDecimalOutput(level.priceTicks, scales.price()),\n qty: scaledToDecimalOutput(level.qtyScaled, scales.baseQty(symbolId)),\n };\n}\n\nexport type OrderbookLevel = ReturnType<typeof formatOrderbookLevel>;\n\nexport function createOrderbookDataSchema(scales: SdkScales, symbolId: number) {\n return v.pipe(\n v.object({\n symbolId: v.literal(symbolId),\n depth: v.number(),\n bookSeq: v.bigint(),\n bids: v.array(OrderbookLevelInputSchema),\n asks: v.array(OrderbookLevelInputSchema),\n }),\n v.transform((d) => ({\n ...d,\n bookSeq: d.bookSeq.toString(),\n bids: d.bids.map((level) => formatOrderbookLevel(level, scales, symbolId)),\n asks: d.asks.map((level) => formatOrderbookLevel(level, scales, symbolId)),\n })),\n );\n}\n\nexport type OrderbookData = v.InferOutput<ReturnType<typeof createOrderbookDataSchema>>;\n"],"mappings":";;;;;AAKA,MAAa,0BAA0B,EAAE,KACrC,EAAE,OAAO;CACL,UAAU;CACV,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,EAAE;AACpC,CAAC,GACD,EAAE,WAAW,UAAU;CACnB,MAAM,QAAQ,wBAAwB,MAAM,KAAK;CACjD,OAAO;EACH,UAAU,MAAM;EAChB,OAAO,MAAM;EACb,YAAY,MAAM;CACtB;AACJ,CAAC,CACL;AAIA,MAAM,4BAA4B,EAAE,OAAO;CACvC,YAAY,EAAE,OAAO;CACrB,WAAW,EAAE,OAAO;AACxB,CAAC;AAID,SAAgB,qBACZ,OACA,QACA,UACF;CACE,OAAO;EACH,OAAO,sBAAsB,MAAM,YAAY,OAAO,MAAM,CAAC;EAC7D,KAAK,sBAAsB,MAAM,WAAW,OAAO,QAAQ,QAAQ,CAAC;CACxE;AACJ;AAIA,SAAgB,0BAA0B,QAAmB,UAAkB;CAC3E,OAAO,EAAE,KACL,EAAE,OAAO;EACL,UAAU,EAAE,QAAQ,QAAQ;EAC5B,OAAO,EAAE,OAAO;EAChB,SAAS,EAAE,OAAO;EAClB,MAAM,EAAE,MAAM,yBAAyB;EACvC,MAAM,EAAE,MAAM,yBAAyB;CAC3C,CAAC,GACD,EAAE,WAAW,OAAO;EAChB,GAAG;EACH,SAAS,EAAE,QAAQ,SAAS;EAC5B,MAAM,EAAE,KAAK,KAAK,UAAU,qBAAqB,OAAO,QAAQ,QAAQ,CAAC;EACzE,MAAM,EAAE,KAAK,KAAK,UAAU,qBAAqB,OAAO,QAAQ,QAAQ,CAAC;CAC7E,EAAE,CACN;AACJ"}
|