@usherlabs/cex-broker 0.2.50 → 0.2.52
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/cex-canonical-orderbook-export.js +7750 -920
- package/dist/commands/cex-canonical-orderbook-export.js.map +41 -10
- package/dist/commands/cli.js +219 -24
- package/dist/commands/market-data-vendor-backfill.js +8297 -6460
- package/dist/commands/market-data-vendor-backfill.js.map +16 -15
- package/dist/helpers/canonical-orderbook-export/parquet-projection.d.ts +19 -0
- package/dist/helpers/deposit-archive-poller.d.ts +33 -0
- package/dist/helpers/market-data-archive/canonical-orderbook.d.ts +1 -1
- package/dist/helpers/market-data-preparation/conformance-fixtures.d.ts +114 -2
- package/dist/helpers/market-data-preparation/contracts.d.ts +1298 -18
- package/dist/helpers/market-data-preparation/required-clock-qualification.d.ts +43 -0
- package/dist/helpers/market-data-preparation/source-tape-dependencies.d.ts +19 -0
- package/dist/helpers/market-data-preparation/source-tape-operation.d.ts +109 -0
- package/dist/helpers/market-data-source-forensics.d.ts +400 -0
- package/dist/helpers/market-data-vendor-backfill/conformance-fixtures.d.ts +3 -5
- package/dist/helpers/market-data-vendor-backfill/contracts.d.ts +21 -56
- package/dist/helpers/market-data-vendor-backfill/core.d.ts +1 -0
- package/dist/helpers/market-data-vendor-backfill/cryptohftdata.d.ts +44 -5
- package/dist/helpers/market-data-vendor-backfill/manifests.d.ts +33 -1112
- package/dist/helpers/market-data-vendor-backfill/promotion.d.ts +1 -0
- package/dist/helpers/source-tape-sandbox.d.ts +82 -0
- package/dist/helpers/source-tape.d.ts +165 -0
- package/dist/index.js +220 -25
- package/dist/index.js.map +4 -4
- package/dist/market-data-preparation/fixtures/{conformance-v2.json → conformance-v3.json} +253 -56
- package/dist/market-data-preparation/policies/capability-policy.json +4 -4
- package/dist/market-data-preparation/policies/source-tape-capability-v1.json +35 -0
- package/dist/market-data-preparation/schema-manifest.json +30 -10
- package/dist/market-data-preparation/schemas/canonical-orderbook-export-request-v1.schema.json +5 -1
- package/dist/market-data-preparation/schemas/{canonical-orderbook-export-result-v1.schema.json → canonical-orderbook-export-result-v2.schema.json} +20 -6
- package/dist/market-data-preparation/schemas/order-book-depth-summary-parquet-projection-v1.schema.json +256 -0
- package/dist/market-data-preparation/schemas/order-book-levels-parquet-projection-v1.schema.json +220 -0
- package/dist/market-data-preparation/schemas/{preparation-product-pin-v1.schema.json → preparation-product-pin-v2.schema.json} +59 -9
- package/dist/market-data-preparation/schemas/promotion-receipt-v1.schema.json +5 -1
- package/dist/market-data-preparation/schemas/source-forensics-ledger-v1.schema.json +463 -0
- package/dist/market-data-preparation/schemas/source-qualification-record-v1.schema.json +394 -0
- package/dist/market-data-preparation.d.ts +7 -0
- package/dist/market-data-preparation.js +35448 -25240
- package/dist/market-data-preparation.js.map +118 -78
- package/dist/market-data-vendor-backfill.d.ts +7 -4
- package/dist/market-data-vendor-backfill.js +19338 -15503
- package/dist/market-data-vendor-backfill.js.map +65 -60
- package/package.json +1 -5
- package/dist/market-data-preparation/policies/capability-policy-v1.json +0 -28
- package/dist/market-data-preparation/policies/resource-policy-v1.json +0 -16
- package/dist/market-data-vendor-backfill/fixtures/conformance-v1.json +0 -448
- package/dist/market-data-vendor-backfill/policies/capability-policy-v2.json +0 -39
- package/dist/market-data-vendor-backfill/policies/capability-policy.json +0 -28
- package/dist/market-data-vendor-backfill/policies/resource-policy-v2.json +0 -16
- package/dist/market-data-vendor-backfill/policies/resource-policy.json +0 -16
- package/dist/market-data-vendor-backfill/schema-manifest.json +0 -31
- package/dist/market-data-vendor-backfill/schemas/archive-selection.schema.json +0 -224
- package/dist/market-data-vendor-backfill/schemas/promotion-receipt.schema.json +0 -171
- package/dist/market-data-vendor-backfill/schemas/request.schema.json +0 -166
- package/dist/market-data-vendor-backfill/schemas/required-clock.schema.json +0 -47
- package/dist/market-data-vendor-backfill/schemas/result.schema.json +0 -198
package/dist/commands/cli.js
CHANGED
|
@@ -317211,6 +317211,16 @@ function withTimeout(promise, timeoutMs, label) {
|
|
|
317211
317211
|
return Promise.race([promise, expiry]).finally(() => clearTimeout(timer));
|
|
317212
317212
|
}
|
|
317213
317213
|
var ALL_CURRENCIES_CODE = "*";
|
|
317214
|
+
var BINANCE_UNLOCK_PROGRESS_SOURCE = {
|
|
317215
|
+
venue: "binance",
|
|
317216
|
+
endpoint: "GET /sapi/v1/capital/deposit/hisrec",
|
|
317217
|
+
fields: {
|
|
317218
|
+
status: "info.status",
|
|
317219
|
+
confirmTimes: "info.confirmTimes",
|
|
317220
|
+
unlockConfirm: "info.unlockConfirm",
|
|
317221
|
+
completeTime: "info.completeTime"
|
|
317222
|
+
}
|
|
317223
|
+
};
|
|
317214
317224
|
function depositTimestamp(record) {
|
|
317215
317225
|
const observedAt = depositField(record, [
|
|
317216
317226
|
"timestamp",
|
|
@@ -317223,12 +317233,185 @@ function depositTimestamp(record) {
|
|
|
317223
317233
|
const timestamp = typeof observedAt === "number" ? observedAt : typeof observedAt === "string" ? Date.parse(observedAt) : Number.NaN;
|
|
317224
317234
|
return Number.isFinite(timestamp) ? timestamp : undefined;
|
|
317225
317235
|
}
|
|
317226
|
-
function
|
|
317227
|
-
|
|
317228
|
-
|
|
317229
|
-
|
|
317236
|
+
function parseNonNegativeInteger(value) {
|
|
317237
|
+
if (typeof value === "number") {
|
|
317238
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
317239
|
+
}
|
|
317240
|
+
if (typeof value !== "string") {
|
|
317241
|
+
return;
|
|
317242
|
+
}
|
|
317243
|
+
const trimmed = value.trim();
|
|
317244
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
317245
|
+
return;
|
|
317246
|
+
}
|
|
317247
|
+
const parsed = Number(trimmed);
|
|
317248
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : undefined;
|
|
317249
|
+
}
|
|
317250
|
+
function parseConfirmTimes(value) {
|
|
317251
|
+
if (value === undefined || value === null) {
|
|
317252
|
+
return { reason: "missing_confirmTimes" };
|
|
317253
|
+
}
|
|
317254
|
+
let currentValue;
|
|
317255
|
+
let creditRequiredValue;
|
|
317256
|
+
if (typeof value === "string") {
|
|
317257
|
+
const match = /^(\d+)\s*\/\s*(\d+)$/.exec(value.trim());
|
|
317258
|
+
if (!match) {
|
|
317259
|
+
return { reason: "invalid_confirmTimes" };
|
|
317260
|
+
}
|
|
317261
|
+
currentValue = match[1];
|
|
317262
|
+
creditRequiredValue = match[2];
|
|
317263
|
+
} else {
|
|
317264
|
+
const record = asRecord(value);
|
|
317265
|
+
if (!record) {
|
|
317266
|
+
return { reason: "invalid_confirmTimes" };
|
|
317267
|
+
}
|
|
317268
|
+
currentValue = record.current;
|
|
317269
|
+
creditRequiredValue = record.credit_required;
|
|
317270
|
+
}
|
|
317271
|
+
const current = parseNonNegativeInteger(currentValue);
|
|
317272
|
+
const creditRequired = parseNonNegativeInteger(creditRequiredValue);
|
|
317273
|
+
if (current === undefined || creditRequired === undefined) {
|
|
317274
|
+
return { reason: "invalid_confirmTimes" };
|
|
317275
|
+
}
|
|
317276
|
+
return { current, creditRequired, reason: null };
|
|
317277
|
+
}
|
|
317278
|
+
function parseOptionalNonNegativeInteger(value, fieldName) {
|
|
317279
|
+
if (value === undefined || value === null) {
|
|
317280
|
+
return { value: undefined, reason: null };
|
|
317281
|
+
}
|
|
317282
|
+
const parsed = parseNonNegativeInteger(value);
|
|
317283
|
+
return parsed === undefined ? { value: undefined, reason: `invalid_${fieldName}` } : { value: parsed, reason: null };
|
|
317284
|
+
}
|
|
317285
|
+
function parseBinanceUnlockProgress(record) {
|
|
317286
|
+
const info = asRecord(record.info);
|
|
317287
|
+
const nativeStatus = parseNonNegativeInteger(info?.status);
|
|
317288
|
+
const confirmations = parseConfirmTimes(info?.confirmTimes);
|
|
317289
|
+
const unlockRequired = parseOptionalNonNegativeInteger(info?.unlockConfirm, "unlockConfirm");
|
|
317290
|
+
const completeTime = parseOptionalNonNegativeInteger(info?.completeTime, "completeTime");
|
|
317291
|
+
let quality = "valid";
|
|
317292
|
+
let reason = null;
|
|
317293
|
+
if (nativeStatus === undefined) {
|
|
317294
|
+
quality = "unknown";
|
|
317295
|
+
reason = "missing_or_invalid_status";
|
|
317296
|
+
} else if (confirmations.reason !== null) {
|
|
317297
|
+
quality = "unknown";
|
|
317298
|
+
reason = confirmations.reason;
|
|
317299
|
+
} else if (unlockRequired.reason !== null) {
|
|
317300
|
+
quality = "unknown";
|
|
317301
|
+
reason = unlockRequired.reason;
|
|
317302
|
+
} else if (completeTime.reason !== null) {
|
|
317303
|
+
quality = "unknown";
|
|
317304
|
+
reason = completeTime.reason;
|
|
317305
|
+
}
|
|
317306
|
+
let state = "unknown";
|
|
317307
|
+
switch (nativeStatus) {
|
|
317308
|
+
case 0:
|
|
317309
|
+
state = "pending";
|
|
317310
|
+
break;
|
|
317311
|
+
case 1:
|
|
317312
|
+
if (quality === "valid" && confirmations.current !== undefined && unlockRequired.value !== undefined && confirmations.current >= unlockRequired.value) {
|
|
317313
|
+
state = "ok";
|
|
317314
|
+
} else if (quality === "valid") {
|
|
317315
|
+
state = "credited_not_withdrawable";
|
|
317316
|
+
}
|
|
317317
|
+
break;
|
|
317318
|
+
case 2:
|
|
317319
|
+
case 7:
|
|
317320
|
+
state = "failed";
|
|
317321
|
+
break;
|
|
317322
|
+
case 6:
|
|
317323
|
+
state = "credited_not_withdrawable";
|
|
317324
|
+
break;
|
|
317325
|
+
case 8:
|
|
317326
|
+
state = "pending";
|
|
317327
|
+
break;
|
|
317328
|
+
default:
|
|
317329
|
+
quality = "unknown";
|
|
317330
|
+
reason = "unsupported_status";
|
|
317331
|
+
break;
|
|
317332
|
+
}
|
|
317333
|
+
return {
|
|
317334
|
+
version: 1,
|
|
317335
|
+
state,
|
|
317336
|
+
progress_state: quality,
|
|
317337
|
+
reason,
|
|
317338
|
+
native_status: nativeStatus ?? null,
|
|
317339
|
+
current: confirmations.current ?? null,
|
|
317340
|
+
credit_required: confirmations.creditRequired ?? null,
|
|
317341
|
+
unlock_required: unlockRequired.value ?? null,
|
|
317342
|
+
complete_time: completeTime.value ?? null,
|
|
317343
|
+
observed_at: new Date().toISOString(),
|
|
317344
|
+
source: BINANCE_UNLOCK_PROGRESS_SOURCE
|
|
317345
|
+
};
|
|
317346
|
+
}
|
|
317347
|
+
function unlockProgressKey(progress) {
|
|
317348
|
+
return JSON.stringify({
|
|
317349
|
+
version: progress.version,
|
|
317350
|
+
state: progress.state,
|
|
317351
|
+
progress_state: progress.progress_state,
|
|
317352
|
+
reason: progress.reason,
|
|
317353
|
+
native_status: progress.native_status,
|
|
317354
|
+
current: progress.current,
|
|
317355
|
+
credit_required: progress.credit_required,
|
|
317356
|
+
unlock_required: progress.unlock_required,
|
|
317357
|
+
complete_time: progress.complete_time
|
|
317358
|
+
});
|
|
317359
|
+
}
|
|
317360
|
+
function progressWatermark(progress, previous) {
|
|
317361
|
+
if (progress.progress_state !== "valid" || progress.current === null || progress.credit_required === null || progress.unlock_required === null) {
|
|
317362
|
+
return previous;
|
|
317363
|
+
}
|
|
317364
|
+
return {
|
|
317365
|
+
current: Math.max(previous?.current ?? 0, progress.current),
|
|
317366
|
+
credit_required: progress.credit_required,
|
|
317367
|
+
unlock_required: progress.unlock_required
|
|
317368
|
+
};
|
|
317369
|
+
}
|
|
317370
|
+
function classifyBinanceDeposit(record, previous) {
|
|
317371
|
+
let progress = parseBinanceUnlockProgress(record);
|
|
317372
|
+
let highWatermark = previous?.highWatermark;
|
|
317373
|
+
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)) {
|
|
317374
|
+
progress = {
|
|
317375
|
+
...progress,
|
|
317376
|
+
state: "unknown",
|
|
317377
|
+
progress_state: "contradictory",
|
|
317378
|
+
reason: "confirmation_progress_regressed_or_requirement_changed"
|
|
317379
|
+
};
|
|
317380
|
+
} else {
|
|
317381
|
+
highWatermark = progressWatermark(progress, previous?.highWatermark);
|
|
317382
|
+
}
|
|
317383
|
+
return {
|
|
317384
|
+
archiveStatus: progress.state,
|
|
317385
|
+
holdCursor: progress.state === "pending" || progress.state === "credited_not_withdrawable" || progress.state === "unknown",
|
|
317386
|
+
unlockProgress: progress,
|
|
317387
|
+
progressKey: unlockProgressKey(progress),
|
|
317388
|
+
highWatermark
|
|
317389
|
+
};
|
|
317390
|
+
}
|
|
317391
|
+
function classifyDeposit(exchangeId, record, previous) {
|
|
317392
|
+
if (exchangeId?.toLowerCase() === "binance") {
|
|
317393
|
+
return classifyBinanceDeposit(record, previous);
|
|
317394
|
+
}
|
|
317395
|
+
const archiveStatus = normalizeCcxtTransactionForArchive(record).status ?? "";
|
|
317396
|
+
const status = normalizeDepositStatus(depositField(record, ["status", "state"]));
|
|
317397
|
+
return {
|
|
317398
|
+
archiveStatus,
|
|
317399
|
+
holdCursor: archiveStatus === "credited_not_withdrawable" || status === "pending",
|
|
317400
|
+
progressKey: JSON.stringify({ status: archiveStatus })
|
|
317401
|
+
};
|
|
317402
|
+
}
|
|
317403
|
+
function depositIdentity(input) {
|
|
317404
|
+
if (input.externalId === undefined && input.txid === undefined) {
|
|
317405
|
+
return;
|
|
317230
317406
|
}
|
|
317231
|
-
return
|
|
317407
|
+
return JSON.stringify({
|
|
317408
|
+
exchange: input.exchangeId,
|
|
317409
|
+
account: input.accountSelector,
|
|
317410
|
+
coin: input.coin === undefined ? "" : String(input.coin),
|
|
317411
|
+
network: input.network === undefined ? "" : String(input.network),
|
|
317412
|
+
external_id: input.externalId ?? "",
|
|
317413
|
+
txid: input.txid ?? ""
|
|
317414
|
+
});
|
|
317232
317415
|
}
|
|
317233
317416
|
function nextDepositCursor(deposits, currentSince, depositsLimit, exchangeId) {
|
|
317234
317417
|
if (deposits.length >= depositsLimit) {
|
|
@@ -317242,9 +317425,8 @@ function nextDepositCursor(deposits, currentSince, depositsLimit, exchangeId) {
|
|
|
317242
317425
|
return currentSince;
|
|
317243
317426
|
}
|
|
317244
317427
|
const timestamp = depositTimestamp(record);
|
|
317245
|
-
const
|
|
317246
|
-
const
|
|
317247
|
-
const isPending = archiveStatus === "credited_not_withdrawable" || status === "pending";
|
|
317428
|
+
const classification = classifyDeposit(exchangeId, record);
|
|
317429
|
+
const isPending = classification.holdCursor;
|
|
317248
317430
|
if (timestamp === undefined) {
|
|
317249
317431
|
if (isPending) {
|
|
317250
317432
|
return currentSince;
|
|
@@ -317364,7 +317546,8 @@ class DepositArchivePoller {
|
|
|
317364
317546
|
if (!record) {
|
|
317365
317547
|
continue;
|
|
317366
317548
|
}
|
|
317367
|
-
const
|
|
317549
|
+
const info = asRecord(record.info);
|
|
317550
|
+
const assetSymbol = depositField(record, ["currency", "code", "asset"]) ?? info?.coin;
|
|
317368
317551
|
const amount = depositField(record, ["amount"]);
|
|
317369
317552
|
const address = depositField(record, [
|
|
317370
317553
|
"address",
|
|
@@ -317373,8 +317556,21 @@ class DepositArchivePoller {
|
|
|
317373
317556
|
"destination"
|
|
317374
317557
|
]);
|
|
317375
317558
|
const txid = depositField(record, ["txid", "txId", "tx_hash", "txHash"]);
|
|
317376
|
-
const network = depositField(record, ["network", "chain"]);
|
|
317377
|
-
const
|
|
317559
|
+
const network = depositField(record, ["network", "chain"]) ?? info?.network;
|
|
317560
|
+
const depositTxid = txid === undefined ? undefined : String(txid);
|
|
317561
|
+
const identity = depositIdentity({
|
|
317562
|
+
exchangeId: target.exchangeId,
|
|
317563
|
+
accountSelector: target.account.label,
|
|
317564
|
+
coin: assetSymbol,
|
|
317565
|
+
network,
|
|
317566
|
+
externalId: depositTxid,
|
|
317567
|
+
txid: depositTxid
|
|
317568
|
+
});
|
|
317569
|
+
const lastArchived = identity === undefined ? undefined : this.#lastArchivedByTarget.get(key)?.get(identity);
|
|
317570
|
+
const classification = classifyDeposit(target.exchangeId, record, lastArchived);
|
|
317571
|
+
if (lastArchived && lastArchived.status === classification.archiveStatus && lastArchived.progressKey === classification.progressKey) {
|
|
317572
|
+
continue;
|
|
317573
|
+
}
|
|
317378
317574
|
const creditedAt = depositField(record, [
|
|
317379
317575
|
"creditedAt",
|
|
317380
317576
|
"credited_at",
|
|
@@ -317383,11 +317579,7 @@ class DepositArchivePoller {
|
|
|
317383
317579
|
"timestamp",
|
|
317384
317580
|
"datetime"
|
|
317385
317581
|
]);
|
|
317386
|
-
const
|
|
317387
|
-
const lastArchived = depositTxid === undefined ? undefined : this.#lastArchivedByTarget.get(key)?.get(depositTxid);
|
|
317388
|
-
if (lastArchived && lastArchived.status === archiveStatus) {
|
|
317389
|
-
continue;
|
|
317390
|
-
}
|
|
317582
|
+
const payload = classification.unlockProgress === undefined ? record : { ...record, unlock_progress: classification.unlockProgress };
|
|
317391
317583
|
this.params.archiver.enqueue(buildTransferEventArchiveRow({
|
|
317392
317584
|
tags: buildCommonArchiveTags({
|
|
317393
317585
|
deploymentId: this.params.archiver.getDeploymentId(),
|
|
@@ -317398,25 +317590,27 @@ class DepositArchivePoller {
|
|
|
317398
317590
|
transfer: {
|
|
317399
317591
|
eventKind: "deposit",
|
|
317400
317592
|
lifecycleAction: "observe_deposit",
|
|
317401
|
-
status: archiveStatus,
|
|
317593
|
+
status: classification.archiveStatus,
|
|
317402
317594
|
amount: amount === undefined ? undefined : String(amount),
|
|
317403
317595
|
address: address === undefined ? undefined : String(address),
|
|
317404
317596
|
network: network === undefined ? undefined : String(network),
|
|
317405
317597
|
externalId: depositTxid,
|
|
317406
317598
|
txid: depositTxid,
|
|
317407
317599
|
exchangeTimestamp: normalizeTimestamp(creditedAt),
|
|
317408
|
-
payload
|
|
317600
|
+
payload
|
|
317409
317601
|
}
|
|
317410
317602
|
}));
|
|
317411
|
-
if (
|
|
317603
|
+
if (identity !== undefined) {
|
|
317412
317604
|
let targetDeposits2 = this.#lastArchivedByTarget.get(key);
|
|
317413
317605
|
if (!targetDeposits2) {
|
|
317414
317606
|
targetDeposits2 = new Map;
|
|
317415
317607
|
this.#lastArchivedByTarget.set(key, targetDeposits2);
|
|
317416
317608
|
}
|
|
317417
|
-
targetDeposits2.set(
|
|
317418
|
-
status: archiveStatus,
|
|
317419
|
-
timestamp: depositTimestamp(record)
|
|
317609
|
+
targetDeposits2.set(identity, {
|
|
317610
|
+
status: classification.archiveStatus,
|
|
317611
|
+
timestamp: depositTimestamp(record),
|
|
317612
|
+
progressKey: classification.progressKey,
|
|
317613
|
+
highWatermark: classification.highWatermark
|
|
317420
317614
|
});
|
|
317421
317615
|
}
|
|
317422
317616
|
archived += 1;
|
|
@@ -318611,7 +318805,7 @@ function commonEvidenceFields(context2, rawCapture, input) {
|
|
|
318611
318805
|
source_time_ms: input.eventTimeMs,
|
|
318612
318806
|
received_time_ms: input.receivedTimeMs,
|
|
318613
318807
|
snapshot_id: input.snapshotId,
|
|
318614
|
-
construction_mode:
|
|
318808
|
+
construction_mode: input.constructionMode,
|
|
318615
318809
|
gap_policy: "record_gap",
|
|
318616
318810
|
depth_limit: input.depthLimit,
|
|
318617
318811
|
sequence: input.sequence,
|
|
@@ -318665,7 +318859,8 @@ function buildCanonicalOrderBookRows(input) {
|
|
|
318665
318859
|
sequence,
|
|
318666
318860
|
depthLimit: input.depthLimit,
|
|
318667
318861
|
eventTimeMs,
|
|
318668
|
-
receivedTimeMs
|
|
318862
|
+
receivedTimeMs,
|
|
318863
|
+
constructionMode: input.constructionMode ?? "sampled_top_n_snapshot"
|
|
318669
318864
|
});
|
|
318670
318865
|
const levels = [
|
|
318671
318866
|
["bid", bids],
|