@usherlabs/cex-broker 0.2.51 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/cli.js +580 -93
- package/dist/index.js +581 -94
- package/dist/index.js.map +15 -14
- package/package.json +5 -28
- package/dist/commands/cex-canonical-orderbook-export.d.ts +0 -23
- package/dist/commands/cex-canonical-orderbook-export.js +0 -34275
- package/dist/commands/cex-canonical-orderbook-export.js.map +0 -266
- package/dist/commands/market-data-vendor-backfill.d.ts +0 -24
- package/dist/commands/market-data-vendor-backfill.js +0 -34930
- package/dist/commands/market-data-vendor-backfill.js.map +0 -268
- package/dist/handlers/execute-action/context.d.ts +0 -50
- package/dist/handlers/execute-action/deposit.d.ts +0 -2
- package/dist/handlers/execute-action/handler.d.ts +0 -19
- package/dist/handlers/execute-action/index.d.ts +0 -10
- package/dist/handlers/execute-action/internal-transfer.d.ts +0 -2
- package/dist/handlers/execute-action/order-book-call.d.ts +0 -3
- package/dist/handlers/execute-action/orders.d.ts +0 -2
- package/dist/handlers/execute-action/pass-through.d.ts +0 -2
- package/dist/handlers/execute-action/perp-config.d.ts +0 -2
- package/dist/handlers/execute-action/registry.d.ts +0 -5
- package/dist/handlers/execute-action/treasury-call.d.ts +0 -2
- package/dist/handlers/execute-action/withdraw.d.ts +0 -2
- package/dist/handlers/subscribe/broker-lifecycle.d.ts +0 -13
- package/dist/handlers/subscribe/handler.d.ts +0 -20
- package/dist/handlers/subscribe/index.d.ts +0 -2
- package/dist/handlers/types.d.ts +0 -23
- package/dist/helpers/account-balance-archive-poller.d.ts +0 -19
- package/dist/helpers/auth.d.ts +0 -5
- package/dist/helpers/balance-update-archive-consumer.d.ts +0 -16
- package/dist/helpers/binance-user-data-normalization.d.ts +0 -3
- package/dist/helpers/binance-user-data-stream.d.ts +0 -58
- package/dist/helpers/broker-execution-archive/capture.d.ts +0 -41
- package/dist/helpers/broker-execution-archive/index.d.ts +0 -7
- package/dist/helpers/broker-execution-archive/journal-export.d.ts +0 -20
- package/dist/helpers/broker-execution-archive/loss-journal.d.ts +0 -36
- package/dist/helpers/broker-execution-archive/redact.d.ts +0 -7
- package/dist/helpers/broker-execution-archive/rows.d.ts +0 -134
- package/dist/helpers/broker-execution-archive/types.d.ts +0 -26
- package/dist/helpers/broker-execution-archive/withdrawal-observation-tracker.d.ts +0 -23
- package/dist/helpers/broker-execution-archive/writer.d.ts +0 -105
- package/dist/helpers/broker.d.ts +0 -38
- package/dist/helpers/canonical-orderbook-export/exact-selection.d.ts +0 -21
- package/dist/helpers/canonical-orderbook-export/exporter.d.ts +0 -26
- package/dist/helpers/canonical-orderbook-export/parquet-projection.d.ts +0 -19
- package/dist/helpers/constants.d.ts +0 -36
- package/dist/helpers/deposit-archive-poller.d.ts +0 -33
- package/dist/helpers/deposit.d.ts +0 -5
- package/dist/helpers/exchange-credentials.d.ts +0 -10
- package/dist/helpers/fill-archive-poller.d.ts +0 -42
- package/dist/helpers/grpc/broker.d.ts +0 -5
- package/dist/helpers/grpc/callbacks.d.ts +0 -9
- package/dist/helpers/grpc/payload.d.ts +0 -9
- package/dist/helpers/grpc/status.d.ts +0 -8
- package/dist/helpers/index.d.ts +0 -44
- package/dist/helpers/logger.d.ts +0 -13
- package/dist/helpers/market-data-archive/canonical-orderbook.d.ts +0 -20
- package/dist/helpers/market-data-archive/capture-context.d.ts +0 -53
- package/dist/helpers/market-data-archive/capture-contract.d.ts +0 -30
- package/dist/helpers/market-data-archive/capture.d.ts +0 -22
- package/dist/helpers/market-data-archive/index.d.ts +0 -13
- package/dist/helpers/market-data-archive/legacy-migration.d.ts +0 -37
- package/dist/helpers/market-data-archive/ohlcv-bar-tracker.d.ts +0 -11
- package/dist/helpers/market-data-archive/ohlcv-bootstrap.d.ts +0 -1
- package/dist/helpers/market-data-archive/ohlcv-history.d.ts +0 -8
- package/dist/helpers/market-data-archive/orderbook-depth.d.ts +0 -5
- package/dist/helpers/market-data-archive/orderbook-sampler.d.ts +0 -12
- package/dist/helpers/market-data-archive/parse-stream.d.ts +0 -26
- package/dist/helpers/market-data-archive/rows.d.ts +0 -14
- package/dist/helpers/market-data-archive/types.d.ts +0 -83
- package/dist/helpers/market-data-preparation/conformance-fixtures.d.ts +0 -128
- package/dist/helpers/market-data-preparation/contracts.d.ts +0 -2970
- package/dist/helpers/market-data-preparation/file-job.d.ts +0 -38
- package/dist/helpers/market-data-preparation/required-clock-qualification.d.ts +0 -43
- package/dist/helpers/market-data-preparation/source-tape-dependencies.d.ts +0 -19
- package/dist/helpers/market-data-preparation/source-tape-operation.d.ts +0 -109
- package/dist/helpers/market-data-source-forensics.d.ts +0 -400
- package/dist/helpers/market-data-vendor-backfill/archive-reader.d.ts +0 -26
- package/dist/helpers/market-data-vendor-backfill/batching.d.ts +0 -10
- package/dist/helpers/market-data-vendor-backfill/conformance-fixtures.d.ts +0 -78
- package/dist/helpers/market-data-vendor-backfill/contracts.d.ts +0 -358
- package/dist/helpers/market-data-vendor-backfill/core.d.ts +0 -101
- package/dist/helpers/market-data-vendor-backfill/cryptohftdata.d.ts +0 -118
- package/dist/helpers/market-data-vendor-backfill/forwarder-client.d.ts +0 -25
- package/dist/helpers/market-data-vendor-backfill/identity.d.ts +0 -10
- package/dist/helpers/market-data-vendor-backfill/manifests.d.ts +0 -61
- package/dist/helpers/market-data-vendor-backfill/promotion.d.ts +0 -10
- package/dist/helpers/market-data-vendor-backfill/qualification.d.ts +0 -20
- package/dist/helpers/market-data-vendor-backfill/selection.d.ts +0 -30
- package/dist/helpers/market-data-vendor-backfill/semantic-verification.d.ts +0 -25
- package/dist/helpers/market-type.d.ts +0 -16
- package/dist/helpers/order-activity-tracker.d.ts +0 -22
- package/dist/helpers/order-book.d.ts +0 -79
- package/dist/helpers/order-telemetry.d.ts +0 -50
- package/dist/helpers/otel.d.ts +0 -83
- package/dist/helpers/passive-order.d.ts +0 -8
- package/dist/helpers/public-market-data-feed/identity.d.ts +0 -12
- package/dist/helpers/public-market-data-feed/index.d.ts +0 -5
- package/dist/helpers/public-market-data-feed/orderbook-coalescing-evidence.d.ts +0 -79
- package/dist/helpers/public-market-data-feed/orderbook-profile.d.ts +0 -54
- package/dist/helpers/public-market-data-feed/subscriber-buffer.d.ts +0 -31
- package/dist/helpers/public-market-data-feed/supervisor.d.ts +0 -82
- package/dist/helpers/shared/errors.d.ts +0 -14
- package/dist/helpers/shared/guards.d.ts +0 -2
- package/dist/helpers/source-tape-sandbox.d.ts +0 -82
- package/dist/helpers/source-tape.d.ts +0 -165
- package/dist/helpers/stream-health-publisher.d.ts +0 -41
- package/dist/helpers/trace-context.d.ts +0 -8
- package/dist/helpers/transfer-network.d.ts +0 -12
- package/dist/helpers/travel-rule-deposit-reconciler.d.ts +0 -159
- package/dist/helpers/travel-rule.d.ts +0 -75
- package/dist/helpers/treasury-discovery.d.ts +0 -17
- package/dist/helpers/user-asset-archive-poller.d.ts +0 -19
- package/dist/helpers/user-data-stream-supervisor.d.ts +0 -27
- package/dist/helpers/verity.d.ts +0 -5
- package/dist/index.d.ts +0 -56
- package/dist/market-data-preparation/fixtures/conformance-v3.json +0 -621
- package/dist/market-data-preparation/policies/capability-policy.json +0 -39
- package/dist/market-data-preparation/policies/resource-policy.json +0 -16
- package/dist/market-data-preparation/policies/source-tape-capability-v1.json +0 -35
- package/dist/market-data-preparation/schema-manifest.json +0 -66
- package/dist/market-data-preparation/schemas/archive-selection-v1.schema.json +0 -224
- package/dist/market-data-preparation/schemas/backfill-request-v1.schema.json +0 -166
- package/dist/market-data-preparation/schemas/backfill-result-v2.schema.json +0 -212
- package/dist/market-data-preparation/schemas/canonical-orderbook-export-request-v1.schema.json +0 -61
- package/dist/market-data-preparation/schemas/canonical-orderbook-export-result-v2.schema.json +0 -252
- package/dist/market-data-preparation/schemas/order-book-depth-summary-parquet-projection-v1.schema.json +0 -256
- package/dist/market-data-preparation/schemas/order-book-levels-parquet-projection-v1.schema.json +0 -220
- package/dist/market-data-preparation/schemas/preparation-product-pin-v2.schema.json +0 -176
- package/dist/market-data-preparation/schemas/promotion-receipt-v1.schema.json +0 -175
- package/dist/market-data-preparation/schemas/required-clock-v1.schema.json +0 -47
- package/dist/market-data-preparation/schemas/source-forensics-ledger-v1.schema.json +0 -463
- package/dist/market-data-preparation/schemas/source-qualification-record-v1.schema.json +0 -394
- package/dist/market-data-preparation.d.ts +0 -11
- package/dist/market-data-preparation.js +0 -37488
- package/dist/market-data-preparation.js.map +0 -277
- package/dist/market-data-vendor-backfill.d.ts +0 -21
- package/dist/market-data-vendor-backfill.js +0 -22463
- package/dist/market-data-vendor-backfill.js.map +0 -199
- package/dist/proto/node.descriptor.d.ts +0 -127
- package/dist/proto-loader-options.d.ts +0 -7
- package/dist/proto-package-definition.d.ts +0 -2
- package/dist/schemas/action-payloads.d.ts +0 -88
- package/dist/server.d.ts +0 -10
- package/dist/types.d.ts +0 -100
package/dist/index.js
CHANGED
|
@@ -291352,6 +291352,22 @@ import {
|
|
|
291352
291352
|
import { basename, dirname } from "node:path";
|
|
291353
291353
|
var EXPORT_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
291354
291354
|
var SHA256_RECEIPT_PATTERN = /^([0-9a-f]{64}) {2}(.+)\n$/;
|
|
291355
|
+
function sha256File(path) {
|
|
291356
|
+
const hash4 = createHash3("sha256");
|
|
291357
|
+
const fd2 = openSync(path, "r");
|
|
291358
|
+
try {
|
|
291359
|
+
const chunk = Buffer.alloc(EXPORT_CHUNK_BYTES);
|
|
291360
|
+
for (;; ) {
|
|
291361
|
+
const read = readSync(fd2, chunk, 0, chunk.length, null);
|
|
291362
|
+
if (read === 0)
|
|
291363
|
+
break;
|
|
291364
|
+
hash4.update(chunk.subarray(0, read));
|
|
291365
|
+
}
|
|
291366
|
+
} finally {
|
|
291367
|
+
closeSync(fd2);
|
|
291368
|
+
}
|
|
291369
|
+
return hash4.digest("hex");
|
|
291370
|
+
}
|
|
291355
291371
|
|
|
291356
291372
|
class DeadLetterJournalExportError extends Error {
|
|
291357
291373
|
constructor(message, options) {
|
|
@@ -291385,6 +291401,9 @@ function exportDeadLetterJournal(journalPath, exportPath) {
|
|
|
291385
291401
|
if (match?.[1] === undefined || match[2] !== basename(exportPath)) {
|
|
291386
291402
|
throw new Error("export receipt is malformed");
|
|
291387
291403
|
}
|
|
291404
|
+
if (sha256File(exportPath) !== match[1]) {
|
|
291405
|
+
throw new Error("export digest does not match receipt");
|
|
291406
|
+
}
|
|
291388
291407
|
} catch (error) {
|
|
291389
291408
|
throw new DeadLetterJournalExportError("Dead-letter journal export target is incomplete or unverifiable", { cause: error });
|
|
291390
291409
|
}
|
|
@@ -292725,6 +292744,16 @@ function withTimeout(promise, timeoutMs, label) {
|
|
|
292725
292744
|
return Promise.race([promise, expiry]).finally(() => clearTimeout(timer));
|
|
292726
292745
|
}
|
|
292727
292746
|
var ALL_CURRENCIES_CODE = "*";
|
|
292747
|
+
var BINANCE_UNLOCK_PROGRESS_SOURCE = {
|
|
292748
|
+
venue: "binance",
|
|
292749
|
+
endpoint: "GET /sapi/v1/capital/deposit/hisrec",
|
|
292750
|
+
fields: {
|
|
292751
|
+
status: "info.status",
|
|
292752
|
+
confirmTimes: "info.confirmTimes",
|
|
292753
|
+
unlockConfirm: "info.unlockConfirm",
|
|
292754
|
+
completeTime: "info.completeTime"
|
|
292755
|
+
}
|
|
292756
|
+
};
|
|
292728
292757
|
function depositTimestamp(record) {
|
|
292729
292758
|
const observedAt = depositField(record, [
|
|
292730
292759
|
"timestamp",
|
|
@@ -292737,12 +292766,185 @@ function depositTimestamp(record) {
|
|
|
292737
292766
|
const timestamp = typeof observedAt === "number" ? observedAt : typeof observedAt === "string" ? Date.parse(observedAt) : Number.NaN;
|
|
292738
292767
|
return Number.isFinite(timestamp) ? timestamp : undefined;
|
|
292739
292768
|
}
|
|
292740
|
-
function
|
|
292741
|
-
|
|
292742
|
-
|
|
292743
|
-
|
|
292769
|
+
function parseNonNegativeInteger(value) {
|
|
292770
|
+
if (typeof value === "number") {
|
|
292771
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
292772
|
+
}
|
|
292773
|
+
if (typeof value !== "string") {
|
|
292774
|
+
return;
|
|
292775
|
+
}
|
|
292776
|
+
const trimmed = value.trim();
|
|
292777
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
292778
|
+
return;
|
|
292779
|
+
}
|
|
292780
|
+
const parsed = Number(trimmed);
|
|
292781
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : undefined;
|
|
292782
|
+
}
|
|
292783
|
+
function parseConfirmTimes(value) {
|
|
292784
|
+
if (value === undefined || value === null) {
|
|
292785
|
+
return { reason: "missing_confirmTimes" };
|
|
292786
|
+
}
|
|
292787
|
+
let currentValue;
|
|
292788
|
+
let creditRequiredValue;
|
|
292789
|
+
if (typeof value === "string") {
|
|
292790
|
+
const match = /^(\d+)\s*\/\s*(\d+)$/.exec(value.trim());
|
|
292791
|
+
if (!match) {
|
|
292792
|
+
return { reason: "invalid_confirmTimes" };
|
|
292793
|
+
}
|
|
292794
|
+
currentValue = match[1];
|
|
292795
|
+
creditRequiredValue = match[2];
|
|
292796
|
+
} else {
|
|
292797
|
+
const record = asRecord(value);
|
|
292798
|
+
if (!record) {
|
|
292799
|
+
return { reason: "invalid_confirmTimes" };
|
|
292800
|
+
}
|
|
292801
|
+
currentValue = record.current;
|
|
292802
|
+
creditRequiredValue = record.credit_required;
|
|
292803
|
+
}
|
|
292804
|
+
const current = parseNonNegativeInteger(currentValue);
|
|
292805
|
+
const creditRequired = parseNonNegativeInteger(creditRequiredValue);
|
|
292806
|
+
if (current === undefined || creditRequired === undefined) {
|
|
292807
|
+
return { reason: "invalid_confirmTimes" };
|
|
292744
292808
|
}
|
|
292745
|
-
return
|
|
292809
|
+
return { current, creditRequired, reason: null };
|
|
292810
|
+
}
|
|
292811
|
+
function parseOptionalNonNegativeInteger(value, fieldName) {
|
|
292812
|
+
if (value === undefined || value === null) {
|
|
292813
|
+
return { value: undefined, reason: null };
|
|
292814
|
+
}
|
|
292815
|
+
const parsed = parseNonNegativeInteger(value);
|
|
292816
|
+
return parsed === undefined ? { value: undefined, reason: `invalid_${fieldName}` } : { value: parsed, reason: null };
|
|
292817
|
+
}
|
|
292818
|
+
function parseBinanceUnlockProgress(record) {
|
|
292819
|
+
const info = asRecord(record.info);
|
|
292820
|
+
const nativeStatus = parseNonNegativeInteger(info?.status);
|
|
292821
|
+
const confirmations = parseConfirmTimes(info?.confirmTimes);
|
|
292822
|
+
const unlockRequired = parseOptionalNonNegativeInteger(info?.unlockConfirm, "unlockConfirm");
|
|
292823
|
+
const completeTime = parseOptionalNonNegativeInteger(info?.completeTime, "completeTime");
|
|
292824
|
+
let quality = "valid";
|
|
292825
|
+
let reason = null;
|
|
292826
|
+
if (nativeStatus === undefined) {
|
|
292827
|
+
quality = "unknown";
|
|
292828
|
+
reason = "missing_or_invalid_status";
|
|
292829
|
+
} else if (confirmations.reason !== null) {
|
|
292830
|
+
quality = "unknown";
|
|
292831
|
+
reason = confirmations.reason;
|
|
292832
|
+
} else if (unlockRequired.reason !== null) {
|
|
292833
|
+
quality = "unknown";
|
|
292834
|
+
reason = unlockRequired.reason;
|
|
292835
|
+
} else if (completeTime.reason !== null) {
|
|
292836
|
+
quality = "unknown";
|
|
292837
|
+
reason = completeTime.reason;
|
|
292838
|
+
}
|
|
292839
|
+
let state = "unknown";
|
|
292840
|
+
switch (nativeStatus) {
|
|
292841
|
+
case 0:
|
|
292842
|
+
state = "pending";
|
|
292843
|
+
break;
|
|
292844
|
+
case 1:
|
|
292845
|
+
if (quality === "valid" && confirmations.current !== undefined && unlockRequired.value !== undefined && confirmations.current >= unlockRequired.value) {
|
|
292846
|
+
state = "ok";
|
|
292847
|
+
} else if (quality === "valid") {
|
|
292848
|
+
state = "credited_not_withdrawable";
|
|
292849
|
+
}
|
|
292850
|
+
break;
|
|
292851
|
+
case 2:
|
|
292852
|
+
case 7:
|
|
292853
|
+
state = "failed";
|
|
292854
|
+
break;
|
|
292855
|
+
case 6:
|
|
292856
|
+
state = "credited_not_withdrawable";
|
|
292857
|
+
break;
|
|
292858
|
+
case 8:
|
|
292859
|
+
state = "pending";
|
|
292860
|
+
break;
|
|
292861
|
+
default:
|
|
292862
|
+
quality = "unknown";
|
|
292863
|
+
reason = "unsupported_status";
|
|
292864
|
+
break;
|
|
292865
|
+
}
|
|
292866
|
+
return {
|
|
292867
|
+
version: 1,
|
|
292868
|
+
state,
|
|
292869
|
+
progress_state: quality,
|
|
292870
|
+
reason,
|
|
292871
|
+
native_status: nativeStatus ?? null,
|
|
292872
|
+
current: confirmations.current ?? null,
|
|
292873
|
+
credit_required: confirmations.creditRequired ?? null,
|
|
292874
|
+
unlock_required: unlockRequired.value ?? null,
|
|
292875
|
+
complete_time: completeTime.value ?? null,
|
|
292876
|
+
observed_at: new Date().toISOString(),
|
|
292877
|
+
source: BINANCE_UNLOCK_PROGRESS_SOURCE
|
|
292878
|
+
};
|
|
292879
|
+
}
|
|
292880
|
+
function unlockProgressKey(progress) {
|
|
292881
|
+
return JSON.stringify({
|
|
292882
|
+
version: progress.version,
|
|
292883
|
+
state: progress.state,
|
|
292884
|
+
progress_state: progress.progress_state,
|
|
292885
|
+
reason: progress.reason,
|
|
292886
|
+
native_status: progress.native_status,
|
|
292887
|
+
current: progress.current,
|
|
292888
|
+
credit_required: progress.credit_required,
|
|
292889
|
+
unlock_required: progress.unlock_required,
|
|
292890
|
+
complete_time: progress.complete_time
|
|
292891
|
+
});
|
|
292892
|
+
}
|
|
292893
|
+
function progressWatermark(progress, previous) {
|
|
292894
|
+
if (progress.progress_state !== "valid" || progress.current === null || progress.credit_required === null || progress.unlock_required === null) {
|
|
292895
|
+
return previous;
|
|
292896
|
+
}
|
|
292897
|
+
return {
|
|
292898
|
+
current: Math.max(previous?.current ?? 0, progress.current),
|
|
292899
|
+
credit_required: progress.credit_required,
|
|
292900
|
+
unlock_required: progress.unlock_required
|
|
292901
|
+
};
|
|
292902
|
+
}
|
|
292903
|
+
function classifyBinanceDeposit(record, previous) {
|
|
292904
|
+
let progress = parseBinanceUnlockProgress(record);
|
|
292905
|
+
let highWatermark = previous?.highWatermark;
|
|
292906
|
+
if (progress.progress_state === "valid" && progress.current !== null && progress.credit_required !== null && progress.unlock_required !== null && previous?.highWatermark !== undefined && (progress.current < previous.highWatermark.current || progress.credit_required !== previous.highWatermark.credit_required || progress.unlock_required !== previous.highWatermark.unlock_required)) {
|
|
292907
|
+
progress = {
|
|
292908
|
+
...progress,
|
|
292909
|
+
state: "unknown",
|
|
292910
|
+
progress_state: "contradictory",
|
|
292911
|
+
reason: "confirmation_progress_regressed_or_requirement_changed"
|
|
292912
|
+
};
|
|
292913
|
+
} else {
|
|
292914
|
+
highWatermark = progressWatermark(progress, previous?.highWatermark);
|
|
292915
|
+
}
|
|
292916
|
+
return {
|
|
292917
|
+
archiveStatus: progress.state,
|
|
292918
|
+
holdCursor: progress.state === "pending" || progress.state === "credited_not_withdrawable" || progress.state === "unknown",
|
|
292919
|
+
unlockProgress: progress,
|
|
292920
|
+
progressKey: unlockProgressKey(progress),
|
|
292921
|
+
highWatermark
|
|
292922
|
+
};
|
|
292923
|
+
}
|
|
292924
|
+
function classifyDeposit(exchangeId, record, previous) {
|
|
292925
|
+
if (exchangeId?.toLowerCase() === "binance") {
|
|
292926
|
+
return classifyBinanceDeposit(record, previous);
|
|
292927
|
+
}
|
|
292928
|
+
const archiveStatus = normalizeCcxtTransactionForArchive(record).status ?? "";
|
|
292929
|
+
const status = normalizeDepositStatus(depositField(record, ["status", "state"]));
|
|
292930
|
+
return {
|
|
292931
|
+
archiveStatus,
|
|
292932
|
+
holdCursor: archiveStatus === "credited_not_withdrawable" || status === "pending",
|
|
292933
|
+
progressKey: JSON.stringify({ status: archiveStatus })
|
|
292934
|
+
};
|
|
292935
|
+
}
|
|
292936
|
+
function depositIdentity(input) {
|
|
292937
|
+
if (input.externalId === undefined && input.txid === undefined) {
|
|
292938
|
+
return;
|
|
292939
|
+
}
|
|
292940
|
+
return JSON.stringify({
|
|
292941
|
+
exchange: input.exchangeId,
|
|
292942
|
+
account: input.accountSelector,
|
|
292943
|
+
coin: input.coin === undefined ? "" : String(input.coin),
|
|
292944
|
+
network: input.network === undefined ? "" : String(input.network),
|
|
292945
|
+
external_id: input.externalId ?? "",
|
|
292946
|
+
txid: input.txid ?? ""
|
|
292947
|
+
});
|
|
292746
292948
|
}
|
|
292747
292949
|
function nextDepositCursor(deposits, currentSince, depositsLimit, exchangeId) {
|
|
292748
292950
|
if (deposits.length >= depositsLimit) {
|
|
@@ -292756,9 +292958,8 @@ function nextDepositCursor(deposits, currentSince, depositsLimit, exchangeId) {
|
|
|
292756
292958
|
return currentSince;
|
|
292757
292959
|
}
|
|
292758
292960
|
const timestamp = depositTimestamp(record);
|
|
292759
|
-
const
|
|
292760
|
-
const
|
|
292761
|
-
const isPending = archiveStatus === "credited_not_withdrawable" || status === "pending";
|
|
292961
|
+
const classification = classifyDeposit(exchangeId, record);
|
|
292962
|
+
const isPending = classification.holdCursor;
|
|
292762
292963
|
if (timestamp === undefined) {
|
|
292763
292964
|
if (isPending) {
|
|
292764
292965
|
return currentSince;
|
|
@@ -292878,7 +293079,8 @@ class DepositArchivePoller {
|
|
|
292878
293079
|
if (!record) {
|
|
292879
293080
|
continue;
|
|
292880
293081
|
}
|
|
292881
|
-
const
|
|
293082
|
+
const info = asRecord(record.info);
|
|
293083
|
+
const assetSymbol = depositField(record, ["currency", "code", "asset"]) ?? info?.coin;
|
|
292882
293084
|
const amount = depositField(record, ["amount"]);
|
|
292883
293085
|
const address = depositField(record, [
|
|
292884
293086
|
"address",
|
|
@@ -292887,8 +293089,21 @@ class DepositArchivePoller {
|
|
|
292887
293089
|
"destination"
|
|
292888
293090
|
]);
|
|
292889
293091
|
const txid = depositField(record, ["txid", "txId", "tx_hash", "txHash"]);
|
|
292890
|
-
const network = depositField(record, ["network", "chain"]);
|
|
292891
|
-
const
|
|
293092
|
+
const network = depositField(record, ["network", "chain"]) ?? info?.network;
|
|
293093
|
+
const depositTxid = txid === undefined ? undefined : String(txid);
|
|
293094
|
+
const identity = depositIdentity({
|
|
293095
|
+
exchangeId: target.exchangeId,
|
|
293096
|
+
accountSelector: target.account.label,
|
|
293097
|
+
coin: assetSymbol,
|
|
293098
|
+
network,
|
|
293099
|
+
externalId: depositTxid,
|
|
293100
|
+
txid: depositTxid
|
|
293101
|
+
});
|
|
293102
|
+
const lastArchived = identity === undefined ? undefined : this.#lastArchivedByTarget.get(key)?.get(identity);
|
|
293103
|
+
const classification = classifyDeposit(target.exchangeId, record, lastArchived);
|
|
293104
|
+
if (lastArchived && lastArchived.status === classification.archiveStatus && lastArchived.progressKey === classification.progressKey) {
|
|
293105
|
+
continue;
|
|
293106
|
+
}
|
|
292892
293107
|
const creditedAt = depositField(record, [
|
|
292893
293108
|
"creditedAt",
|
|
292894
293109
|
"credited_at",
|
|
@@ -292897,11 +293112,7 @@ class DepositArchivePoller {
|
|
|
292897
293112
|
"timestamp",
|
|
292898
293113
|
"datetime"
|
|
292899
293114
|
]);
|
|
292900
|
-
const
|
|
292901
|
-
const lastArchived = depositTxid === undefined ? undefined : this.#lastArchivedByTarget.get(key)?.get(depositTxid);
|
|
292902
|
-
if (lastArchived && lastArchived.status === archiveStatus) {
|
|
292903
|
-
continue;
|
|
292904
|
-
}
|
|
293115
|
+
const payload = classification.unlockProgress === undefined ? record : { ...record, unlock_progress: classification.unlockProgress };
|
|
292905
293116
|
this.params.archiver.enqueue(buildTransferEventArchiveRow({
|
|
292906
293117
|
tags: buildCommonArchiveTags({
|
|
292907
293118
|
deploymentId: this.params.archiver.getDeploymentId(),
|
|
@@ -292912,25 +293123,27 @@ class DepositArchivePoller {
|
|
|
292912
293123
|
transfer: {
|
|
292913
293124
|
eventKind: "deposit",
|
|
292914
293125
|
lifecycleAction: "observe_deposit",
|
|
292915
|
-
status: archiveStatus,
|
|
293126
|
+
status: classification.archiveStatus,
|
|
292916
293127
|
amount: amount === undefined ? undefined : String(amount),
|
|
292917
293128
|
address: address === undefined ? undefined : String(address),
|
|
292918
293129
|
network: network === undefined ? undefined : String(network),
|
|
292919
293130
|
externalId: depositTxid,
|
|
292920
293131
|
txid: depositTxid,
|
|
292921
293132
|
exchangeTimestamp: normalizeTimestamp(creditedAt),
|
|
292922
|
-
payload
|
|
293133
|
+
payload
|
|
292923
293134
|
}
|
|
292924
293135
|
}));
|
|
292925
|
-
if (
|
|
293136
|
+
if (identity !== undefined) {
|
|
292926
293137
|
let targetDeposits2 = this.#lastArchivedByTarget.get(key);
|
|
292927
293138
|
if (!targetDeposits2) {
|
|
292928
293139
|
targetDeposits2 = new Map;
|
|
292929
293140
|
this.#lastArchivedByTarget.set(key, targetDeposits2);
|
|
292930
293141
|
}
|
|
292931
|
-
targetDeposits2.set(
|
|
292932
|
-
status: archiveStatus,
|
|
292933
|
-
timestamp: depositTimestamp(record)
|
|
293142
|
+
targetDeposits2.set(identity, {
|
|
293143
|
+
status: classification.archiveStatus,
|
|
293144
|
+
timestamp: depositTimestamp(record),
|
|
293145
|
+
progressKey: classification.progressKey,
|
|
293146
|
+
highWatermark: classification.highWatermark
|
|
292934
293147
|
});
|
|
292935
293148
|
}
|
|
292936
293149
|
archived += 1;
|
|
@@ -293098,10 +293311,7 @@ import { createHash as createHash4 } from "node:crypto";
|
|
|
293098
293311
|
var MARKET_CAPTURE_SCHEMA_VERSION = "1.0.0";
|
|
293099
293312
|
var CHECKSUM_ALGORITHM = "sha256-canonical-json-v1";
|
|
293100
293313
|
var ARCHIVE_SOURCES = ["broker_read", "broker_write"];
|
|
293101
|
-
var MARKET_ARCHIVE_SOURCES =
|
|
293102
|
-
...ARCHIVE_SOURCES,
|
|
293103
|
-
"external_backfill"
|
|
293104
|
-
];
|
|
293314
|
+
var MARKET_ARCHIVE_SOURCES = ARCHIVE_SOURCES;
|
|
293105
293315
|
var CAPTURE_FEEDS = [
|
|
293106
293316
|
"ORDERBOOK",
|
|
293107
293317
|
"TICKER",
|
|
@@ -293115,15 +293325,12 @@ var SOURCE_MODES = [
|
|
|
293115
293325
|
"broker_bootstrap_fetch_v1",
|
|
293116
293326
|
"external_ccxt_fallback_v1",
|
|
293117
293327
|
"external_hummingbot_fallback_v1",
|
|
293118
|
-
"legacy_migration_v1"
|
|
293119
|
-
"historical_vendor_orderbook_v1",
|
|
293120
|
-
"vendor_historical_backfill_v1"
|
|
293328
|
+
"legacy_migration_v1"
|
|
293121
293329
|
];
|
|
293122
293330
|
var RAW_CAPTURE_SCOPES = [
|
|
293123
293331
|
"ccxt_normalized_object",
|
|
293124
293332
|
"broker_visible_payload",
|
|
293125
|
-
"exchange_wire_frame"
|
|
293126
|
-
"vendor_normalized_dataset_file"
|
|
293333
|
+
"exchange_wire_frame"
|
|
293127
293334
|
];
|
|
293128
293335
|
var CHECKSUM_FIELDS = new Set([
|
|
293129
293336
|
"normalized_row_checksum",
|
|
@@ -293312,6 +293519,9 @@ function createRawCapture(context2, input) {
|
|
|
293312
293519
|
checksumAlgorithm: context2.checksumAlgorithm
|
|
293313
293520
|
};
|
|
293314
293521
|
}
|
|
293522
|
+
function projectRawCapturePayload(rawCapture, redactedPayload) {
|
|
293523
|
+
return { ...rawCapture, redactedPayload };
|
|
293524
|
+
}
|
|
293315
293525
|
function captureCoreFields(context2, rawCapture) {
|
|
293316
293526
|
assertCaptureContext(context2);
|
|
293317
293527
|
return {
|
|
@@ -293888,14 +294098,20 @@ function resolveConservativeOrderBookAcquisitionProfile(input) {
|
|
|
293888
294098
|
id: `${exchange}:conservative:default`,
|
|
293889
294099
|
upstreamLimit: undefined,
|
|
293890
294100
|
guaranteedRetainedDepth: undefined,
|
|
293891
|
-
coalescingSupported: false
|
|
294101
|
+
coalescingSupported: false,
|
|
294102
|
+
bidExhaustionEvidence: false,
|
|
294103
|
+
askExhaustionEvidence: false,
|
|
294104
|
+
exhaustionEvidenceValidated: true
|
|
293892
294105
|
};
|
|
293893
294106
|
}
|
|
293894
294107
|
return {
|
|
293895
294108
|
id: `${exchange}:conservative:limit:${input.requestedDepth}`,
|
|
293896
294109
|
upstreamLimit: input.requestedDepth,
|
|
293897
294110
|
guaranteedRetainedDepth: input.requestedDepth,
|
|
293898
|
-
coalescingSupported: false
|
|
294111
|
+
coalescingSupported: false,
|
|
294112
|
+
bidExhaustionEvidence: false,
|
|
294113
|
+
askExhaustionEvidence: false,
|
|
294114
|
+
exhaustionEvidenceValidated: true
|
|
293899
294115
|
};
|
|
293900
294116
|
}
|
|
293901
294117
|
function resolveOrderBookAcquisitionProfile(input) {
|
|
@@ -293907,7 +294123,10 @@ function resolveOrderBookAcquisitionProfile(input) {
|
|
|
293907
294123
|
id: candidateProfileId,
|
|
293908
294124
|
upstreamLimit: VERIFIED_PROFILE_DEPTH,
|
|
293909
294125
|
guaranteedRetainedDepth: VERIFIED_PROFILE_DEPTH,
|
|
293910
|
-
coalescingSupported: true
|
|
294126
|
+
coalescingSupported: true,
|
|
294127
|
+
bidExhaustionEvidence: false,
|
|
294128
|
+
askExhaustionEvidence: false,
|
|
294129
|
+
exhaustionEvidenceValidated: true
|
|
293911
294130
|
};
|
|
293912
294131
|
}
|
|
293913
294132
|
return resolveConservativeOrderBookAcquisitionProfile(input);
|
|
@@ -294057,7 +294276,63 @@ class PublicFeedSubscriberBuffer {
|
|
|
294057
294276
|
this.#bytes = 0;
|
|
294058
294277
|
}
|
|
294059
294278
|
}
|
|
294279
|
+
// src/helpers/market-data-archive/orderbook-depth.ts
|
|
294280
|
+
var DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 25;
|
|
294281
|
+
var MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 500;
|
|
294282
|
+
var MAX_ORDERBOOK_MEASUREMENT_BANDS = 64;
|
|
294283
|
+
var MAX_ORDERBOOK_MEASUREMENT_BAND_BPS = 1e4;
|
|
294284
|
+
var DEFAULT_ORDERBOOK_MEASUREMENT_BANDS_BPS = [10, 25, 50, 100];
|
|
294285
|
+
function parseBoundedDepth(raw, field) {
|
|
294286
|
+
if (!/^[1-9]\d*$/.test(raw)) {
|
|
294287
|
+
throw new Error(`${field} must be an integer between 1 and 500`);
|
|
294288
|
+
}
|
|
294289
|
+
const parsed = Number(raw);
|
|
294290
|
+
if (!Number.isSafeInteger(parsed) || parsed > MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT) {
|
|
294291
|
+
throw new Error(`${field} must be an integer between 1 and 500`);
|
|
294292
|
+
}
|
|
294293
|
+
return parsed;
|
|
294294
|
+
}
|
|
294295
|
+
function getOrderbookArchiveDepthLimit() {
|
|
294296
|
+
const raw = process.env.CEX_BROKER_ORDERBOOK_ARCHIVE_DEPTH_LIMIT?.trim();
|
|
294297
|
+
if (!raw) {
|
|
294298
|
+
return DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
|
|
294299
|
+
}
|
|
294300
|
+
return parseBoundedDepth(raw, "CEX_BROKER_ORDERBOOK_ARCHIVE_DEPTH_LIMIT");
|
|
294301
|
+
}
|
|
294302
|
+
function normalizeOrderbookMeasurementBandsBps(input) {
|
|
294303
|
+
const bands = input ?? DEFAULT_ORDERBOOK_MEASUREMENT_BANDS_BPS;
|
|
294304
|
+
if (bands.length === 0) {
|
|
294305
|
+
throw new Error("ORDERBOOK measurement bands must not be empty");
|
|
294306
|
+
}
|
|
294307
|
+
if (bands.length > MAX_ORDERBOOK_MEASUREMENT_BANDS) {
|
|
294308
|
+
throw new Error(`ORDERBOOK measurement bands must contain at most ${MAX_ORDERBOOK_MEASUREMENT_BANDS} entries`);
|
|
294309
|
+
}
|
|
294310
|
+
for (const band of bands) {
|
|
294311
|
+
if (!Number.isSafeInteger(band) || band <= 0 || band > MAX_ORDERBOOK_MEASUREMENT_BAND_BPS) {
|
|
294312
|
+
throw new Error("ORDERBOOK measurement bands must be integer basis points in 1..10000");
|
|
294313
|
+
}
|
|
294314
|
+
}
|
|
294315
|
+
const normalized = [...new Set(bands)].sort((left, right) => left - right);
|
|
294316
|
+
if (normalized.length > MAX_ORDERBOOK_MEASUREMENT_BANDS) {
|
|
294317
|
+
throw new Error(`ORDERBOOK measurement bands must contain at most ${MAX_ORDERBOOK_MEASUREMENT_BANDS} unique entries`);
|
|
294318
|
+
}
|
|
294319
|
+
return normalized;
|
|
294320
|
+
}
|
|
294321
|
+
function getOrderbookMeasurementBandsBps() {
|
|
294322
|
+
const raw = process.env.CEX_BROKER_ORDERBOOK_MEASUREMENT_BANDS_BPS?.trim();
|
|
294323
|
+
if (!raw) {
|
|
294324
|
+
return [...DEFAULT_ORDERBOOK_MEASUREMENT_BANDS_BPS];
|
|
294325
|
+
}
|
|
294326
|
+
const parts = raw.split(",").map((entry) => entry.trim());
|
|
294327
|
+
if (parts.some((entry) => !/^[1-9]\d*$/.test(entry))) {
|
|
294328
|
+
throw new Error("CEX_BROKER_ORDERBOOK_MEASUREMENT_BANDS_BPS must be a comma-separated list of positive integers");
|
|
294329
|
+
}
|
|
294330
|
+
return normalizeOrderbookMeasurementBandsBps(parts.map(Number));
|
|
294331
|
+
}
|
|
294332
|
+
|
|
294060
294333
|
// src/helpers/market-data-archive/canonical-orderbook.ts
|
|
294334
|
+
var ORDERBOOK_SUMMARY_SCHEMA_VERSION = "2.0.0";
|
|
294335
|
+
|
|
294061
294336
|
class OrderBookValidationError extends Error {
|
|
294062
294337
|
reason;
|
|
294063
294338
|
constructor(reason) {
|
|
@@ -294083,38 +294358,70 @@ function parseSequence(value) {
|
|
|
294083
294358
|
}
|
|
294084
294359
|
return parsed.toString(10);
|
|
294085
294360
|
}
|
|
294086
|
-
function
|
|
294361
|
+
function validatePositiveInteger(value, field, maximum = Number.MAX_SAFE_INTEGER) {
|
|
294362
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > maximum) {
|
|
294363
|
+
throw new OrderBookValidationError(`${field} must be a positive integer${maximum === 500 ? " between 1 and 500" : ""}`);
|
|
294364
|
+
}
|
|
294365
|
+
}
|
|
294366
|
+
function validateSide(side, levels) {
|
|
294087
294367
|
if (levels.length === 0) {
|
|
294088
294368
|
throw new OrderBookValidationError(`${side} side is missing`);
|
|
294089
294369
|
}
|
|
294090
|
-
const
|
|
294091
|
-
for (let index2 = 0;index2 <
|
|
294092
|
-
const entry =
|
|
294370
|
+
const validated = [];
|
|
294371
|
+
for (let index2 = 0;index2 < levels.length; index2 += 1) {
|
|
294372
|
+
const entry = levels[index2];
|
|
294093
294373
|
const price = entry?.[0];
|
|
294094
294374
|
const amount = entry?.[1];
|
|
294095
294375
|
if (!Array.isArray(entry) || entry.length < 2 || price === undefined || amount === undefined || !Number.isFinite(price) || !Number.isFinite(amount) || price <= 0 || amount <= 0) {
|
|
294096
294376
|
throw new OrderBookValidationError(`${side} level ${index2} has a non-positive or non-finite price/amount`);
|
|
294097
294377
|
}
|
|
294098
294378
|
if (index2 > 0) {
|
|
294099
|
-
const previous =
|
|
294379
|
+
const previous = validated[index2 - 1]?.price;
|
|
294100
294380
|
if (previous === undefined || (side === "bid" ? price >= previous : price <= previous)) {
|
|
294101
294381
|
throw new OrderBookValidationError(`${side} levels are not strictly ${side === "bid" ? "descending" : "ascending"}`);
|
|
294102
294382
|
}
|
|
294103
294383
|
}
|
|
294384
|
+
validated.push({ price, amount });
|
|
294104
294385
|
}
|
|
294105
|
-
return
|
|
294106
|
-
price,
|
|
294107
|
-
amount
|
|
294108
|
-
}));
|
|
294386
|
+
return validated;
|
|
294109
294387
|
}
|
|
294110
|
-
function
|
|
294111
|
-
|
|
294112
|
-
|
|
294113
|
-
|
|
294114
|
-
|
|
294388
|
+
function validateMetadata(metadata, observedBids, observedAsks) {
|
|
294389
|
+
if (!metadata.captureProfileId.trim()) {
|
|
294390
|
+
throw new OrderBookValidationError("capture_profile_id must not be empty");
|
|
294391
|
+
}
|
|
294392
|
+
validatePositiveInteger(metadata.effectiveCadenceMs, "effective_cadence_ms");
|
|
294393
|
+
if (metadata.requestedUpstreamDepth !== null) {
|
|
294394
|
+
validatePositiveInteger(metadata.requestedUpstreamDepth, "requested_upstream_depth", 500);
|
|
294395
|
+
}
|
|
294396
|
+
validatePositiveInteger(metadata.observedBidCount, "observed_bid_count");
|
|
294397
|
+
validatePositiveInteger(metadata.observedAskCount, "observed_ask_count");
|
|
294398
|
+
if (metadata.observedBidCount !== observedBids.length) {
|
|
294399
|
+
throw new OrderBookValidationError("observed_bid_count does not match the complete observation");
|
|
294400
|
+
}
|
|
294401
|
+
if (metadata.observedAskCount !== observedAsks.length) {
|
|
294402
|
+
throw new OrderBookValidationError("observed_ask_count does not match the complete observation");
|
|
294403
|
+
}
|
|
294404
|
+
const farthestBid = observedBids.at(-1)?.price;
|
|
294405
|
+
const farthestAsk = observedAsks.at(-1)?.price;
|
|
294406
|
+
if (!Number.isFinite(metadata.observedFarthestBid) || metadata.observedFarthestBid <= 0 || metadata.observedFarthestBid !== farthestBid) {
|
|
294407
|
+
throw new OrderBookValidationError("observed_farthest_bid does not match the complete observation");
|
|
294408
|
+
}
|
|
294409
|
+
if (!Number.isFinite(metadata.observedFarthestAsk) || metadata.observedFarthestAsk <= 0 || metadata.observedFarthestAsk !== farthestAsk) {
|
|
294410
|
+
throw new OrderBookValidationError("observed_farthest_ask does not match the complete observation");
|
|
294411
|
+
}
|
|
294412
|
+
for (const [side, evidence] of [
|
|
294413
|
+
["bid", metadata.exhaustionEvidence.bid],
|
|
294414
|
+
["ask", metadata.exhaustionEvidence.ask]
|
|
294415
|
+
]) {
|
|
294416
|
+
if (evidence.validated !== true || typeof evidence.exhausted !== "boolean" || !evidence.source.trim()) {
|
|
294417
|
+
throw new OrderBookValidationError(`${side} exhaustion evidence must be validated and source-bound`);
|
|
294115
294418
|
}
|
|
294116
294419
|
}
|
|
294117
|
-
|
|
294420
|
+
try {
|
|
294421
|
+
return normalizeOrderbookMeasurementBandsBps(metadata.measurementBandsBps);
|
|
294422
|
+
} catch (error) {
|
|
294423
|
+
throw new OrderBookValidationError(error instanceof Error ? error.message : "invalid measurement bands");
|
|
294424
|
+
}
|
|
294118
294425
|
}
|
|
294119
294426
|
function checksumRow(row) {
|
|
294120
294427
|
return { ...row, normalized_row_checksum: sha256Canonical(row) };
|
|
@@ -294125,20 +294432,33 @@ function commonEvidenceFields(context2, rawCapture, input) {
|
|
|
294125
294432
|
source_time_ms: input.eventTimeMs,
|
|
294126
294433
|
received_time_ms: input.receivedTimeMs,
|
|
294127
294434
|
snapshot_id: input.snapshotId,
|
|
294128
|
-
construction_mode:
|
|
294435
|
+
construction_mode: "sampled_top_n_snapshot",
|
|
294129
294436
|
gap_policy: "record_gap",
|
|
294130
294437
|
depth_limit: input.depthLimit,
|
|
294131
294438
|
sequence: input.sequence,
|
|
294132
294439
|
exact_l2_reconstruction_complete: 0
|
|
294133
294440
|
};
|
|
294134
294441
|
}
|
|
294442
|
+
function sideBandEvidence(input) {
|
|
294443
|
+
const farthest = input.levels.at(-1)?.price;
|
|
294444
|
+
const depths = input.boundaries.map((boundary) => input.levels.filter(({ price }) => input.side === "bid" ? price >= boundary : price <= boundary).reduce((sum3, { amount }) => sum3 + amount, 0));
|
|
294445
|
+
const statuses = input.boundaries.map((boundary) => {
|
|
294446
|
+
const boundaryReached = input.side === "bid" ? farthest <= boundary : farthest >= boundary;
|
|
294447
|
+
return boundaryReached || input.exhausted ? "exact" : "censored";
|
|
294448
|
+
});
|
|
294449
|
+
return { depths, statuses };
|
|
294450
|
+
}
|
|
294135
294451
|
function buildCanonicalOrderBookRows(input) {
|
|
294136
|
-
|
|
294137
|
-
throw new OrderBookValidationError("depth limit must be an integer between 1 and 500");
|
|
294138
|
-
}
|
|
294452
|
+
validatePositiveInteger(input.depthLimit, "depth limit", 500);
|
|
294139
294453
|
if (input.context.feed !== "ORDERBOOK") {
|
|
294140
294454
|
throw new OrderBookValidationError("capture context feed is not ORDERBOOK");
|
|
294141
294455
|
}
|
|
294456
|
+
if (input.context.schemaVersion !== "1.0.0") {
|
|
294457
|
+
throw new OrderBookValidationError("ORDERBOOK raw and level capture schema must be 1.0.0");
|
|
294458
|
+
}
|
|
294459
|
+
if (!input.context.provenanceComplete) {
|
|
294460
|
+
throw new OrderBookValidationError("summary v2 requires complete live provenance");
|
|
294461
|
+
}
|
|
294142
294462
|
if (input.constructionMode === "exact_l2_reconstruction") {
|
|
294143
294463
|
throw new OrderBookValidationError("exact L2 requires a complete continuity proof and is unsupported");
|
|
294144
294464
|
}
|
|
@@ -294153,13 +294473,18 @@ function buildCanonicalOrderBookRows(input) {
|
|
|
294153
294473
|
if (receivedTimeMs < eventTimeMs) {
|
|
294154
294474
|
throw new OrderBookValidationError("received timestamp precedes source timestamp");
|
|
294155
294475
|
}
|
|
294156
|
-
const
|
|
294157
|
-
const
|
|
294158
|
-
const bestBid =
|
|
294159
|
-
const bestAsk =
|
|
294476
|
+
const observedBids = validateSide("bid", input.snapshot.bids);
|
|
294477
|
+
const observedAsks = validateSide("ask", input.snapshot.asks);
|
|
294478
|
+
const bestBid = observedBids[0];
|
|
294479
|
+
const bestAsk = observedAsks[0];
|
|
294160
294480
|
if (bestBid.price >= bestAsk.price) {
|
|
294161
294481
|
throw new OrderBookValidationError("book is crossed or locked");
|
|
294162
294482
|
}
|
|
294483
|
+
const bands = validateMetadata(input.archiveMetadata, observedBids, observedAsks);
|
|
294484
|
+
const bids = observedBids.slice(0, input.depthLimit);
|
|
294485
|
+
const asks = observedAsks.slice(0, input.depthLimit);
|
|
294486
|
+
const retainedFarthestBid = bids.at(-1);
|
|
294487
|
+
const retainedFarthestAsk = asks.at(-1);
|
|
294163
294488
|
const sequence = parseSequence(input.snapshot.sequence);
|
|
294164
294489
|
const midPrice = (bestBid.price + bestAsk.price) / 2;
|
|
294165
294490
|
const spread2 = bestAsk.price - bestBid.price;
|
|
@@ -294179,8 +294504,7 @@ function buildCanonicalOrderBookRows(input) {
|
|
|
294179
294504
|
sequence,
|
|
294180
294505
|
depthLimit: input.depthLimit,
|
|
294181
294506
|
eventTimeMs,
|
|
294182
|
-
receivedTimeMs
|
|
294183
|
-
constructionMode: input.constructionMode ?? "sampled_top_n_snapshot"
|
|
294507
|
+
receivedTimeMs
|
|
294184
294508
|
});
|
|
294185
294509
|
const levels = [
|
|
294186
294510
|
["bid", bids],
|
|
@@ -294198,17 +294522,34 @@ function buildCanonicalOrderBookRows(input) {
|
|
|
294198
294522
|
});
|
|
294199
294523
|
return { table: "market_data.cex_order_book_levels", row };
|
|
294200
294524
|
}));
|
|
294201
|
-
const
|
|
294202
|
-
const
|
|
294203
|
-
|
|
294204
|
-
|
|
294525
|
+
const bidBoundaries = bands.map((band) => midPrice * (1 - band / 1e4));
|
|
294526
|
+
const askBoundaries = bands.map((band) => midPrice * (1 + band / 1e4));
|
|
294527
|
+
const bidEvidence = sideBandEvidence({
|
|
294528
|
+
levels: observedBids,
|
|
294529
|
+
boundaries: bidBoundaries,
|
|
294530
|
+
side: "bid",
|
|
294531
|
+
exhausted: input.archiveMetadata.exhaustionEvidence.bid.exhausted
|
|
294205
294532
|
});
|
|
294206
|
-
const
|
|
294207
|
-
|
|
294208
|
-
|
|
294533
|
+
const askEvidence = sideBandEvidence({
|
|
294534
|
+
levels: observedAsks,
|
|
294535
|
+
boundaries: askBoundaries,
|
|
294536
|
+
side: "ask",
|
|
294537
|
+
exhausted: input.archiveMetadata.exhaustionEvidence.ask.exhausted
|
|
294209
294538
|
});
|
|
294210
294539
|
const summaryRow = checksumRow({
|
|
294211
294540
|
...common,
|
|
294541
|
+
schema_version: ORDERBOOK_SUMMARY_SCHEMA_VERSION,
|
|
294542
|
+
capture_profile_id: input.archiveMetadata.captureProfileId,
|
|
294543
|
+
effective_cadence_ms: input.archiveMetadata.effectiveCadenceMs,
|
|
294544
|
+
requested_upstream_depth: input.archiveMetadata.requestedUpstreamDepth,
|
|
294545
|
+
observed_bid_count: input.archiveMetadata.observedBidCount,
|
|
294546
|
+
observed_ask_count: input.archiveMetadata.observedAskCount,
|
|
294547
|
+
observed_farthest_bid: input.archiveMetadata.observedFarthestBid,
|
|
294548
|
+
observed_farthest_ask: input.archiveMetadata.observedFarthestAsk,
|
|
294549
|
+
retained_farthest_bid: retainedFarthestBid.price,
|
|
294550
|
+
retained_farthest_ask: retainedFarthestAsk.price,
|
|
294551
|
+
bid_exhausted: input.archiveMetadata.exhaustionEvidence.bid.exhausted ? 1 : 0,
|
|
294552
|
+
ask_exhausted: input.archiveMetadata.exhaustionEvidence.ask.exhausted ? 1 : 0,
|
|
294212
294553
|
best_bid: bestBid.price,
|
|
294213
294554
|
best_ask: bestAsk.price,
|
|
294214
294555
|
best_bid_amount: bestBid.amount,
|
|
@@ -294220,8 +294561,12 @@ function buildCanonicalOrderBookRows(input) {
|
|
|
294220
294561
|
bid_level_count: bids.length,
|
|
294221
294562
|
ask_level_count: asks.length,
|
|
294222
294563
|
measurement_bands_bps: bands,
|
|
294223
|
-
|
|
294224
|
-
|
|
294564
|
+
bid_boundary_price_by_band: bidBoundaries,
|
|
294565
|
+
ask_boundary_price_by_band: askBoundaries,
|
|
294566
|
+
bid_depth_by_band: bidEvidence.depths,
|
|
294567
|
+
ask_depth_by_band: askEvidence.depths,
|
|
294568
|
+
bid_status_by_band: bidEvidence.statuses,
|
|
294569
|
+
ask_status_by_band: askEvidence.statuses
|
|
294225
294570
|
});
|
|
294226
294571
|
return {
|
|
294227
294572
|
snapshotId,
|
|
@@ -294351,21 +294696,6 @@ class OhlcvBarTracker {
|
|
|
294351
294696
|
}
|
|
294352
294697
|
}
|
|
294353
294698
|
|
|
294354
|
-
// src/helpers/market-data-archive/orderbook-depth.ts
|
|
294355
|
-
var DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 25;
|
|
294356
|
-
var MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 500;
|
|
294357
|
-
function getOrderbookArchiveDepthLimit() {
|
|
294358
|
-
const raw = process.env.CEX_BROKER_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
|
|
294359
|
-
if (!raw) {
|
|
294360
|
-
return DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
|
|
294361
|
-
}
|
|
294362
|
-
const parsed = Number.parseInt(raw, 10);
|
|
294363
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
294364
|
-
return DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
|
|
294365
|
-
}
|
|
294366
|
-
return Math.min(parsed, MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT);
|
|
294367
|
-
}
|
|
294368
|
-
|
|
294369
294699
|
// src/helpers/market-data-archive/parse-stream.ts
|
|
294370
294700
|
function isFiniteNumber2(value) {
|
|
294371
294701
|
return typeof value === "number" && Number.isFinite(value);
|
|
@@ -294489,13 +294819,17 @@ function legacyMarketFields(context2, rawCapture) {
|
|
|
294489
294819
|
function legacyDecimal8(value) {
|
|
294490
294820
|
return value === undefined ? undefined : Number(value.toFixed(8));
|
|
294491
294821
|
}
|
|
294492
|
-
function buildCanonicalCexStreamEventRow(context2, rawCapture) {
|
|
294822
|
+
function buildCanonicalCexStreamEventRow(context2, rawCapture, options) {
|
|
294823
|
+
const payloadEncoding = options?.payloadEncoding ?? "canonical_json_v1";
|
|
294824
|
+
if (payloadEncoding === "orderbook_metadata_only_v1" && context2.feed !== "ORDERBOOK") {
|
|
294825
|
+
throw new Error("Metadata-only raw encoding requires an ORDERBOOK context");
|
|
294826
|
+
}
|
|
294493
294827
|
const row = withNormalizedChecksum({
|
|
294494
294828
|
...captureCoreFields(context2, rawCapture),
|
|
294495
294829
|
...legacyMarketFields(context2, rawCapture),
|
|
294496
294830
|
stream_type: context2.feed,
|
|
294497
294831
|
event_time_ms: rawCapture.eventTimeMs,
|
|
294498
|
-
payload_encoding:
|
|
294832
|
+
payload_encoding: payloadEncoding,
|
|
294499
294833
|
payload_json: canonicalSerialize(rawCapture.redactedPayload)
|
|
294500
294834
|
});
|
|
294501
294835
|
return { table: "market_data.cex_stream_events", row };
|
|
@@ -294639,7 +294973,13 @@ function archiveOrderbookInBackground(archiver, otelMetrics, input, options) {
|
|
|
294639
294973
|
queueMicrotask(() => {
|
|
294640
294974
|
try {
|
|
294641
294975
|
const context2 = resolveCaptureContext(archiver, input, "ORDERBOOK", options?.sourceMode ?? "broker_live_sampling_v1");
|
|
294642
|
-
const
|
|
294976
|
+
const depthLimit = options?.depthLimit ?? getOrderbookArchiveDepthLimit();
|
|
294977
|
+
const measurementBandsBps = normalizeOrderbookMeasurementBandsBps(input.archiveMetadata.measurementBandsBps);
|
|
294978
|
+
const archiveMetadata = {
|
|
294979
|
+
...input.archiveMetadata,
|
|
294980
|
+
measurementBandsBps
|
|
294981
|
+
};
|
|
294982
|
+
const completeRawCapture = createRawCapture(context2, {
|
|
294643
294983
|
payload: input.snapshot,
|
|
294644
294984
|
eventTimeMs: input.snapshot.timestamp,
|
|
294645
294985
|
receivedTimeMs: input.snapshot.receivedTimestamp,
|
|
@@ -294648,10 +294988,29 @@ function archiveOrderbookInBackground(archiver, otelMetrics, input, options) {
|
|
|
294648
294988
|
const canonical = buildCanonicalOrderBookRows({
|
|
294649
294989
|
context: context2,
|
|
294650
294990
|
snapshot: input.snapshot,
|
|
294651
|
-
rawCapture,
|
|
294652
|
-
depthLimit
|
|
294991
|
+
rawCapture: completeRawCapture,
|
|
294992
|
+
depthLimit,
|
|
294993
|
+
archiveMetadata
|
|
294653
294994
|
});
|
|
294654
|
-
|
|
294995
|
+
const rawMetadata = {
|
|
294996
|
+
capture_profile_id: archiveMetadata.captureProfileId,
|
|
294997
|
+
effective_cadence_ms: archiveMetadata.effectiveCadenceMs,
|
|
294998
|
+
requested_upstream_depth: archiveMetadata.requestedUpstreamDepth,
|
|
294999
|
+
archive_depth_limit: depthLimit,
|
|
295000
|
+
observed_bid_count: archiveMetadata.observedBidCount,
|
|
295001
|
+
observed_ask_count: archiveMetadata.observedAskCount,
|
|
295002
|
+
observed_farthest_bid: canonicalDecimal(archiveMetadata.observedFarthestBid),
|
|
295003
|
+
observed_farthest_ask: canonicalDecimal(archiveMetadata.observedFarthestAsk),
|
|
295004
|
+
bid_exhausted: archiveMetadata.exhaustionEvidence.bid.exhausted,
|
|
295005
|
+
ask_exhausted: archiveMetadata.exhaustionEvidence.ask.exhausted,
|
|
295006
|
+
retained_bid_count: canonical.levels.filter(({ row }) => row.side === "bid").length,
|
|
295007
|
+
retained_ask_count: canonical.levels.filter(({ row }) => row.side === "ask").length,
|
|
295008
|
+
measurement_bands_bps: measurementBandsBps
|
|
295009
|
+
};
|
|
295010
|
+
const storedRawCapture = projectRawCapturePayload(completeRawCapture, rawMetadata);
|
|
295011
|
+
archiver.enqueue(buildCanonicalCexStreamEventRow(context2, storedRawCapture, {
|
|
295012
|
+
payloadEncoding: "orderbook_metadata_only_v1"
|
|
295013
|
+
}));
|
|
294655
295014
|
for (const row of canonical.levels)
|
|
294656
295015
|
archiver.enqueue(row);
|
|
294657
295016
|
archiver.enqueue(canonical.summary);
|
|
@@ -294773,6 +295132,9 @@ function archiveTickerInBackground(archiver, otelMetrics, input) {
|
|
|
294773
295132
|
});
|
|
294774
295133
|
}
|
|
294775
295134
|
function archiveCexStreamEventInBackground(archiver, otelMetrics, input) {
|
|
295135
|
+
if (input.streamType === "ORDERBOOK") {
|
|
295136
|
+
throw new Error("Generic ORDERBOOK archive events are unsupported; use archiveOrderbookInBackground");
|
|
295137
|
+
}
|
|
294776
295138
|
archiveMarketRowsInBackground(archiver, otelMetrics, "stream", input, input.streamType, () => [
|
|
294777
295139
|
buildCexStreamEventRow({
|
|
294778
295140
|
...input,
|
|
@@ -294797,6 +295159,82 @@ function resolveOhlcvBootstrapLimit(optionValue) {
|
|
|
294797
295159
|
}
|
|
294798
295160
|
return Math.min(parsed, MAX_OHLCV_BOOTSTRAP_LIMIT);
|
|
294799
295161
|
}
|
|
295162
|
+
// src/helpers/market-data-archive/summary-v2-conformance.ts
|
|
295163
|
+
var ORDERBOOK_SUMMARY_V2_SUPPORTED_VIEW_FIELDS = [
|
|
295164
|
+
["source", "String", false],
|
|
295165
|
+
["deployment_id", "String", false],
|
|
295166
|
+
["capture_bundle_id", "String", false],
|
|
295167
|
+
["exchange", "String", false],
|
|
295168
|
+
["symbol", "String", false],
|
|
295169
|
+
["trading_pair", "String", false],
|
|
295170
|
+
["source_symbol", "String", false],
|
|
295171
|
+
["asset_type", "String", false],
|
|
295172
|
+
["feed", "String", false],
|
|
295173
|
+
["provider", "String", false],
|
|
295174
|
+
["source_mode", "String", false],
|
|
295175
|
+
["source_time_ms", "UInt64", false],
|
|
295176
|
+
["received_time_ms", "UInt64", false],
|
|
295177
|
+
["raw_capture_id", "String", false],
|
|
295178
|
+
["raw_capture_scope", "String", false],
|
|
295179
|
+
["schema_version", "String", false],
|
|
295180
|
+
["checksum_algorithm", "String", false],
|
|
295181
|
+
["raw_checksum", "String", false],
|
|
295182
|
+
["provenance_complete", "UInt8", false],
|
|
295183
|
+
["snapshot_id", "String", false],
|
|
295184
|
+
["construction_mode", "String", false],
|
|
295185
|
+
["gap_policy", "String", false],
|
|
295186
|
+
["depth_limit", "UInt16", false],
|
|
295187
|
+
["sequence", "UInt64", true],
|
|
295188
|
+
["exact_l2_reconstruction_complete", "UInt8", false],
|
|
295189
|
+
["capture_profile_id", "String", false],
|
|
295190
|
+
["effective_cadence_ms", "UInt32", false],
|
|
295191
|
+
["requested_upstream_depth", "UInt16", true],
|
|
295192
|
+
["observed_bid_count", "UInt32", false],
|
|
295193
|
+
["observed_ask_count", "UInt32", false],
|
|
295194
|
+
["observed_farthest_bid", "Decimal(38,18)", false],
|
|
295195
|
+
["observed_farthest_ask", "Decimal(38,18)", false],
|
|
295196
|
+
["retained_farthest_bid", "Decimal(38,18)", false],
|
|
295197
|
+
["retained_farthest_ask", "Decimal(38,18)", false],
|
|
295198
|
+
["bid_exhausted", "UInt8", false],
|
|
295199
|
+
["ask_exhausted", "UInt8", false],
|
|
295200
|
+
["best_bid", "Decimal(38,18)", false],
|
|
295201
|
+
["best_ask", "Decimal(38,18)", false],
|
|
295202
|
+
["best_bid_amount", "Decimal(38,18)", false],
|
|
295203
|
+
["best_ask_amount", "Decimal(38,18)", false],
|
|
295204
|
+
["mid_price", "Decimal(38,18)", false],
|
|
295205
|
+
["spread", "Decimal(38,18)", false],
|
|
295206
|
+
["spread_bps", "Float64", false],
|
|
295207
|
+
["staleness_ms", "UInt64", false],
|
|
295208
|
+
["bid_level_count", "UInt16", false],
|
|
295209
|
+
["ask_level_count", "UInt16", false],
|
|
295210
|
+
["measurement_bands_bps", "Array(UInt32)", false],
|
|
295211
|
+
["bid_boundary_price_by_band", "Array(Decimal(38,18))", false],
|
|
295212
|
+
["ask_boundary_price_by_band", "Array(Decimal(38,18))", false],
|
|
295213
|
+
["bid_depth_by_band", "Array(Decimal(38,18))", false],
|
|
295214
|
+
["ask_depth_by_band", "Array(Decimal(38,18))", false],
|
|
295215
|
+
["bid_status_by_band", "Array(Enum8('exact'=1,'censored'=2))", false],
|
|
295216
|
+
["ask_status_by_band", "Array(Enum8('exact'=1,'censored'=2))", false],
|
|
295217
|
+
["normalized_row_checksum", "String", false]
|
|
295218
|
+
];
|
|
295219
|
+
var ORDERBOOK_SUMMARY_V2_SUPPORTED_VIEW_FIELD_NAMES = ORDERBOOK_SUMMARY_V2_SUPPORTED_VIEW_FIELDS.map(([name]) => name);
|
|
295220
|
+
var DECIMAL_38_18_FIELDS = new Set([
|
|
295221
|
+
"observed_farthest_bid",
|
|
295222
|
+
"observed_farthest_ask",
|
|
295223
|
+
"retained_farthest_bid",
|
|
295224
|
+
"retained_farthest_ask",
|
|
295225
|
+
"best_bid",
|
|
295226
|
+
"best_ask",
|
|
295227
|
+
"best_bid_amount",
|
|
295228
|
+
"best_ask_amount",
|
|
295229
|
+
"mid_price",
|
|
295230
|
+
"spread"
|
|
295231
|
+
]);
|
|
295232
|
+
var DECIMAL_38_18_ARRAY_FIELDS = new Set([
|
|
295233
|
+
"bid_boundary_price_by_band",
|
|
295234
|
+
"ask_boundary_price_by_band",
|
|
295235
|
+
"bid_depth_by_band",
|
|
295236
|
+
"ask_depth_by_band"
|
|
295237
|
+
]);
|
|
294800
295238
|
// src/helpers/order-book.ts
|
|
294801
295239
|
var ORDER_BOOK_CALL_METHODS = {
|
|
294802
295240
|
FETCH_CAPABILITY: "fetch_order_book_capability",
|
|
@@ -295148,7 +295586,7 @@ class PublicFeedWorker {
|
|
|
295148
295586
|
if (this.options.profile) {
|
|
295149
295587
|
this.options.metrics?.recordCounter("public_feed_acquisition_profiles_total", 1, {
|
|
295150
295588
|
...this.#metricLabels(),
|
|
295151
|
-
|
|
295589
|
+
profile_class: this.options.profile.coalescingSupported ? "coalesced" : "conservative"
|
|
295152
295590
|
});
|
|
295153
295591
|
}
|
|
295154
295592
|
this.#run = this.#watchLoop();
|
|
@@ -295216,7 +295654,34 @@ class PublicFeedWorker {
|
|
|
295216
295654
|
depthLimit: retainedDepth,
|
|
295217
295655
|
receivedTimestamp
|
|
295218
295656
|
});
|
|
295219
|
-
|
|
295657
|
+
const observedBidCount = snapshot.bids.length;
|
|
295658
|
+
const observedAskCount = snapshot.asks.length;
|
|
295659
|
+
this.options.archiveSink.orderbook({
|
|
295660
|
+
...context2,
|
|
295661
|
+
snapshot,
|
|
295662
|
+
archiveMetadata: {
|
|
295663
|
+
captureProfileId: this.options.profile?.id ?? `${this.options.exchangeName}:conservative:default`,
|
|
295664
|
+
effectiveCadenceMs: getOrderbookIntervalMs(),
|
|
295665
|
+
requestedUpstreamDepth: this.options.profile?.upstreamLimit ?? null,
|
|
295666
|
+
observedBidCount,
|
|
295667
|
+
observedAskCount,
|
|
295668
|
+
observedFarthestBid: snapshot.bids.at(-1)?.[0] ?? Number.NaN,
|
|
295669
|
+
observedFarthestAsk: snapshot.asks.at(-1)?.[0] ?? Number.NaN,
|
|
295670
|
+
exhaustionEvidence: {
|
|
295671
|
+
bid: {
|
|
295672
|
+
exhausted: this.options.profile?.bidExhaustionEvidence ?? false,
|
|
295673
|
+
validated: this.options.profile?.exhaustionEvidenceValidated ?? true,
|
|
295674
|
+
source: this.options.profile?.id ?? "broker:conservative"
|
|
295675
|
+
},
|
|
295676
|
+
ask: {
|
|
295677
|
+
exhausted: this.options.profile?.askExhaustionEvidence ?? false,
|
|
295678
|
+
validated: this.options.profile?.exhaustionEvidenceValidated ?? true,
|
|
295679
|
+
source: this.options.profile?.id ?? "broker:conservative"
|
|
295680
|
+
}
|
|
295681
|
+
},
|
|
295682
|
+
measurementBandsBps: getOrderbookMeasurementBandsBps()
|
|
295683
|
+
}
|
|
295684
|
+
}, { sampledOut: !this.#sampler.shouldEmit(receivedTimestamp) });
|
|
295220
295685
|
this.#recordCounter("public_feed_archive_decisions_total");
|
|
295221
295686
|
this.options.observer?.archiveDecision?.(this.#observation());
|
|
295222
295687
|
this.#fanout((subscriber) => this.#frame(projectOrderBookSnapshot(snapshot, subscriber.depthLimit), receivedTimestamp));
|
|
@@ -295389,7 +295854,7 @@ class PublicFeedWorker {
|
|
|
295389
295854
|
}
|
|
295390
295855
|
#metricLabels() {
|
|
295391
295856
|
return {
|
|
295392
|
-
|
|
295857
|
+
exchange_bucket: this.options.exchangeOwned ? "dynamic" : "configured",
|
|
295393
295858
|
feed: this.options.feed,
|
|
295394
295859
|
market_type: this.options.marketType
|
|
295395
295860
|
};
|
|
@@ -310756,7 +311221,29 @@ async function handleOrderBookCall(ctx) {
|
|
|
310756
311221
|
assetType: "spot",
|
|
310757
311222
|
accountSelector: ctx.selectedBrokerAccount?.label,
|
|
310758
311223
|
deploymentId: ctx.brokerArchiver?.getDeploymentId() ?? "unarchived",
|
|
310759
|
-
snapshot
|
|
311224
|
+
snapshot,
|
|
311225
|
+
archiveMetadata: {
|
|
311226
|
+
captureProfileId: `${orderBookPayload.exchange.trim().toLowerCase()}:current-snapshot:requested:${orderBookPayload.depthLimit}`,
|
|
311227
|
+
effectiveCadenceMs: 1,
|
|
311228
|
+
requestedUpstreamDepth: orderBookPayload.depthLimit,
|
|
311229
|
+
observedBidCount: snapshot.bids.length,
|
|
311230
|
+
observedAskCount: snapshot.asks.length,
|
|
311231
|
+
observedFarthestBid: snapshot.bids.at(-1)?.[0] ?? Number.NaN,
|
|
311232
|
+
observedFarthestAsk: snapshot.asks.at(-1)?.[0] ?? Number.NaN,
|
|
311233
|
+
exhaustionEvidence: {
|
|
311234
|
+
bid: {
|
|
311235
|
+
exhausted: false,
|
|
311236
|
+
validated: true,
|
|
311237
|
+
source: "broker:current-snapshot"
|
|
311238
|
+
},
|
|
311239
|
+
ask: {
|
|
311240
|
+
exhausted: false,
|
|
311241
|
+
validated: true,
|
|
311242
|
+
source: "broker:current-snapshot"
|
|
311243
|
+
}
|
|
311244
|
+
},
|
|
311245
|
+
measurementBandsBps: getOrderbookMeasurementBandsBps()
|
|
311246
|
+
}
|
|
310760
311247
|
}, {
|
|
310761
311248
|
sourceMode: "broker_current_snapshot_v1",
|
|
310762
311249
|
depthLimit: orderBookPayload.depthLimit
|
|
@@ -313345,4 +313832,4 @@ export {
|
|
|
313345
313832
|
CEXBroker as default
|
|
313346
313833
|
};
|
|
313347
313834
|
|
|
313348
|
-
//# debugId=
|
|
313835
|
+
//# debugId=46EFCE207D029E0F64756E2164756E21
|