@tradejs/cli 2.0.2 → 2.0.3

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/cli.js CHANGED
@@ -2755,7 +2755,8 @@ var init_selectStrategy = __esm({
2755
2755
  "MaStrategy",
2756
2756
  "AdaptiveMomentumRibbon",
2757
2757
  "TrendLine",
2758
- "VolumeDivergence"
2758
+ "VolumeDivergence",
2759
+ "Grid"
2759
2760
  ];
2760
2761
  };
2761
2762
  selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -3435,7 +3436,7 @@ var init_aiTrainOptions = __esm({
3435
3436
  });
3436
3437
 
3437
3438
  // src/lib/aiPocketSearch.ts
3438
- var DAY_MS2, DAYS_PER_WEEK2, DAYS_PER_MONTH2, OUTCOME_SEGMENTS, isPlainRecord, isFiniteNumber, isFeaturePrimitive, normalizeFeaturePrimitive, isOutcomePath, isFeaturePathPrefix, isCompactFeaturePathSkipped, addFlattenedFeatures, findFeatureNumber, findFeatureString, addDirectionalDerivedFeatures, collectAiPocketFeatures, formatNumber, formatPredicateValue, roundThreshold, quantileAt, getPeriodDays, createSummaryAccumulator, addSummaryRow, emptyAiPocketSummary, finalizeAiPocketSummary, summarizeSelectedRows, summarizeMask, summarizeRowIndexes, summarizeAiPocketRows, matchesPredicate, buildMask, intersectMasks, buildPredicateListMask, toPublicPredicate, buildAiPocketPredicateResult, scorePositivePocket, scoreNegativePocket, comparePositivePockets, compareNegativePockets, createPocketResult, hashMask, isBetterRepresentativePocket, estimateCombinationCount, searchAiPockets, formatMdNumber, formatMdPercent, escapeMarkdownCell, markdownTable, summaryMetricRows, pocketRows, buildAiPocketMarkdownReport;
3439
+ var DAY_MS2, DAYS_PER_WEEK2, DAYS_PER_MONTH2, OUTCOME_SEGMENTS, isPlainRecord, isFiniteNumber, isFeaturePrimitive, normalizeFeaturePrimitive, isOutcomePath, isFeaturePathPrefix, isCompactFeaturePathSkipped, addFlattenedFeatures, findFeatureNumber, findFeatureString, addDirectionalDerivedFeatures, addSignalRiskDistanceFeatures, collectAiPocketFeatures, formatNumber, formatPredicateValue, roundThreshold, quantileAt, getPeriodDays, createSummaryAccumulator, addSummaryRow, emptyAiPocketSummary, finalizeAiPocketSummary, summarizeSelectedRows, summarizeMask, summarizeRowIndexes, summarizeAiPocketRows, matchesPredicate, buildMask, intersectMasks, buildPredicateListMask, toPublicPredicate, buildAiPocketPredicateResult, scorePositivePocket, scoreNegativePocket, comparePositivePockets, compareNegativePockets, createPocketResult, hashMask, isBetterRepresentativePocket, estimateCombinationCount, searchAiPockets, formatMdNumber, formatMdPercent, escapeMarkdownCell, markdownTable, summaryMetricRows, pocketRows, buildAiPocketMarkdownReport;
3439
3440
  var init_aiPocketSearch = __esm({
3440
3441
  "src/lib/aiPocketSearch.ts"() {
3441
3442
  "use strict";
@@ -3739,6 +3740,23 @@ var init_aiPocketSearch = __esm({
3739
3740
  }
3740
3741
  features["derived.directIndicatorSupportCount"] = supportCount;
3741
3742
  };
3743
+ addSignalRiskDistanceFeatures = ({
3744
+ features,
3745
+ signal
3746
+ }) => {
3747
+ const currentPrice = isFiniteNumber(signal.prices?.currentPrice) ? signal.prices.currentPrice : null;
3748
+ const stopLossPrice = isFiniteNumber(signal.prices?.stopLossPrice) ? signal.prices.stopLossPrice : null;
3749
+ const takeProfitPrice = isFiniteNumber(signal.prices?.takeProfitPrice) ? signal.prices.takeProfitPrice : null;
3750
+ if (currentPrice == null || currentPrice === 0) {
3751
+ return;
3752
+ }
3753
+ if (stopLossPrice != null) {
3754
+ features["derived.stopDistanceBps"] = Math.abs(currentPrice - stopLossPrice) / Math.abs(currentPrice) * 1e4;
3755
+ }
3756
+ if (takeProfitPrice != null) {
3757
+ features["derived.takeProfitDistanceBps"] = Math.abs(takeProfitPrice - currentPrice) / Math.abs(currentPrice) * 1e4;
3758
+ }
3759
+ };
3742
3760
  collectAiPocketFeatures = ({
3743
3761
  payload,
3744
3762
  gateContext,
@@ -3766,6 +3784,7 @@ var init_aiPocketSearch = __esm({
3766
3784
  maxDepth: 8,
3767
3785
  shouldSkipPath: featureProfile === "compact" ? isCompactFeaturePathSkipped : void 0
3768
3786
  });
3787
+ addSignalRiskDistanceFeatures({ features, signal });
3769
3788
  addDirectionalDerivedFeatures(features);
3770
3789
  return features;
3771
3790
  };
@@ -30291,7 +30310,7 @@ var init_resultsReporting = __esm({
30291
30310
  });
30292
30311
 
30293
30312
  // src/lib/runtimeTradeSync.ts
30294
- var import_constants18, import_time10, import_redis21, CLOSED_PNL_LIMIT, EXCHANGE_HISTORY_MAX_RANGE_MS, splitExchangeHistoryTimeRange, formatRuntimeTradeSyncError, loadClosedPnlRows, consumeClosedPnlMatch, syncRuntimeTrades;
30313
+ var import_constants18, import_time10, import_redis21, CLOSED_PNL_LIMIT, CLOSED_PNL_RECONCILIATION_LOOKBACK_MS, EXCHANGE_HISTORY_MAX_RANGE_MS, isRuntimeTradeSyncFallbackClose, splitExchangeHistoryTimeRange, formatRuntimeTradeSyncError, loadClosedPnlRows, consumeClosedPnlMatch, syncRuntimeTrades;
30295
30314
  var init_runtimeTradeSync = __esm({
30296
30315
  "src/lib/runtimeTradeSync.ts"() {
30297
30316
  "use strict";
@@ -30299,7 +30318,9 @@ var init_runtimeTradeSync = __esm({
30299
30318
  import_time10 = require("@tradejs/core/time");
30300
30319
  import_redis21 = require("@tradejs/infra/redis");
30301
30320
  CLOSED_PNL_LIMIT = 100;
30321
+ CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
30302
30322
  EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
30323
+ isRuntimeTradeSyncFallbackClose = (trade) => trade.status === "closed" && trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null;
30303
30324
  splitExchangeHistoryTimeRange = ({
30304
30325
  startTime,
30305
30326
  endTime,
@@ -30428,7 +30449,7 @@ var init_runtimeTradeSync = __esm({
30428
30449
  );
30429
30450
  const closedPnlRows = await loadClosedPnlRows({
30430
30451
  connector,
30431
- startTime,
30452
+ startTime: Math.max(0, startTime - CLOSED_PNL_RECONCILIATION_LOOKBACK_MS),
30432
30453
  endTime,
30433
30454
  callbacks: closedPnlCallbacks
30434
30455
  });
@@ -30440,14 +30461,14 @@ var init_runtimeTradeSync = __esm({
30440
30461
  }
30441
30462
  const syncedTrades = [];
30442
30463
  for (const trade of trades) {
30443
- if (trade.status !== "active") {
30464
+ if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
30444
30465
  syncedTrades.push(trade);
30445
30466
  continue;
30446
30467
  }
30447
30468
  const openPosition = openPositionsBySymbol.get(trade.symbol);
30448
30469
  const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
30449
30470
  const isCurrentActiveTrade = activeOrderId === trade.orderId;
30450
- if (!openPositionsReliable) {
30471
+ if (trade.status === "active" && !openPositionsReliable) {
30451
30472
  syncedTrades.push({
30452
30473
  ...trade,
30453
30474
  status: "active",
@@ -30455,7 +30476,7 @@ var init_runtimeTradeSync = __esm({
30455
30476
  });
30456
30477
  continue;
30457
30478
  }
30458
- if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
30479
+ if (trade.status === "active" && isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
30459
30480
  const nextTrade2 = {
30460
30481
  ...trade,
30461
30482
  status: "active",
@@ -30483,21 +30504,24 @@ var init_runtimeTradeSync = __esm({
30483
30504
  continue;
30484
30505
  }
30485
30506
  const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
30507
+ if (!matchedClosedPnl) {
30508
+ continue;
30509
+ }
30486
30510
  const nextTrade = {
30487
30511
  ...trade,
30488
30512
  status: "closed",
30489
- currentPrice: matchedClosedPnl?.exitPrice ?? trade.currentPrice ?? null,
30490
- currentPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
30491
- closedPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
30492
- actualEntryPrice: matchedClosedPnl?.entryPrice ?? trade.actualEntryPrice ?? null,
30493
- exitPrice: matchedClosedPnl?.exitPrice ?? trade.exitPrice ?? null,
30494
- actualExitPrice: matchedClosedPnl?.exitPrice ?? trade.actualExitPrice ?? null,
30495
- exitTimestamp: matchedClosedPnl?.closedAt ?? trade.exitTimestamp ?? endTime,
30513
+ currentPrice: matchedClosedPnl.exitPrice ?? trade.currentPrice ?? null,
30514
+ currentPnl: matchedClosedPnl.closedPnl,
30515
+ closedPnl: matchedClosedPnl.closedPnl,
30516
+ actualEntryPrice: matchedClosedPnl.entryPrice ?? trade.actualEntryPrice ?? null,
30517
+ exitPrice: matchedClosedPnl.exitPrice ?? trade.exitPrice ?? null,
30518
+ actualExitPrice: matchedClosedPnl.exitPrice ?? trade.actualExitPrice ?? null,
30519
+ exitTimestamp: matchedClosedPnl.closedAt,
30496
30520
  exitType: trade.exitType ?? null,
30497
- openFee: matchedClosedPnl?.openFee ?? trade.openFee ?? null,
30498
- closeFee: matchedClosedPnl?.closeFee ?? trade.closeFee ?? null,
30499
- fundingFee: matchedClosedPnl?.fundingFee ?? trade.fundingFee ?? null,
30500
- totalFee: matchedClosedPnl?.totalFee ?? trade.totalFee ?? null,
30521
+ openFee: matchedClosedPnl.openFee ?? trade.openFee ?? null,
30522
+ closeFee: matchedClosedPnl.closeFee ?? trade.closeFee ?? null,
30523
+ fundingFee: matchedClosedPnl.fundingFee ?? trade.fundingFee ?? null,
30524
+ totalFee: matchedClosedPnl.totalFee ?? trade.totalFee ?? null,
30501
30525
  lastSyncedAt: endTime
30502
30526
  };
30503
30527
  await Promise.all([
@@ -32655,8 +32679,7 @@ var init_signalsSummary = __esm({
32655
32679
  if (trade.status !== "closed" || !isTimestampInWindow(trade.exitTimestamp, startTime, endTime)) {
32656
32680
  return false;
32657
32681
  }
32658
- const looksLikeSyncFallbackClose = trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null && trade.totalFee == null;
32659
- return !looksLikeSyncFallbackClose;
32682
+ return !isRuntimeTradeSyncFallbackClose(trade);
32660
32683
  };
32661
32684
  buildSummaryMessages = ({
32662
32685
  hours,
@@ -327,6 +327,23 @@ var addDirectionalDerivedFeatures = (features) => {
327
327
  }
328
328
  features["derived.directIndicatorSupportCount"] = supportCount;
329
329
  };
330
+ var addSignalRiskDistanceFeatures = ({
331
+ features,
332
+ signal
333
+ }) => {
334
+ const currentPrice = isFiniteNumber(signal.prices?.currentPrice) ? signal.prices.currentPrice : null;
335
+ const stopLossPrice = isFiniteNumber(signal.prices?.stopLossPrice) ? signal.prices.stopLossPrice : null;
336
+ const takeProfitPrice = isFiniteNumber(signal.prices?.takeProfitPrice) ? signal.prices.takeProfitPrice : null;
337
+ if (currentPrice == null || currentPrice === 0) {
338
+ return;
339
+ }
340
+ if (stopLossPrice != null) {
341
+ features["derived.stopDistanceBps"] = Math.abs(currentPrice - stopLossPrice) / Math.abs(currentPrice) * 1e4;
342
+ }
343
+ if (takeProfitPrice != null) {
344
+ features["derived.takeProfitDistanceBps"] = Math.abs(takeProfitPrice - currentPrice) / Math.abs(currentPrice) * 1e4;
345
+ }
346
+ };
330
347
  var collectAiPocketFeatures = ({
331
348
  payload,
332
349
  gateContext,
@@ -354,6 +371,7 @@ var collectAiPocketFeatures = ({
354
371
  maxDepth: 8,
355
372
  shouldSkipPath: featureProfile === "compact" ? isCompactFeaturePathSkipped : void 0
356
373
  });
374
+ addSignalRiskDistanceFeatures({ features, signal });
357
375
  addDirectionalDerivedFeatures(features);
358
376
  return features;
359
377
  };
@@ -23,6 +23,7 @@ __export(runtimeTradeSync_exports, {
23
23
  EXCHANGE_HISTORY_MAX_RANGE_MS: () => EXCHANGE_HISTORY_MAX_RANGE_MS,
24
24
  consumeClosedPnlMatch: () => consumeClosedPnlMatch,
25
25
  formatRuntimeTradeSyncError: () => formatRuntimeTradeSyncError,
26
+ isRuntimeTradeSyncFallbackClose: () => isRuntimeTradeSyncFallbackClose,
26
27
  loadClosedPnlRows: () => loadClosedPnlRows,
27
28
  splitExchangeHistoryTimeRange: () => splitExchangeHistoryTimeRange,
28
29
  syncRuntimeTrades: () => syncRuntimeTrades
@@ -32,7 +33,9 @@ var import_constants = require("@tradejs/core/constants");
32
33
  var import_time = require("@tradejs/core/time");
33
34
  var import_redis = require("@tradejs/infra/redis");
34
35
  var CLOSED_PNL_LIMIT = 100;
36
+ var CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
35
37
  var EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
38
+ var isRuntimeTradeSyncFallbackClose = (trade) => trade.status === "closed" && trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null;
36
39
  var splitExchangeHistoryTimeRange = ({
37
40
  startTime,
38
41
  endTime,
@@ -161,7 +164,7 @@ var syncRuntimeTrades = async ({
161
164
  );
162
165
  const closedPnlRows = await loadClosedPnlRows({
163
166
  connector,
164
- startTime,
167
+ startTime: Math.max(0, startTime - CLOSED_PNL_RECONCILIATION_LOOKBACK_MS),
165
168
  endTime,
166
169
  callbacks: closedPnlCallbacks
167
170
  });
@@ -173,14 +176,14 @@ var syncRuntimeTrades = async ({
173
176
  }
174
177
  const syncedTrades = [];
175
178
  for (const trade of trades) {
176
- if (trade.status !== "active") {
179
+ if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
177
180
  syncedTrades.push(trade);
178
181
  continue;
179
182
  }
180
183
  const openPosition = openPositionsBySymbol.get(trade.symbol);
181
184
  const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
182
185
  const isCurrentActiveTrade = activeOrderId === trade.orderId;
183
- if (!openPositionsReliable) {
186
+ if (trade.status === "active" && !openPositionsReliable) {
184
187
  syncedTrades.push({
185
188
  ...trade,
186
189
  status: "active",
@@ -188,7 +191,7 @@ var syncRuntimeTrades = async ({
188
191
  });
189
192
  continue;
190
193
  }
191
- if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
194
+ if (trade.status === "active" && isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
192
195
  const nextTrade2 = {
193
196
  ...trade,
194
197
  status: "active",
@@ -216,21 +219,24 @@ var syncRuntimeTrades = async ({
216
219
  continue;
217
220
  }
218
221
  const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
222
+ if (!matchedClosedPnl) {
223
+ continue;
224
+ }
219
225
  const nextTrade = {
220
226
  ...trade,
221
227
  status: "closed",
222
- currentPrice: matchedClosedPnl?.exitPrice ?? trade.currentPrice ?? null,
223
- currentPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
224
- closedPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
225
- actualEntryPrice: matchedClosedPnl?.entryPrice ?? trade.actualEntryPrice ?? null,
226
- exitPrice: matchedClosedPnl?.exitPrice ?? trade.exitPrice ?? null,
227
- actualExitPrice: matchedClosedPnl?.exitPrice ?? trade.actualExitPrice ?? null,
228
- exitTimestamp: matchedClosedPnl?.closedAt ?? trade.exitTimestamp ?? endTime,
228
+ currentPrice: matchedClosedPnl.exitPrice ?? trade.currentPrice ?? null,
229
+ currentPnl: matchedClosedPnl.closedPnl,
230
+ closedPnl: matchedClosedPnl.closedPnl,
231
+ actualEntryPrice: matchedClosedPnl.entryPrice ?? trade.actualEntryPrice ?? null,
232
+ exitPrice: matchedClosedPnl.exitPrice ?? trade.exitPrice ?? null,
233
+ actualExitPrice: matchedClosedPnl.exitPrice ?? trade.actualExitPrice ?? null,
234
+ exitTimestamp: matchedClosedPnl.closedAt,
229
235
  exitType: trade.exitType ?? null,
230
- openFee: matchedClosedPnl?.openFee ?? trade.openFee ?? null,
231
- closeFee: matchedClosedPnl?.closeFee ?? trade.closeFee ?? null,
232
- fundingFee: matchedClosedPnl?.fundingFee ?? trade.fundingFee ?? null,
233
- totalFee: matchedClosedPnl?.totalFee ?? trade.totalFee ?? null,
236
+ openFee: matchedClosedPnl.openFee ?? trade.openFee ?? null,
237
+ closeFee: matchedClosedPnl.closeFee ?? trade.closeFee ?? null,
238
+ fundingFee: matchedClosedPnl.fundingFee ?? trade.fundingFee ?? null,
239
+ totalFee: matchedClosedPnl.totalFee ?? trade.totalFee ?? null,
234
240
  lastSyncedAt: endTime
235
241
  };
236
242
  await Promise.all([
@@ -257,6 +263,7 @@ var syncRuntimeTrades = async ({
257
263
  EXCHANGE_HISTORY_MAX_RANGE_MS,
258
264
  consumeClosedPnlMatch,
259
265
  formatRuntimeTradeSyncError,
266
+ isRuntimeTradeSyncFallbackClose,
260
267
  loadClosedPnlRows,
261
268
  splitExchangeHistoryTimeRange,
262
269
  syncRuntimeTrades
@@ -1697,7 +1697,8 @@ var getStrategyChoices = async () => {
1697
1697
  "MaStrategy",
1698
1698
  "AdaptiveMomentumRibbon",
1699
1699
  "TrendLine",
1700
- "VolumeDivergence"
1700
+ "VolumeDivergence",
1701
+ "Grid"
1701
1702
  ];
1702
1703
  };
1703
1704
  var selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -54,7 +54,8 @@ var getStrategyChoices = async () => {
54
54
  "MaStrategy",
55
55
  "AdaptiveMomentumRibbon",
56
56
  "TrendLine",
57
- "VolumeDivergence"
57
+ "VolumeDivergence",
58
+ "Grid"
58
59
  ];
59
60
  };
60
61
  var selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -2310,6 +2310,23 @@ var addDirectionalDerivedFeatures = (features) => {
2310
2310
  }
2311
2311
  features["derived.directIndicatorSupportCount"] = supportCount;
2312
2312
  };
2313
+ var addSignalRiskDistanceFeatures = ({
2314
+ features,
2315
+ signal
2316
+ }) => {
2317
+ const currentPrice = isFiniteNumber(signal.prices?.currentPrice) ? signal.prices.currentPrice : null;
2318
+ const stopLossPrice = isFiniteNumber(signal.prices?.stopLossPrice) ? signal.prices.stopLossPrice : null;
2319
+ const takeProfitPrice = isFiniteNumber(signal.prices?.takeProfitPrice) ? signal.prices.takeProfitPrice : null;
2320
+ if (currentPrice == null || currentPrice === 0) {
2321
+ return;
2322
+ }
2323
+ if (stopLossPrice != null) {
2324
+ features["derived.stopDistanceBps"] = Math.abs(currentPrice - stopLossPrice) / Math.abs(currentPrice) * 1e4;
2325
+ }
2326
+ if (takeProfitPrice != null) {
2327
+ features["derived.takeProfitDistanceBps"] = Math.abs(takeProfitPrice - currentPrice) / Math.abs(currentPrice) * 1e4;
2328
+ }
2329
+ };
2313
2330
  var collectAiPocketFeatures = ({
2314
2331
  payload,
2315
2332
  gateContext,
@@ -2337,6 +2354,7 @@ var collectAiPocketFeatures = ({
2337
2354
  maxDepth: 8,
2338
2355
  shouldSkipPath: featureProfile === "compact" ? isCompactFeaturePathSkipped : void 0
2339
2356
  });
2357
+ addSignalRiskDistanceFeatures({ features, signal });
2340
2358
  addDirectionalDerivedFeatures(features);
2341
2359
  return features;
2342
2360
  };
@@ -1697,7 +1697,8 @@ var getStrategyChoices = async () => {
1697
1697
  "MaStrategy",
1698
1698
  "AdaptiveMomentumRibbon",
1699
1699
  "TrendLine",
1700
- "VolumeDivergence"
1700
+ "VolumeDivergence",
1701
+ "Grid"
1701
1702
  ];
1702
1703
  };
1703
1704
  var selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -54,7 +54,8 @@ var getStrategyChoices = async () => {
54
54
  "MaStrategy",
55
55
  "AdaptiveMomentumRibbon",
56
56
  "TrendLine",
57
- "VolumeDivergence"
57
+ "VolumeDivergence",
58
+ "Grid"
58
59
  ];
59
60
  };
60
61
  var selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -63,7 +63,8 @@ var getStrategyChoices = async () => {
63
63
  "MaStrategy",
64
64
  "AdaptiveMomentumRibbon",
65
65
  "TrendLine",
66
- "VolumeDivergence"
66
+ "VolumeDivergence",
67
+ "Grid"
67
68
  ];
68
69
  };
69
70
  var selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -6909,7 +6909,9 @@ var import_constants5 = require("@tradejs/core/constants");
6909
6909
  var import_time5 = require("@tradejs/core/time");
6910
6910
  var import_redis4 = require("@tradejs/infra/redis");
6911
6911
  var CLOSED_PNL_LIMIT = 100;
6912
+ var CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
6912
6913
  var EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
6914
+ var isRuntimeTradeSyncFallbackClose = (trade) => trade.status === "closed" && trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null;
6913
6915
  var splitExchangeHistoryTimeRange = ({
6914
6916
  startTime,
6915
6917
  endTime,
@@ -7038,7 +7040,7 @@ var syncRuntimeTrades = async ({
7038
7040
  );
7039
7041
  const closedPnlRows = await loadClosedPnlRows({
7040
7042
  connector,
7041
- startTime,
7043
+ startTime: Math.max(0, startTime - CLOSED_PNL_RECONCILIATION_LOOKBACK_MS),
7042
7044
  endTime,
7043
7045
  callbacks: closedPnlCallbacks
7044
7046
  });
@@ -7050,14 +7052,14 @@ var syncRuntimeTrades = async ({
7050
7052
  }
7051
7053
  const syncedTrades = [];
7052
7054
  for (const trade of trades) {
7053
- if (trade.status !== "active") {
7055
+ if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
7054
7056
  syncedTrades.push(trade);
7055
7057
  continue;
7056
7058
  }
7057
7059
  const openPosition = openPositionsBySymbol.get(trade.symbol);
7058
7060
  const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
7059
7061
  const isCurrentActiveTrade = activeOrderId === trade.orderId;
7060
- if (!openPositionsReliable) {
7062
+ if (trade.status === "active" && !openPositionsReliable) {
7061
7063
  syncedTrades.push({
7062
7064
  ...trade,
7063
7065
  status: "active",
@@ -7065,7 +7067,7 @@ var syncRuntimeTrades = async ({
7065
7067
  });
7066
7068
  continue;
7067
7069
  }
7068
- if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
7070
+ if (trade.status === "active" && isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
7069
7071
  const nextTrade2 = {
7070
7072
  ...trade,
7071
7073
  status: "active",
@@ -7093,21 +7095,24 @@ var syncRuntimeTrades = async ({
7093
7095
  continue;
7094
7096
  }
7095
7097
  const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
7098
+ if (!matchedClosedPnl) {
7099
+ continue;
7100
+ }
7096
7101
  const nextTrade = {
7097
7102
  ...trade,
7098
7103
  status: "closed",
7099
- currentPrice: matchedClosedPnl?.exitPrice ?? trade.currentPrice ?? null,
7100
- currentPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
7101
- closedPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
7102
- actualEntryPrice: matchedClosedPnl?.entryPrice ?? trade.actualEntryPrice ?? null,
7103
- exitPrice: matchedClosedPnl?.exitPrice ?? trade.exitPrice ?? null,
7104
- actualExitPrice: matchedClosedPnl?.exitPrice ?? trade.actualExitPrice ?? null,
7105
- exitTimestamp: matchedClosedPnl?.closedAt ?? trade.exitTimestamp ?? endTime,
7104
+ currentPrice: matchedClosedPnl.exitPrice ?? trade.currentPrice ?? null,
7105
+ currentPnl: matchedClosedPnl.closedPnl,
7106
+ closedPnl: matchedClosedPnl.closedPnl,
7107
+ actualEntryPrice: matchedClosedPnl.entryPrice ?? trade.actualEntryPrice ?? null,
7108
+ exitPrice: matchedClosedPnl.exitPrice ?? trade.exitPrice ?? null,
7109
+ actualExitPrice: matchedClosedPnl.exitPrice ?? trade.actualExitPrice ?? null,
7110
+ exitTimestamp: matchedClosedPnl.closedAt,
7106
7111
  exitType: trade.exitType ?? null,
7107
- openFee: matchedClosedPnl?.openFee ?? trade.openFee ?? null,
7108
- closeFee: matchedClosedPnl?.closeFee ?? trade.closeFee ?? null,
7109
- fundingFee: matchedClosedPnl?.fundingFee ?? trade.fundingFee ?? null,
7110
- totalFee: matchedClosedPnl?.totalFee ?? trade.totalFee ?? null,
7112
+ openFee: matchedClosedPnl.openFee ?? trade.openFee ?? null,
7113
+ closeFee: matchedClosedPnl.closeFee ?? trade.closeFee ?? null,
7114
+ fundingFee: matchedClosedPnl.fundingFee ?? trade.fundingFee ?? null,
7115
+ totalFee: matchedClosedPnl.totalFee ?? trade.totalFee ?? null,
7111
7116
  lastSyncedAt: endTime
7112
7117
  };
7113
7118
  await Promise.all([
@@ -6912,7 +6912,9 @@ var import_constants5 = require("@tradejs/core/constants");
6912
6912
  var import_time5 = require("@tradejs/core/time");
6913
6913
  var import_redis4 = require("@tradejs/infra/redis");
6914
6914
  var CLOSED_PNL_LIMIT = 100;
6915
+ var CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
6915
6916
  var EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
6917
+ var isRuntimeTradeSyncFallbackClose = (trade) => trade.status === "closed" && trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null;
6916
6918
  var splitExchangeHistoryTimeRange = ({
6917
6919
  startTime,
6918
6920
  endTime,
@@ -7041,7 +7043,7 @@ var syncRuntimeTrades = async ({
7041
7043
  );
7042
7044
  const closedPnlRows = await loadClosedPnlRows({
7043
7045
  connector,
7044
- startTime,
7046
+ startTime: Math.max(0, startTime - CLOSED_PNL_RECONCILIATION_LOOKBACK_MS),
7045
7047
  endTime,
7046
7048
  callbacks: closedPnlCallbacks
7047
7049
  });
@@ -7053,14 +7055,14 @@ var syncRuntimeTrades = async ({
7053
7055
  }
7054
7056
  const syncedTrades = [];
7055
7057
  for (const trade of trades) {
7056
- if (trade.status !== "active") {
7058
+ if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
7057
7059
  syncedTrades.push(trade);
7058
7060
  continue;
7059
7061
  }
7060
7062
  const openPosition = openPositionsBySymbol.get(trade.symbol);
7061
7063
  const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
7062
7064
  const isCurrentActiveTrade = activeOrderId === trade.orderId;
7063
- if (!openPositionsReliable) {
7065
+ if (trade.status === "active" && !openPositionsReliable) {
7064
7066
  syncedTrades.push({
7065
7067
  ...trade,
7066
7068
  status: "active",
@@ -7068,7 +7070,7 @@ var syncRuntimeTrades = async ({
7068
7070
  });
7069
7071
  continue;
7070
7072
  }
7071
- if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
7073
+ if (trade.status === "active" && isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
7072
7074
  const nextTrade2 = {
7073
7075
  ...trade,
7074
7076
  status: "active",
@@ -7096,21 +7098,24 @@ var syncRuntimeTrades = async ({
7096
7098
  continue;
7097
7099
  }
7098
7100
  const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
7101
+ if (!matchedClosedPnl) {
7102
+ continue;
7103
+ }
7099
7104
  const nextTrade = {
7100
7105
  ...trade,
7101
7106
  status: "closed",
7102
- currentPrice: matchedClosedPnl?.exitPrice ?? trade.currentPrice ?? null,
7103
- currentPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
7104
- closedPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
7105
- actualEntryPrice: matchedClosedPnl?.entryPrice ?? trade.actualEntryPrice ?? null,
7106
- exitPrice: matchedClosedPnl?.exitPrice ?? trade.exitPrice ?? null,
7107
- actualExitPrice: matchedClosedPnl?.exitPrice ?? trade.actualExitPrice ?? null,
7108
- exitTimestamp: matchedClosedPnl?.closedAt ?? trade.exitTimestamp ?? endTime,
7107
+ currentPrice: matchedClosedPnl.exitPrice ?? trade.currentPrice ?? null,
7108
+ currentPnl: matchedClosedPnl.closedPnl,
7109
+ closedPnl: matchedClosedPnl.closedPnl,
7110
+ actualEntryPrice: matchedClosedPnl.entryPrice ?? trade.actualEntryPrice ?? null,
7111
+ exitPrice: matchedClosedPnl.exitPrice ?? trade.exitPrice ?? null,
7112
+ actualExitPrice: matchedClosedPnl.exitPrice ?? trade.actualExitPrice ?? null,
7113
+ exitTimestamp: matchedClosedPnl.closedAt,
7109
7114
  exitType: trade.exitType ?? null,
7110
- openFee: matchedClosedPnl?.openFee ?? trade.openFee ?? null,
7111
- closeFee: matchedClosedPnl?.closeFee ?? trade.closeFee ?? null,
7112
- fundingFee: matchedClosedPnl?.fundingFee ?? trade.fundingFee ?? null,
7113
- totalFee: matchedClosedPnl?.totalFee ?? trade.totalFee ?? null,
7115
+ openFee: matchedClosedPnl.openFee ?? trade.openFee ?? null,
7116
+ closeFee: matchedClosedPnl.closeFee ?? trade.closeFee ?? null,
7117
+ fundingFee: matchedClosedPnl.fundingFee ?? trade.fundingFee ?? null,
7118
+ totalFee: matchedClosedPnl.totalFee ?? trade.totalFee ?? null,
7114
7119
  lastSyncedAt: endTime
7115
7120
  };
7116
7121
  await Promise.all([
@@ -54,7 +54,8 @@ var getStrategyChoices = async () => {
54
54
  "MaStrategy",
55
55
  "AdaptiveMomentumRibbon",
56
56
  "TrendLine",
57
- "VolumeDivergence"
57
+ "VolumeDivergence",
58
+ "Grid"
58
59
  ];
59
60
  };
60
61
  var selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -52,7 +52,8 @@ var getStrategyChoices = async () => {
52
52
  "MaStrategy",
53
53
  "AdaptiveMomentumRibbon",
54
54
  "TrendLine",
55
- "VolumeDivergence"
55
+ "VolumeDivergence",
56
+ "Grid"
56
57
  ];
57
58
  };
58
59
  var selectStrategy = async (promptLabel = "Select strategy", options) => {
@@ -113,7 +113,9 @@ var import_constants = require("@tradejs/core/constants");
113
113
  var import_time2 = require("@tradejs/core/time");
114
114
  var import_redis2 = require("@tradejs/infra/redis");
115
115
  var CLOSED_PNL_LIMIT = 100;
116
+ var CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
116
117
  var EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
118
+ var isRuntimeTradeSyncFallbackClose = (trade) => trade.status === "closed" && trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null;
117
119
  var splitExchangeHistoryTimeRange = ({
118
120
  startTime,
119
121
  endTime,
@@ -242,7 +244,7 @@ var syncRuntimeTrades = async ({
242
244
  );
243
245
  const closedPnlRows = await loadClosedPnlRows({
244
246
  connector,
245
- startTime,
247
+ startTime: Math.max(0, startTime - CLOSED_PNL_RECONCILIATION_LOOKBACK_MS),
246
248
  endTime,
247
249
  callbacks: closedPnlCallbacks
248
250
  });
@@ -254,14 +256,14 @@ var syncRuntimeTrades = async ({
254
256
  }
255
257
  const syncedTrades = [];
256
258
  for (const trade of trades) {
257
- if (trade.status !== "active") {
259
+ if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
258
260
  syncedTrades.push(trade);
259
261
  continue;
260
262
  }
261
263
  const openPosition = openPositionsBySymbol.get(trade.symbol);
262
264
  const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
263
265
  const isCurrentActiveTrade = activeOrderId === trade.orderId;
264
- if (!openPositionsReliable) {
266
+ if (trade.status === "active" && !openPositionsReliable) {
265
267
  syncedTrades.push({
266
268
  ...trade,
267
269
  status: "active",
@@ -269,7 +271,7 @@ var syncRuntimeTrades = async ({
269
271
  });
270
272
  continue;
271
273
  }
272
- if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
274
+ if (trade.status === "active" && isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
273
275
  const nextTrade2 = {
274
276
  ...trade,
275
277
  status: "active",
@@ -297,21 +299,24 @@ var syncRuntimeTrades = async ({
297
299
  continue;
298
300
  }
299
301
  const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
302
+ if (!matchedClosedPnl) {
303
+ continue;
304
+ }
300
305
  const nextTrade = {
301
306
  ...trade,
302
307
  status: "closed",
303
- currentPrice: matchedClosedPnl?.exitPrice ?? trade.currentPrice ?? null,
304
- currentPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
305
- closedPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
306
- actualEntryPrice: matchedClosedPnl?.entryPrice ?? trade.actualEntryPrice ?? null,
307
- exitPrice: matchedClosedPnl?.exitPrice ?? trade.exitPrice ?? null,
308
- actualExitPrice: matchedClosedPnl?.exitPrice ?? trade.actualExitPrice ?? null,
309
- exitTimestamp: matchedClosedPnl?.closedAt ?? trade.exitTimestamp ?? endTime,
308
+ currentPrice: matchedClosedPnl.exitPrice ?? trade.currentPrice ?? null,
309
+ currentPnl: matchedClosedPnl.closedPnl,
310
+ closedPnl: matchedClosedPnl.closedPnl,
311
+ actualEntryPrice: matchedClosedPnl.entryPrice ?? trade.actualEntryPrice ?? null,
312
+ exitPrice: matchedClosedPnl.exitPrice ?? trade.exitPrice ?? null,
313
+ actualExitPrice: matchedClosedPnl.exitPrice ?? trade.actualExitPrice ?? null,
314
+ exitTimestamp: matchedClosedPnl.closedAt,
310
315
  exitType: trade.exitType ?? null,
311
- openFee: matchedClosedPnl?.openFee ?? trade.openFee ?? null,
312
- closeFee: matchedClosedPnl?.closeFee ?? trade.closeFee ?? null,
313
- fundingFee: matchedClosedPnl?.fundingFee ?? trade.fundingFee ?? null,
314
- totalFee: matchedClosedPnl?.totalFee ?? trade.totalFee ?? null,
316
+ openFee: matchedClosedPnl.openFee ?? trade.openFee ?? null,
317
+ closeFee: matchedClosedPnl.closeFee ?? trade.closeFee ?? null,
318
+ fundingFee: matchedClosedPnl.fundingFee ?? trade.fundingFee ?? null,
319
+ totalFee: matchedClosedPnl.totalFee ?? trade.totalFee ?? null,
315
320
  lastSyncedAt: endTime
316
321
  };
317
322
  await Promise.all([
@@ -904,8 +909,7 @@ var isRuntimeTradeClosedInWindow = (trade, startTime, endTime) => {
904
909
  if (trade.status !== "closed" || !isTimestampInWindow(trade.exitTimestamp, startTime, endTime)) {
905
910
  return false;
906
911
  }
907
- const looksLikeSyncFallbackClose = trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null && trade.totalFee == null;
908
- return !looksLikeSyncFallbackClose;
912
+ return !isRuntimeTradeSyncFallbackClose(trade);
909
913
  };
910
914
  var buildSummaryMessages = ({
911
915
  hours,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/cli",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
5
5
  "keywords": [
6
6
  "tradejs",
@@ -29,14 +29,14 @@
29
29
  "tradejs": "dist/cli.js"
30
30
  },
31
31
  "dependencies": {
32
- "@tradejs/base": "^2.0.2",
33
- "@tradejs/connectors": "^2.0.2",
34
- "@tradejs/core": "^2.0.2",
35
- "@tradejs/indicators": "^2.0.2",
36
- "@tradejs/infra": "^2.0.2",
37
- "@tradejs/node": "^2.0.2",
38
- "@tradejs/strategies": "^2.0.2",
39
- "@tradejs/types": "^2.0.2",
32
+ "@tradejs/base": "^2.0.3",
33
+ "@tradejs/connectors": "^2.0.3",
34
+ "@tradejs/core": "^2.0.3",
35
+ "@tradejs/indicators": "^2.0.3",
36
+ "@tradejs/infra": "^2.0.3",
37
+ "@tradejs/node": "^2.0.3",
38
+ "@tradejs/strategies": "^2.0.3",
39
+ "@tradejs/types": "^2.0.3",
40
40
  "args": "^5.0.3",
41
41
  "bcryptjs": "^2.4.3",
42
42
  "chalk": "4.1.2",