@tradejs/cli 2.0.15 → 2.0.16

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.
@@ -135,6 +135,29 @@ var loadRuntimeTrades = async (userName, {
135
135
  const trades = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
136
136
  return trades.filter(isRuntimeTradeRecord).filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
137
137
  };
138
+ var loadRuntimeClosedTrades = async (userName, {
139
+ startTime,
140
+ endTime
141
+ }) => {
142
+ const dayKeys = (0, import_time.getRuntimeStorageDayKeys)(startTime, endTime);
143
+ const trades = (await Promise.all(
144
+ dayKeys.map(
145
+ (dayKey) => (0, import_redis.getHashJsonValues)(
146
+ import_redis.redisKeys.runtimeClosedTradeBucket(userName, dayKey)
147
+ )
148
+ )
149
+ )).flat();
150
+ const deduped = /* @__PURE__ */ new Map();
151
+ for (const trade of trades) {
152
+ if (!isRuntimeTradeRecord(trade) || trade.status !== "closed" || !Number.isFinite(trade.exitTimestamp) || trade.exitTimestamp < startTime || trade.exitTimestamp >= endTime) {
153
+ continue;
154
+ }
155
+ deduped.set(trade.orderId, trade);
156
+ }
157
+ return [...deduped.values()].sort(
158
+ (left, right) => left.exitTimestamp - right.exitTimestamp
159
+ );
160
+ };
138
161
 
139
162
  // src/lib/runtimeSignalsLoader.ts
140
163
  var import_redis2 = require("@tradejs/infra/redis");
@@ -299,11 +322,6 @@ var formatRuntimeDebugDateTime = (timestamp) => new Intl.DateTimeFormat("ru-RU",
299
322
  minute: "2-digit",
300
323
  hour12: false
301
324
  }).format(new Date(timestamp));
302
- var buildRuntimeDebugEvaluationId = ({
303
- strategy,
304
- symbol,
305
- timestamp
306
- }) => `${strategy}:${symbol}:${timestamp}`;
307
325
  var filterByStrategies = (values, strategies) => {
308
326
  if (!strategies?.length) {
309
327
  return values;
@@ -319,13 +337,30 @@ var collectRuntimeDebugEvidence = async ({
319
337
  }) => {
320
338
  const dayKeys = (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime);
321
339
  const dayKeySet = new Set(dayKeys);
322
- const [trades, signals, evaluations, evaluationStatsBuckets, configs] = await Promise.all([
340
+ const [
341
+ entryTrades,
342
+ closedTrades,
343
+ signals,
344
+ evaluations,
345
+ evaluationStatsBuckets,
346
+ configs
347
+ ] = await Promise.all([
323
348
  loadRuntimeTrades(userName, { startTime, endTime }),
349
+ loadRuntimeClosedTrades(userName, { startTime, endTime }),
324
350
  loadRuntimeSignals(userName, { startTime, endTime }),
325
351
  loadRuntimeSignalEvaluations(userName, { startTime, endTime }),
326
352
  loadRuntimeSignalEvaluationStatsBuckets(userName),
327
353
  loadRuntimeStrategyConfigs(userName)
328
354
  ]);
355
+ const tradesByOrderId = new Map(
356
+ entryTrades.map((trade) => [trade.orderId, trade])
357
+ );
358
+ for (const trade of closedTrades) {
359
+ tradesByOrderId.set(trade.orderId, trade);
360
+ }
361
+ const trades = [...tradesByOrderId.values()].sort(
362
+ (left, right) => left.entryTimestamp - right.entryTimestamp
363
+ );
329
364
  const filteredStats = evaluationStatsBuckets.filter(
330
365
  (entry) => dayKeySet.has(entry.dayKey) && (!strategies?.length || strategies.includes(entry.strategy))
331
366
  );
@@ -340,7 +375,7 @@ var collectRuntimeDebugEvidence = async ({
340
375
  )
341
376
  };
342
377
  };
343
- var buildRuntimeDebugReportPayload = async ({
378
+ var buildRuntimeEvidenceReportPayload = ({
344
379
  userName,
345
380
  startTime,
346
381
  endTime,
@@ -349,159 +384,30 @@ var buildRuntimeDebugReportPayload = async ({
349
384
  trades,
350
385
  strategyConfigs,
351
386
  evaluationStatsBuckets
352
- }) => {
353
- const signalById = new Map(
354
- signals.map((signal) => [signal.signalId, signal])
355
- );
356
- const evaluationById = new Map(
357
- evaluations.map((evaluation) => [evaluation.evaluationId, evaluation])
358
- );
359
- const evaluationBySignalShape = new Map(
360
- evaluations.map((evaluation) => [
361
- buildRuntimeDebugEvaluationId(evaluation),
362
- evaluation
363
- ])
364
- );
365
- const dayKeys = (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime);
366
- const debugTrades = await Promise.all(
367
- trades.map(async (trade) => {
368
- const signal = trade.signalId != null ? signalById.get(trade.signalId) : void 0;
369
- const evaluationId = buildRuntimeDebugEvaluationId({
370
- strategy: trade.strategy,
371
- symbol: trade.symbol,
372
- timestamp: signal?.timestamp ?? trade.entryTimestamp
373
- });
374
- const knownEvaluation = evaluationById.get(evaluationId) ?? evaluationBySignalShape.get(evaluationId);
375
- const tradeDayKey = (0, import_time2.getRuntimeStorageDayKey)(trade.entryTimestamp);
376
- const signalDayKey = signal != null ? (0, import_time2.getRuntimeStorageDayKey)(signal.timestamp) : tradeDayKey;
377
- const evaluationDayKey = knownEvaluation != null ? (0, import_time2.getRuntimeStorageDayKey)(knownEvaluation.timestamp) : signalDayKey;
378
- const tradeKey = import_redis3.redisKeys.runtimeTrade(userName, trade.orderId);
379
- const tradeBucketKey = import_redis3.redisKeys.runtimeTradeBucket(
380
- userName,
381
- tradeDayKey
382
- );
383
- const activeTradeKey = import_redis3.redisKeys.runtimeActiveTrade(
384
- userName,
385
- trade.symbol,
386
- trade.deploymentId ?? trade.accountId
387
- );
388
- const signalKey = trade.signalId != null ? import_redis3.redisKeys.storeSignal(trade.symbol, trade.signalId) : null;
389
- const evaluationBucketKey = import_redis3.redisKeys.runtimeSignalEvaluationBucket(
390
- userName,
391
- evaluationDayKey,
392
- knownEvaluation?.strategy ?? trade.strategy
393
- );
394
- const evaluationField = knownEvaluation?.evaluationId ?? evaluationId;
395
- const evaluationKey = import_redis3.redisKeys.runtimeSignalEvaluation(
396
- userName,
397
- evaluationField
398
- );
399
- const [
400
- tradeValue,
401
- activeTradeValue,
402
- signalValue,
403
- directEvaluationValue,
404
- bucketEvaluationValue
405
- ] = await Promise.all([
406
- (0, import_redis3.getData)(tradeKey, null),
407
- (0, import_redis3.getData)(activeTradeKey, null),
408
- signalKey ? (0, import_redis3.getData)(signalKey, null) : Promise.resolve(null),
409
- (0, import_redis3.getData)(evaluationKey, null),
410
- knownEvaluation ? Promise.resolve(knownEvaluation) : (0, import_redis3.getHashJsonField)(
411
- evaluationBucketKey,
412
- evaluationField,
413
- null
414
- )
415
- ]);
416
- const evaluationValue = directEvaluationValue ?? bucketEvaluationValue ?? knownEvaluation ?? null;
417
- return {
418
- redisDebug: {
419
- trade: tradeKey,
420
- tradeBucket: {
421
- key: tradeBucketKey,
422
- field: trade.orderId
423
- },
424
- activeTrade: activeTradeKey,
425
- signal: signalKey,
426
- evaluation: {
427
- key: evaluationBucketKey,
428
- field: evaluationField,
429
- directKey: evaluationKey
430
- }
431
- },
432
- trade,
433
- redisValues: {
434
- trade: tradeValue,
435
- tradeBucket: trade,
436
- activeTrade: activeTradeValue,
437
- signal: signalValue ?? signal ?? null,
438
- evaluation: evaluationValue ?? knownEvaluation ?? null
439
- }
440
- };
441
- })
442
- );
443
- const linkedEvaluations = /* @__PURE__ */ new Map();
444
- for (const trade of debugTrades) {
445
- const evaluation = trade.redisValues.evaluation;
446
- if (evaluation && typeof evaluation === "object" && "evaluationId" in evaluation && typeof evaluation.evaluationId === "string") {
447
- linkedEvaluations.set(
448
- evaluation.evaluationId,
449
- evaluation
450
- );
451
- }
452
- }
453
- const reportEvaluations = evaluations.length > 0 ? evaluations : [...linkedEvaluations.values()];
454
- return {
455
- reportType: "runtime-daily-debug",
456
- generatedAt: Date.now(),
457
- generatedAtMsk: formatRuntimeDebugDateTime(Date.now()),
458
- userName,
459
- window: {
460
- startTime,
461
- endTime,
462
- startMsk: formatRuntimeDebugDateTime(startTime),
463
- endMsk: formatRuntimeDebugDateTime(endTime),
464
- dayKeys
465
- },
466
- redisPrefixes: {
467
- runtimeTrades: import_redis3.redisKeys.runtimeTrades(userName),
468
- runtimeTradeBuckets: import_redis3.redisKeys.runtimeTradeBuckets(userName),
469
- runtimeActiveTrades: import_redis3.redisKeys.runtimeActiveTrades(userName),
470
- runtimeSignals: import_redis3.redisKeys.runtimeSignalBuckets(userName),
471
- runtimeSignalEvaluations: import_redis3.redisKeys.runtimeSignalEvaluationBuckets(userName),
472
- runtimeSignalEvaluationStats: import_redis3.redisKeys.runtimeSignalEvaluationStatsBuckets(userName)
473
- },
474
- counts: {
475
- trades: trades.length,
476
- signals: signals.length,
477
- evaluations: reportEvaluations.length,
478
- evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
479
- strategyConfigs: strategyConfigs?.length ?? 0
480
- },
481
- trades: debugTrades,
482
- signals: signals.map((signal) => ({
483
- redisKey: import_redis3.redisKeys.storeSignal(signal.symbol, signal.signalId),
484
- signal
485
- })),
486
- evaluations: reportEvaluations.map((evaluation) => ({
487
- redisDebug: {
488
- key: import_redis3.redisKeys.runtimeSignalEvaluationBucket(
489
- userName,
490
- (0, import_time2.getRuntimeStorageDayKey)(evaluation.timestamp),
491
- evaluation.strategy
492
- ),
493
- field: evaluation.evaluationId,
494
- directKey: import_redis3.redisKeys.runtimeSignalEvaluation(
495
- userName,
496
- evaluation.evaluationId
497
- )
498
- },
499
- evaluation
500
- })),
501
- evaluationStatsBuckets: evaluationStatsBuckets ?? [],
502
- strategyConfigs: strategyConfigs ?? []
503
- };
504
- };
387
+ }) => ({
388
+ reportType: "runtime-daily-evidence",
389
+ generatedAt: Date.now(),
390
+ userName,
391
+ window: {
392
+ startTime,
393
+ endTime,
394
+ startMsk: formatRuntimeDebugDateTime(startTime),
395
+ endMsk: formatRuntimeDebugDateTime(endTime),
396
+ dayKeys: (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime)
397
+ },
398
+ counts: {
399
+ trades: trades.length,
400
+ signals: signals.length,
401
+ evaluations: evaluations.length,
402
+ evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
403
+ strategyConfigs: strategyConfigs?.length ?? 0
404
+ },
405
+ trades: trades.map((trade) => ({ trade })),
406
+ signals: signals.map((signal) => ({ signal })),
407
+ evaluations: evaluations.map((evaluation) => ({ evaluation })),
408
+ evaluationStatsBuckets: evaluationStatsBuckets ?? [],
409
+ strategyConfigs: strategyConfigs ?? []
410
+ });
505
411
 
506
412
  // src/lib/replay/support.ts
507
413
  var import_chalk = __toESM(require("chalk"));
@@ -659,6 +565,7 @@ var summarizeReplayComparison = (runtimeComparison, strategies) => {
659
565
  ].sort((left, right) => left.localeCompare(right));
660
566
  return {
661
567
  mode: comparison.mode ?? null,
568
+ lineage: comparison.lineage ?? null,
662
569
  rows: asArray(comparison.rows).filter(
663
570
  (row) => !useFilter || strategySet.has(String(row.strategyName ?? ""))
664
571
  ),
@@ -786,7 +693,7 @@ var loadRuntimePayload = async ({
786
693
  return {
787
694
  source: "local-redis",
788
695
  path: null,
789
- payload: await buildRuntimeDebugReportPayload({
696
+ payload: buildRuntimeEvidenceReportPayload({
790
697
  userName: flags.user,
791
698
  startTime,
792
699
  endTime,