@tradejs/cli 3.1.29-beta.268 → 3.1.29-beta.270
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 +165 -5
- package/dist/lib/aiPocketSearch.js +13 -0
- package/dist/lib/aiPocketSearchCli.js +68 -1
- package/dist/scripts/aiPocketSearch.js +163 -4
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -1565,7 +1565,7 @@ var init_aiExport2 = __esm({
|
|
|
1565
1565
|
});
|
|
1566
1566
|
|
|
1567
1567
|
// src/lib/aiPocketSearchCli.ts
|
|
1568
|
-
var DAY_MS, DEFAULT_MIN_SUPPORT, LOW_CADENCE_EVENT_LIMIT, LOW_CADENCE_MAX_EVENT_SHARE, countIndependentEvents, getPeriodDays, clampInt, resolveAiPocketCadenceProfile, AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS, splitAiPocketResearchRowsByTimestamp, sealAiPocketTestPartition, readAiPocketSearchCliOption;
|
|
1568
|
+
var DAY_MS, DEFAULT_MIN_SUPPORT, LOW_CADENCE_EVENT_LIMIT, LOW_CADENCE_MAX_EVENT_SHARE, countIndependentEvents, getPeriodDays, clampInt, resolveAiPocketCadenceProfile, AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS, parseAiPocketTestSince, classifyAiPocketLabelHorizon, splitAiPocketResearchRowsByTimestamp, sealAiPocketTestPartition, readAiPocketSearchCliOption;
|
|
1569
1569
|
var init_aiPocketSearchCli = __esm({
|
|
1570
1570
|
"src/lib/aiPocketSearchCli.ts"() {
|
|
1571
1571
|
"use strict";
|
|
@@ -1660,7 +1660,70 @@ var init_aiPocketSearchCli = __esm({
|
|
|
1660
1660
|
validationSplit: "0",
|
|
1661
1661
|
testSplit: "0.4"
|
|
1662
1662
|
};
|
|
1663
|
-
|
|
1663
|
+
parseAiPocketTestSince = (value) => {
|
|
1664
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
1665
|
+
const numeric = typeof value === "number" || /^\d+$/.test(text);
|
|
1666
|
+
const iso = text.match(
|
|
1667
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,3})?)?(?:Z|[+-]\d{2}:\d{2})$/
|
|
1668
|
+
);
|
|
1669
|
+
const validCalendar = iso != null && Number(iso[2]) >= 1 && Number(iso[2]) <= 12 && Number(iso[3]) >= 1 && Number(iso[3]) <= new Date(Date.UTC(Number(iso[1]), Number(iso[2]), 0)).getUTCDate() && Number(iso[4]) < 24 && Number(iso[5]) < 60 && Number(iso[6] ?? 0) < 60;
|
|
1670
|
+
const timestamp = numeric ? Number(value) : validCalendar ? Date.parse(text) : NaN;
|
|
1671
|
+
if (!Number.isSafeInteger(timestamp) || timestamp <= 0 || timestamp > 864e13) {
|
|
1672
|
+
throw new Error("--testSince requires a valid UTC timestamp or epoch ms");
|
|
1673
|
+
}
|
|
1674
|
+
return timestamp;
|
|
1675
|
+
};
|
|
1676
|
+
classifyAiPocketLabelHorizon = (decisionTimestamp, exitTimestamp, cutoff) => {
|
|
1677
|
+
if (decisionTimestamp >= cutoff) return null;
|
|
1678
|
+
if (typeof exitTimestamp !== "number" || !Number.isFinite(exitTimestamp)) {
|
|
1679
|
+
return "unknown";
|
|
1680
|
+
}
|
|
1681
|
+
if (exitTimestamp < decisionTimestamp) {
|
|
1682
|
+
throw new Error(
|
|
1683
|
+
"--testSince requires label exitTimestamp >= decision timestamp"
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
return exitTimestamp >= cutoff ? "crossing" : null;
|
|
1687
|
+
};
|
|
1688
|
+
splitAiPocketResearchRowsByTimestamp = (rows, validationSplit, testSplit = 0, testSince) => {
|
|
1689
|
+
if (testSince != null) {
|
|
1690
|
+
const cutoff = parseAiPocketTestSince(testSince);
|
|
1691
|
+
if (validationSplit !== 0) {
|
|
1692
|
+
throw new Error("--testSince requires --validationSplit 0");
|
|
1693
|
+
}
|
|
1694
|
+
const trainRows = [];
|
|
1695
|
+
const testRows = [];
|
|
1696
|
+
const labelHorizonPurge = {
|
|
1697
|
+
crossing: 0,
|
|
1698
|
+
unknown: 0
|
|
1699
|
+
};
|
|
1700
|
+
for (const row of rows) {
|
|
1701
|
+
if (typeof row.timestamp !== "number" || !Number.isFinite(row.timestamp)) {
|
|
1702
|
+
throw new Error("--testSince requires a finite timestamp on every row");
|
|
1703
|
+
}
|
|
1704
|
+
const purge = classifyAiPocketLabelHorizon(
|
|
1705
|
+
row.timestamp,
|
|
1706
|
+
row.exitTimestamp,
|
|
1707
|
+
cutoff
|
|
1708
|
+
);
|
|
1709
|
+
if (purge) {
|
|
1710
|
+
labelHorizonPurge[purge] += 1;
|
|
1711
|
+
continue;
|
|
1712
|
+
}
|
|
1713
|
+
(row.timestamp < cutoff ? trainRows : testRows).push(row);
|
|
1714
|
+
}
|
|
1715
|
+
if (!trainRows.length || !testRows.length) {
|
|
1716
|
+
throw new Error(
|
|
1717
|
+
"--testSince requires non-empty development and test partitions"
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
return {
|
|
1721
|
+
trainRows,
|
|
1722
|
+
validationRows: [],
|
|
1723
|
+
testRows,
|
|
1724
|
+
labelHorizonPurge
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1664
1727
|
const timestamps = [
|
|
1665
1728
|
...new Set(
|
|
1666
1729
|
rows.map((row) => row.timestamp).filter((timestamp) => Number.isFinite(timestamp))
|
|
@@ -2043,6 +2106,12 @@ var init_commandOptions = __esm({
|
|
|
2043
2106
|
if (sealTest && testSplit <= 0) {
|
|
2044
2107
|
throw new Error("--sealTest requires a positive --testSplit");
|
|
2045
2108
|
}
|
|
2109
|
+
const explicitTestSince = hasCliOption2(argv2, "testSince");
|
|
2110
|
+
const testSinceInput = explicitTestSince ? readAiPocketSearchCliOption({ argv: argv2, longName: "testSince" }) : flags35.testSince;
|
|
2111
|
+
const testSince = explicitTestSince || testSinceInput != null && testSinceInput !== "" ? parseAiPocketTestSince(testSinceInput) : null;
|
|
2112
|
+
if (testSince != null && validationSplit !== 0) {
|
|
2113
|
+
throw new Error("--testSince requires --validationSplit 0");
|
|
2114
|
+
}
|
|
2046
2115
|
const maxEventCountShare = normalizeUnitRatio(
|
|
2047
2116
|
readAiPocketSearchCliOption({
|
|
2048
2117
|
argv: argv2,
|
|
@@ -2083,6 +2152,7 @@ var init_commandOptions = __esm({
|
|
|
2083
2152
|
maxCombinations: normalizePositiveInt(flags35.maxCombinations, 6e4),
|
|
2084
2153
|
validationSplit,
|
|
2085
2154
|
testSplit,
|
|
2155
|
+
testSince,
|
|
2086
2156
|
sealTest,
|
|
2087
2157
|
explicitMinValidationSupport: normalizeInt(flags35.minValidationSupport, 0),
|
|
2088
2158
|
explicitMinEvents: normalizeInt(flags35.minEvents, 0),
|
|
@@ -4079,6 +4149,19 @@ var init_markdownReport = __esm({
|
|
|
4079
4149
|
["test_rows", run.testRows],
|
|
4080
4150
|
["validation_split", formatMdPercent(run.validationSplit)],
|
|
4081
4151
|
["test_split", formatMdPercent(run.testSplit)],
|
|
4152
|
+
["partition_mode", run.partitionMode ?? "timestamp-ratio"],
|
|
4153
|
+
[
|
|
4154
|
+
"purged_development_crossing_labels",
|
|
4155
|
+
run.labelHorizonPurge?.crossing ?? 0
|
|
4156
|
+
],
|
|
4157
|
+
[
|
|
4158
|
+
"purged_development_unknown_labels",
|
|
4159
|
+
run.labelHorizonPurge?.unknown ?? 0
|
|
4160
|
+
],
|
|
4161
|
+
[
|
|
4162
|
+
"test_since",
|
|
4163
|
+
run.testSince == null ? "n/a" : new Date(run.testSince).toISOString()
|
|
4164
|
+
],
|
|
4082
4165
|
["test_sealed", run.sealedTest?.sealed ? "yes" : "no"],
|
|
4083
4166
|
["sealed_test_rows", run.sealedTest?.rows ?? run.testRows],
|
|
4084
4167
|
["sealed_test_events", run.sealedTest?.events ?? "n/a"],
|
|
@@ -4855,6 +4938,11 @@ var init_presenter = __esm({
|
|
|
4855
4938
|
["max_combinations", import_chalk4.default.magenta(String(maxCombinations))],
|
|
4856
4939
|
["validation_split", import_chalk4.default.magenta(formatRatio(validationSplit))],
|
|
4857
4940
|
["test_split", import_chalk4.default.magenta(formatRatio(testSplit))],
|
|
4941
|
+
["partition_mode", run.partitionMode ?? "timestamp-ratio"],
|
|
4942
|
+
[
|
|
4943
|
+
"test_since",
|
|
4944
|
+
run.testSince == null ? "n/a" : new Date(run.testSince).toISOString()
|
|
4945
|
+
],
|
|
4858
4946
|
[
|
|
4859
4947
|
"test_evidence",
|
|
4860
4948
|
sealedTest.sealed ? import_chalk4.default.green(
|
|
@@ -5248,6 +5336,7 @@ var init_dataset = __esm({
|
|
|
5248
5336
|
import_registry = require("@tradejs/node/registry");
|
|
5249
5337
|
init_aiPocketSearch();
|
|
5250
5338
|
init_aiTrainDataset();
|
|
5339
|
+
init_aiPocketSearchCli();
|
|
5251
5340
|
normalizeQuality = (analysis) => {
|
|
5252
5341
|
const quality = Number(analysis?.quality);
|
|
5253
5342
|
return Number.isFinite(quality) ? Math.round(quality) : null;
|
|
@@ -5412,6 +5501,10 @@ var init_dataset = __esm({
|
|
|
5412
5501
|
let failed = 0;
|
|
5413
5502
|
const errors = [];
|
|
5414
5503
|
const rows = [];
|
|
5504
|
+
const labelHorizonPurge = {
|
|
5505
|
+
crossing: 0,
|
|
5506
|
+
unknown: 0
|
|
5507
|
+
};
|
|
5415
5508
|
const excludedFeaturePaths = /* @__PURE__ */ new Map();
|
|
5416
5509
|
await (0, import_ai4.streamAiDatasetRows)({
|
|
5417
5510
|
filePaths: prepared.filePaths,
|
|
@@ -5422,12 +5515,43 @@ var init_dataset = __esm({
|
|
|
5422
5515
|
if (resolvedStrategyName === "unknown" && typeof row.strategyName === "string" && row.strategyName.trim()) {
|
|
5423
5516
|
resolvedStrategyName = row.strategyName.trim();
|
|
5424
5517
|
}
|
|
5518
|
+
if (options.testSince != null && (typeof row.timestamp !== "number" || !Number.isFinite(row.timestamp))) {
|
|
5519
|
+
throw new Error(
|
|
5520
|
+
"--testSince requires a finite numeric timestamp on every export row"
|
|
5521
|
+
);
|
|
5522
|
+
}
|
|
5425
5523
|
const timestamp = getDatasetRowTimestamp(row);
|
|
5426
5524
|
if (prepared.sinceTimestamp != null && (timestamp == null || timestamp < prepared.sinceTimestamp) || options.untilTimestamp != null && (timestamp == null || timestamp > options.untilTimestamp)) {
|
|
5427
5525
|
dateSkipped += 1;
|
|
5428
5526
|
onProgress?.({ symbol: row.symbol, status: "date-skip" });
|
|
5429
5527
|
return;
|
|
5430
5528
|
}
|
|
5529
|
+
if (options.testSince != null) {
|
|
5530
|
+
const purge = classifyAiPocketLabelHorizon(
|
|
5531
|
+
timestamp,
|
|
5532
|
+
row.tradeResult?.exitTimestamp,
|
|
5533
|
+
options.testSince
|
|
5534
|
+
);
|
|
5535
|
+
if (purge) {
|
|
5536
|
+
labelHorizonPurge[purge] += 1;
|
|
5537
|
+
return;
|
|
5538
|
+
}
|
|
5539
|
+
if (options.sealTest && timestamp >= options.testSince) {
|
|
5540
|
+
rows.push({
|
|
5541
|
+
signalId: row.signalId,
|
|
5542
|
+
strategy: row.strategyName,
|
|
5543
|
+
symbol: row.symbol,
|
|
5544
|
+
direction: row.direction,
|
|
5545
|
+
timestamp,
|
|
5546
|
+
profit: 0,
|
|
5547
|
+
profitableTrade: false,
|
|
5548
|
+
aiApproved: false,
|
|
5549
|
+
quality: null,
|
|
5550
|
+
features: {}
|
|
5551
|
+
});
|
|
5552
|
+
return;
|
|
5553
|
+
}
|
|
5554
|
+
}
|
|
5431
5555
|
try {
|
|
5432
5556
|
const signal = extractSignalFromAiDatasetRow(row);
|
|
5433
5557
|
const payload = (0, import_ai5.buildAiPayload)(signal);
|
|
@@ -5457,6 +5581,7 @@ var init_dataset = __esm({
|
|
|
5457
5581
|
symbol: row.symbol,
|
|
5458
5582
|
direction: row.direction,
|
|
5459
5583
|
timestamp,
|
|
5584
|
+
...options.testSince != null ? { exitTimestamp: row.tradeResult?.exitTimestamp } : {},
|
|
5460
5585
|
profit,
|
|
5461
5586
|
profitableTrade: profit > 0,
|
|
5462
5587
|
aiApproved: isAiApproval(row, analysis, options.minQuality),
|
|
@@ -5479,6 +5604,7 @@ var init_dataset = __esm({
|
|
|
5479
5604
|
}
|
|
5480
5605
|
});
|
|
5481
5606
|
return {
|
|
5607
|
+
labelHorizonPurge,
|
|
5482
5608
|
rows,
|
|
5483
5609
|
resolvedStrategyName,
|
|
5484
5610
|
scanned,
|
|
@@ -5915,7 +6041,8 @@ var init_research = __esm({
|
|
|
5915
6041
|
runAiPocketSearchResearch = ({
|
|
5916
6042
|
rows,
|
|
5917
6043
|
options,
|
|
5918
|
-
onProgress
|
|
6044
|
+
onProgress,
|
|
6045
|
+
datasetLabelHorizonPurge
|
|
5919
6046
|
}) => {
|
|
5920
6047
|
const {
|
|
5921
6048
|
direction,
|
|
@@ -5923,6 +6050,7 @@ var init_research = __esm({
|
|
|
5923
6050
|
qualityThresholds,
|
|
5924
6051
|
validationSplit,
|
|
5925
6052
|
testSplit,
|
|
6053
|
+
testSince,
|
|
5926
6054
|
sealTest,
|
|
5927
6055
|
cadenceMode,
|
|
5928
6056
|
explicitMinSupport,
|
|
@@ -5947,14 +6075,30 @@ var init_research = __esm({
|
|
|
5947
6075
|
coverageMode
|
|
5948
6076
|
} = options;
|
|
5949
6077
|
const directionRows = direction ? rows.filter((row) => row.direction === direction) : rows;
|
|
5950
|
-
const
|
|
5951
|
-
|
|
6078
|
+
const calendarSplit = testSince != null ? splitAiPocketResearchRowsByTimestamp(
|
|
6079
|
+
rows,
|
|
6080
|
+
validationSplit,
|
|
6081
|
+
testSplit,
|
|
6082
|
+
testSince
|
|
6083
|
+
) : null;
|
|
6084
|
+
const inDirection = (row) => !direction || row.direction === direction;
|
|
6085
|
+
const fullSplit = calendarSplit ? {
|
|
6086
|
+
trainRows: calendarSplit.trainRows.filter(inDirection),
|
|
6087
|
+
validationRows: calendarSplit.validationRows.filter(inDirection),
|
|
6088
|
+
testRows: calendarSplit.testRows.filter(inDirection)
|
|
6089
|
+
} : splitAiPocketResearchRowsByTimestamp(
|
|
5952
6090
|
directionRows,
|
|
5953
6091
|
validationSplit,
|
|
5954
6092
|
testSplit
|
|
5955
6093
|
);
|
|
6094
|
+
if (testSince != null && (!fullSplit.trainRows.length || !fullSplit.testRows.length)) {
|
|
6095
|
+
throw new Error(
|
|
6096
|
+
"--testSince requires non-empty development and test partitions for the selected direction"
|
|
6097
|
+
);
|
|
6098
|
+
}
|
|
5956
6099
|
const sealedFullSplit = sealAiPocketTestPartition(fullSplit, sealTest);
|
|
5957
6100
|
const discoveryRows = sealedFullSplit.discoveryRows;
|
|
6101
|
+
const scopeRows = resolveScopeRows(discoveryRows, scope);
|
|
5958
6102
|
const trainRows = resolveScopeRows(fullSplit.trainRows, scope);
|
|
5959
6103
|
const validationRows = resolveScopeRows(fullSplit.validationRows, scope);
|
|
5960
6104
|
const testRows = resolveScopeRows(sealedFullSplit.searchTestRows, scope);
|
|
@@ -6107,6 +6251,12 @@ var init_research = __esm({
|
|
|
6107
6251
|
}
|
|
6108
6252
|
}
|
|
6109
6253
|
return {
|
|
6254
|
+
...calendarSplit ? {
|
|
6255
|
+
labelHorizonPurge: {
|
|
6256
|
+
crossing: (calendarSplit.labelHorizonPurge?.crossing ?? 0) + (datasetLabelHorizonPurge?.crossing ?? 0),
|
|
6257
|
+
unknown: (calendarSplit.labelHorizonPurge?.unknown ?? 0) + (datasetLabelHorizonPurge?.unknown ?? 0)
|
|
6258
|
+
}
|
|
6259
|
+
} : {},
|
|
6110
6260
|
scopeRows,
|
|
6111
6261
|
trainRows,
|
|
6112
6262
|
validationRows,
|
|
@@ -6154,6 +6304,7 @@ var init_command = __esm({
|
|
|
6154
6304
|
maxCombinations,
|
|
6155
6305
|
validationSplit,
|
|
6156
6306
|
testSplit,
|
|
6307
|
+
testSince,
|
|
6157
6308
|
maxBatch,
|
|
6158
6309
|
maxSymbolCountShare,
|
|
6159
6310
|
objective,
|
|
@@ -6201,6 +6352,7 @@ var init_command = __esm({
|
|
|
6201
6352
|
const research = runAiPocketSearchResearch({
|
|
6202
6353
|
rows,
|
|
6203
6354
|
options,
|
|
6355
|
+
datasetLabelHorizonPurge: evaluatedDataset.labelHorizonPurge,
|
|
6204
6356
|
onProgress: createAiPocketSearchResearchProgressPresenter()
|
|
6205
6357
|
});
|
|
6206
6358
|
const {
|
|
@@ -6274,6 +6426,9 @@ var init_command = __esm({
|
|
|
6274
6426
|
objective,
|
|
6275
6427
|
validationSplit,
|
|
6276
6428
|
testSplit,
|
|
6429
|
+
testSince,
|
|
6430
|
+
partitionMode: testSince == null ? "timestamp-ratio" : "calendar-cutoff",
|
|
6431
|
+
...research.labelHorizonPurge ? { labelHorizonPurge: research.labelHorizonPurge } : {},
|
|
6277
6432
|
sealedTest,
|
|
6278
6433
|
minValidationSupport: search.stats.cadence.minValidationSupport,
|
|
6279
6434
|
reportPath,
|
|
@@ -6423,6 +6578,11 @@ var init_aiPocketSearch2 = __esm({
|
|
|
6423
6578
|
"Trailing timestamp-grouped test share; default 0.4 (outer 60/40)",
|
|
6424
6579
|
AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS.testSplit
|
|
6425
6580
|
);
|
|
6581
|
+
import_args3.default.option(
|
|
6582
|
+
["z", "testSince"],
|
|
6583
|
+
"Fixed calendar test boundary (UTC ISO or epoch ms); overrides the split ratio and requires validationSplit 0",
|
|
6584
|
+
""
|
|
6585
|
+
);
|
|
6426
6586
|
import_args3.default.option(
|
|
6427
6587
|
["w", "sealTest"],
|
|
6428
6588
|
"Reserve test bounds without exposing its rows or economics to discovery",
|
|
@@ -1966,6 +1966,19 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1966
1966
|
["test_rows", run.testRows],
|
|
1967
1967
|
["validation_split", formatMdPercent(run.validationSplit)],
|
|
1968
1968
|
["test_split", formatMdPercent(run.testSplit)],
|
|
1969
|
+
["partition_mode", run.partitionMode ?? "timestamp-ratio"],
|
|
1970
|
+
[
|
|
1971
|
+
"purged_development_crossing_labels",
|
|
1972
|
+
run.labelHorizonPurge?.crossing ?? 0
|
|
1973
|
+
],
|
|
1974
|
+
[
|
|
1975
|
+
"purged_development_unknown_labels",
|
|
1976
|
+
run.labelHorizonPurge?.unknown ?? 0
|
|
1977
|
+
],
|
|
1978
|
+
[
|
|
1979
|
+
"test_since",
|
|
1980
|
+
run.testSince == null ? "n/a" : new Date(run.testSince).toISOString()
|
|
1981
|
+
],
|
|
1969
1982
|
["test_sealed", run.sealedTest?.sealed ? "yes" : "no"],
|
|
1970
1983
|
["sealed_test_rows", run.sealedTest?.rows ?? run.testRows],
|
|
1971
1984
|
["sealed_test_events", run.sealedTest?.events ?? "n/a"],
|
|
@@ -21,6 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var aiPocketSearchCli_exports = {};
|
|
22
22
|
__export(aiPocketSearchCli_exports, {
|
|
23
23
|
AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS: () => AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS,
|
|
24
|
+
classifyAiPocketLabelHorizon: () => classifyAiPocketLabelHorizon,
|
|
25
|
+
parseAiPocketTestSince: () => parseAiPocketTestSince,
|
|
24
26
|
readAiPocketSearchCliOption: () => readAiPocketSearchCliOption,
|
|
25
27
|
resolveAiPocketCadenceProfile: () => resolveAiPocketCadenceProfile,
|
|
26
28
|
sealAiPocketTestPartition: () => sealAiPocketTestPartition,
|
|
@@ -119,7 +121,70 @@ var AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS = {
|
|
|
119
121
|
validationSplit: "0",
|
|
120
122
|
testSplit: "0.4"
|
|
121
123
|
};
|
|
122
|
-
var
|
|
124
|
+
var parseAiPocketTestSince = (value) => {
|
|
125
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
126
|
+
const numeric = typeof value === "number" || /^\d+$/.test(text);
|
|
127
|
+
const iso = text.match(
|
|
128
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,3})?)?(?:Z|[+-]\d{2}:\d{2})$/
|
|
129
|
+
);
|
|
130
|
+
const validCalendar = iso != null && Number(iso[2]) >= 1 && Number(iso[2]) <= 12 && Number(iso[3]) >= 1 && Number(iso[3]) <= new Date(Date.UTC(Number(iso[1]), Number(iso[2]), 0)).getUTCDate() && Number(iso[4]) < 24 && Number(iso[5]) < 60 && Number(iso[6] ?? 0) < 60;
|
|
131
|
+
const timestamp = numeric ? Number(value) : validCalendar ? Date.parse(text) : NaN;
|
|
132
|
+
if (!Number.isSafeInteger(timestamp) || timestamp <= 0 || timestamp > 864e13) {
|
|
133
|
+
throw new Error("--testSince requires a valid UTC timestamp or epoch ms");
|
|
134
|
+
}
|
|
135
|
+
return timestamp;
|
|
136
|
+
};
|
|
137
|
+
var classifyAiPocketLabelHorizon = (decisionTimestamp, exitTimestamp, cutoff) => {
|
|
138
|
+
if (decisionTimestamp >= cutoff) return null;
|
|
139
|
+
if (typeof exitTimestamp !== "number" || !Number.isFinite(exitTimestamp)) {
|
|
140
|
+
return "unknown";
|
|
141
|
+
}
|
|
142
|
+
if (exitTimestamp < decisionTimestamp) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
"--testSince requires label exitTimestamp >= decision timestamp"
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return exitTimestamp >= cutoff ? "crossing" : null;
|
|
148
|
+
};
|
|
149
|
+
var splitAiPocketResearchRowsByTimestamp = (rows, validationSplit, testSplit = 0, testSince) => {
|
|
150
|
+
if (testSince != null) {
|
|
151
|
+
const cutoff = parseAiPocketTestSince(testSince);
|
|
152
|
+
if (validationSplit !== 0) {
|
|
153
|
+
throw new Error("--testSince requires --validationSplit 0");
|
|
154
|
+
}
|
|
155
|
+
const trainRows = [];
|
|
156
|
+
const testRows = [];
|
|
157
|
+
const labelHorizonPurge = {
|
|
158
|
+
crossing: 0,
|
|
159
|
+
unknown: 0
|
|
160
|
+
};
|
|
161
|
+
for (const row of rows) {
|
|
162
|
+
if (typeof row.timestamp !== "number" || !Number.isFinite(row.timestamp)) {
|
|
163
|
+
throw new Error("--testSince requires a finite timestamp on every row");
|
|
164
|
+
}
|
|
165
|
+
const purge = classifyAiPocketLabelHorizon(
|
|
166
|
+
row.timestamp,
|
|
167
|
+
row.exitTimestamp,
|
|
168
|
+
cutoff
|
|
169
|
+
);
|
|
170
|
+
if (purge) {
|
|
171
|
+
labelHorizonPurge[purge] += 1;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
(row.timestamp < cutoff ? trainRows : testRows).push(row);
|
|
175
|
+
}
|
|
176
|
+
if (!trainRows.length || !testRows.length) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
"--testSince requires non-empty development and test partitions"
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
trainRows,
|
|
183
|
+
validationRows: [],
|
|
184
|
+
testRows,
|
|
185
|
+
labelHorizonPurge
|
|
186
|
+
};
|
|
187
|
+
}
|
|
123
188
|
const timestamps = [
|
|
124
189
|
...new Set(
|
|
125
190
|
rows.map((row) => row.timestamp).filter((timestamp) => Number.isFinite(timestamp))
|
|
@@ -201,6 +266,8 @@ var readAiPocketSearchCliOption = ({
|
|
|
201
266
|
// Annotate the CommonJS export names for ESM import in node:
|
|
202
267
|
0 && (module.exports = {
|
|
203
268
|
AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS,
|
|
269
|
+
classifyAiPocketLabelHorizon,
|
|
270
|
+
parseAiPocketTestSince,
|
|
204
271
|
readAiPocketSearchCliOption,
|
|
205
272
|
resolveAiPocketCadenceProfile,
|
|
206
273
|
sealAiPocketTestPartition,
|
|
@@ -127,7 +127,70 @@ var AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS = {
|
|
|
127
127
|
validationSplit: "0",
|
|
128
128
|
testSplit: "0.4"
|
|
129
129
|
};
|
|
130
|
-
var
|
|
130
|
+
var parseAiPocketTestSince = (value) => {
|
|
131
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
132
|
+
const numeric = typeof value === "number" || /^\d+$/.test(text);
|
|
133
|
+
const iso = text.match(
|
|
134
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,3})?)?(?:Z|[+-]\d{2}:\d{2})$/
|
|
135
|
+
);
|
|
136
|
+
const validCalendar = iso != null && Number(iso[2]) >= 1 && Number(iso[2]) <= 12 && Number(iso[3]) >= 1 && Number(iso[3]) <= new Date(Date.UTC(Number(iso[1]), Number(iso[2]), 0)).getUTCDate() && Number(iso[4]) < 24 && Number(iso[5]) < 60 && Number(iso[6] ?? 0) < 60;
|
|
137
|
+
const timestamp = numeric ? Number(value) : validCalendar ? Date.parse(text) : NaN;
|
|
138
|
+
if (!Number.isSafeInteger(timestamp) || timestamp <= 0 || timestamp > 864e13) {
|
|
139
|
+
throw new Error("--testSince requires a valid UTC timestamp or epoch ms");
|
|
140
|
+
}
|
|
141
|
+
return timestamp;
|
|
142
|
+
};
|
|
143
|
+
var classifyAiPocketLabelHorizon = (decisionTimestamp, exitTimestamp, cutoff) => {
|
|
144
|
+
if (decisionTimestamp >= cutoff) return null;
|
|
145
|
+
if (typeof exitTimestamp !== "number" || !Number.isFinite(exitTimestamp)) {
|
|
146
|
+
return "unknown";
|
|
147
|
+
}
|
|
148
|
+
if (exitTimestamp < decisionTimestamp) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
"--testSince requires label exitTimestamp >= decision timestamp"
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
return exitTimestamp >= cutoff ? "crossing" : null;
|
|
154
|
+
};
|
|
155
|
+
var splitAiPocketResearchRowsByTimestamp = (rows, validationSplit, testSplit = 0, testSince) => {
|
|
156
|
+
if (testSince != null) {
|
|
157
|
+
const cutoff = parseAiPocketTestSince(testSince);
|
|
158
|
+
if (validationSplit !== 0) {
|
|
159
|
+
throw new Error("--testSince requires --validationSplit 0");
|
|
160
|
+
}
|
|
161
|
+
const trainRows = [];
|
|
162
|
+
const testRows = [];
|
|
163
|
+
const labelHorizonPurge = {
|
|
164
|
+
crossing: 0,
|
|
165
|
+
unknown: 0
|
|
166
|
+
};
|
|
167
|
+
for (const row of rows) {
|
|
168
|
+
if (typeof row.timestamp !== "number" || !Number.isFinite(row.timestamp)) {
|
|
169
|
+
throw new Error("--testSince requires a finite timestamp on every row");
|
|
170
|
+
}
|
|
171
|
+
const purge = classifyAiPocketLabelHorizon(
|
|
172
|
+
row.timestamp,
|
|
173
|
+
row.exitTimestamp,
|
|
174
|
+
cutoff
|
|
175
|
+
);
|
|
176
|
+
if (purge) {
|
|
177
|
+
labelHorizonPurge[purge] += 1;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
(row.timestamp < cutoff ? trainRows : testRows).push(row);
|
|
181
|
+
}
|
|
182
|
+
if (!trainRows.length || !testRows.length) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
"--testSince requires non-empty development and test partitions"
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
trainRows,
|
|
189
|
+
validationRows: [],
|
|
190
|
+
testRows,
|
|
191
|
+
labelHorizonPurge
|
|
192
|
+
};
|
|
193
|
+
}
|
|
131
194
|
const timestamps = [
|
|
132
195
|
...new Set(
|
|
133
196
|
rows.map((row) => row.timestamp).filter((timestamp) => Number.isFinite(timestamp))
|
|
@@ -445,6 +508,12 @@ var resolveAiPocketSearchCommandOptions = ({
|
|
|
445
508
|
if (sealTest && testSplit <= 0) {
|
|
446
509
|
throw new Error("--sealTest requires a positive --testSplit");
|
|
447
510
|
}
|
|
511
|
+
const explicitTestSince = hasCliOption2(argv, "testSince");
|
|
512
|
+
const testSinceInput = explicitTestSince ? readAiPocketSearchCliOption({ argv, longName: "testSince" }) : flags2.testSince;
|
|
513
|
+
const testSince = explicitTestSince || testSinceInput != null && testSinceInput !== "" ? parseAiPocketTestSince(testSinceInput) : null;
|
|
514
|
+
if (testSince != null && validationSplit !== 0) {
|
|
515
|
+
throw new Error("--testSince requires --validationSplit 0");
|
|
516
|
+
}
|
|
448
517
|
const maxEventCountShare = normalizeUnitRatio(
|
|
449
518
|
readAiPocketSearchCliOption({
|
|
450
519
|
argv,
|
|
@@ -485,6 +554,7 @@ var resolveAiPocketSearchCommandOptions = ({
|
|
|
485
554
|
maxCombinations: normalizePositiveInt(flags2.maxCombinations, 6e4),
|
|
486
555
|
validationSplit,
|
|
487
556
|
testSplit,
|
|
557
|
+
testSince,
|
|
488
558
|
sealTest,
|
|
489
559
|
explicitMinValidationSupport: normalizeInt(flags2.minValidationSupport, 0),
|
|
490
560
|
explicitMinEvents: normalizeInt(flags2.minEvents, 0),
|
|
@@ -2452,6 +2522,19 @@ var buildAiPocketMarkdownReport = ({
|
|
|
2452
2522
|
["test_rows", run.testRows],
|
|
2453
2523
|
["validation_split", formatMdPercent(run.validationSplit)],
|
|
2454
2524
|
["test_split", formatMdPercent(run.testSplit)],
|
|
2525
|
+
["partition_mode", run.partitionMode ?? "timestamp-ratio"],
|
|
2526
|
+
[
|
|
2527
|
+
"purged_development_crossing_labels",
|
|
2528
|
+
run.labelHorizonPurge?.crossing ?? 0
|
|
2529
|
+
],
|
|
2530
|
+
[
|
|
2531
|
+
"purged_development_unknown_labels",
|
|
2532
|
+
run.labelHorizonPurge?.unknown ?? 0
|
|
2533
|
+
],
|
|
2534
|
+
[
|
|
2535
|
+
"test_since",
|
|
2536
|
+
run.testSince == null ? "n/a" : new Date(run.testSince).toISOString()
|
|
2537
|
+
],
|
|
2455
2538
|
["test_sealed", run.sealedTest?.sealed ? "yes" : "no"],
|
|
2456
2539
|
["sealed_test_rows", run.sealedTest?.rows ?? run.testRows],
|
|
2457
2540
|
["sealed_test_events", run.sealedTest?.events ?? "n/a"],
|
|
@@ -3204,6 +3287,11 @@ var presentAiPocketSearchResult = ({
|
|
|
3204
3287
|
["max_combinations", import_chalk.default.magenta(String(maxCombinations))],
|
|
3205
3288
|
["validation_split", import_chalk.default.magenta(formatRatio(validationSplit))],
|
|
3206
3289
|
["test_split", import_chalk.default.magenta(formatRatio(testSplit))],
|
|
3290
|
+
["partition_mode", run.partitionMode ?? "timestamp-ratio"],
|
|
3291
|
+
[
|
|
3292
|
+
"test_since",
|
|
3293
|
+
run.testSince == null ? "n/a" : new Date(run.testSince).toISOString()
|
|
3294
|
+
],
|
|
3207
3295
|
[
|
|
3208
3296
|
"test_evidence",
|
|
3209
3297
|
sealedTest.sealed ? import_chalk.default.green(
|
|
@@ -3749,6 +3837,10 @@ var evaluateAiPocketSearchDataset = async ({
|
|
|
3749
3837
|
let failed = 0;
|
|
3750
3838
|
const errors = [];
|
|
3751
3839
|
const rows = [];
|
|
3840
|
+
const labelHorizonPurge = {
|
|
3841
|
+
crossing: 0,
|
|
3842
|
+
unknown: 0
|
|
3843
|
+
};
|
|
3752
3844
|
const excludedFeaturePaths = /* @__PURE__ */ new Map();
|
|
3753
3845
|
await (0, import_ai2.streamAiDatasetRows)({
|
|
3754
3846
|
filePaths: prepared.filePaths,
|
|
@@ -3759,12 +3851,43 @@ var evaluateAiPocketSearchDataset = async ({
|
|
|
3759
3851
|
if (resolvedStrategyName === "unknown" && typeof row.strategyName === "string" && row.strategyName.trim()) {
|
|
3760
3852
|
resolvedStrategyName = row.strategyName.trim();
|
|
3761
3853
|
}
|
|
3854
|
+
if (options.testSince != null && (typeof row.timestamp !== "number" || !Number.isFinite(row.timestamp))) {
|
|
3855
|
+
throw new Error(
|
|
3856
|
+
"--testSince requires a finite numeric timestamp on every export row"
|
|
3857
|
+
);
|
|
3858
|
+
}
|
|
3762
3859
|
const timestamp = getDatasetRowTimestamp(row);
|
|
3763
3860
|
if (prepared.sinceTimestamp != null && (timestamp == null || timestamp < prepared.sinceTimestamp) || options.untilTimestamp != null && (timestamp == null || timestamp > options.untilTimestamp)) {
|
|
3764
3861
|
dateSkipped += 1;
|
|
3765
3862
|
onProgress?.({ symbol: row.symbol, status: "date-skip" });
|
|
3766
3863
|
return;
|
|
3767
3864
|
}
|
|
3865
|
+
if (options.testSince != null) {
|
|
3866
|
+
const purge = classifyAiPocketLabelHorizon(
|
|
3867
|
+
timestamp,
|
|
3868
|
+
row.tradeResult?.exitTimestamp,
|
|
3869
|
+
options.testSince
|
|
3870
|
+
);
|
|
3871
|
+
if (purge) {
|
|
3872
|
+
labelHorizonPurge[purge] += 1;
|
|
3873
|
+
return;
|
|
3874
|
+
}
|
|
3875
|
+
if (options.sealTest && timestamp >= options.testSince) {
|
|
3876
|
+
rows.push({
|
|
3877
|
+
signalId: row.signalId,
|
|
3878
|
+
strategy: row.strategyName,
|
|
3879
|
+
symbol: row.symbol,
|
|
3880
|
+
direction: row.direction,
|
|
3881
|
+
timestamp,
|
|
3882
|
+
profit: 0,
|
|
3883
|
+
profitableTrade: false,
|
|
3884
|
+
aiApproved: false,
|
|
3885
|
+
quality: null,
|
|
3886
|
+
features: {}
|
|
3887
|
+
});
|
|
3888
|
+
return;
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3768
3891
|
try {
|
|
3769
3892
|
const signal = extractSignalFromAiDatasetRow(row);
|
|
3770
3893
|
const payload = (0, import_ai3.buildAiPayload)(signal);
|
|
@@ -3794,6 +3917,7 @@ var evaluateAiPocketSearchDataset = async ({
|
|
|
3794
3917
|
symbol: row.symbol,
|
|
3795
3918
|
direction: row.direction,
|
|
3796
3919
|
timestamp,
|
|
3920
|
+
...options.testSince != null ? { exitTimestamp: row.tradeResult?.exitTimestamp } : {},
|
|
3797
3921
|
profit,
|
|
3798
3922
|
profitableTrade: profit > 0,
|
|
3799
3923
|
aiApproved: isAiApproval(row, analysis, options.minQuality),
|
|
@@ -3816,6 +3940,7 @@ var evaluateAiPocketSearchDataset = async ({
|
|
|
3816
3940
|
}
|
|
3817
3941
|
});
|
|
3818
3942
|
return {
|
|
3943
|
+
labelHorizonPurge,
|
|
3819
3944
|
rows,
|
|
3820
3945
|
resolvedStrategyName,
|
|
3821
3946
|
scanned,
|
|
@@ -4182,7 +4307,8 @@ var resolveScopeRows = (rows, scope) => {
|
|
|
4182
4307
|
var runAiPocketSearchResearch = ({
|
|
4183
4308
|
rows,
|
|
4184
4309
|
options,
|
|
4185
|
-
onProgress
|
|
4310
|
+
onProgress,
|
|
4311
|
+
datasetLabelHorizonPurge
|
|
4186
4312
|
}) => {
|
|
4187
4313
|
const {
|
|
4188
4314
|
direction,
|
|
@@ -4190,6 +4316,7 @@ var runAiPocketSearchResearch = ({
|
|
|
4190
4316
|
qualityThresholds,
|
|
4191
4317
|
validationSplit,
|
|
4192
4318
|
testSplit,
|
|
4319
|
+
testSince,
|
|
4193
4320
|
sealTest,
|
|
4194
4321
|
cadenceMode,
|
|
4195
4322
|
explicitMinSupport,
|
|
@@ -4214,14 +4341,30 @@ var runAiPocketSearchResearch = ({
|
|
|
4214
4341
|
coverageMode
|
|
4215
4342
|
} = options;
|
|
4216
4343
|
const directionRows = direction ? rows.filter((row) => row.direction === direction) : rows;
|
|
4217
|
-
const
|
|
4218
|
-
|
|
4344
|
+
const calendarSplit = testSince != null ? splitAiPocketResearchRowsByTimestamp(
|
|
4345
|
+
rows,
|
|
4346
|
+
validationSplit,
|
|
4347
|
+
testSplit,
|
|
4348
|
+
testSince
|
|
4349
|
+
) : null;
|
|
4350
|
+
const inDirection = (row) => !direction || row.direction === direction;
|
|
4351
|
+
const fullSplit = calendarSplit ? {
|
|
4352
|
+
trainRows: calendarSplit.trainRows.filter(inDirection),
|
|
4353
|
+
validationRows: calendarSplit.validationRows.filter(inDirection),
|
|
4354
|
+
testRows: calendarSplit.testRows.filter(inDirection)
|
|
4355
|
+
} : splitAiPocketResearchRowsByTimestamp(
|
|
4219
4356
|
directionRows,
|
|
4220
4357
|
validationSplit,
|
|
4221
4358
|
testSplit
|
|
4222
4359
|
);
|
|
4360
|
+
if (testSince != null && (!fullSplit.trainRows.length || !fullSplit.testRows.length)) {
|
|
4361
|
+
throw new Error(
|
|
4362
|
+
"--testSince requires non-empty development and test partitions for the selected direction"
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4223
4365
|
const sealedFullSplit = sealAiPocketTestPartition(fullSplit, sealTest);
|
|
4224
4366
|
const discoveryRows = sealedFullSplit.discoveryRows;
|
|
4367
|
+
const scopeRows = resolveScopeRows(discoveryRows, scope);
|
|
4225
4368
|
const trainRows = resolveScopeRows(fullSplit.trainRows, scope);
|
|
4226
4369
|
const validationRows = resolveScopeRows(fullSplit.validationRows, scope);
|
|
4227
4370
|
const testRows = resolveScopeRows(sealedFullSplit.searchTestRows, scope);
|
|
@@ -4374,6 +4517,12 @@ var runAiPocketSearchResearch = ({
|
|
|
4374
4517
|
}
|
|
4375
4518
|
}
|
|
4376
4519
|
return {
|
|
4520
|
+
...calendarSplit ? {
|
|
4521
|
+
labelHorizonPurge: {
|
|
4522
|
+
crossing: (calendarSplit.labelHorizonPurge?.crossing ?? 0) + (datasetLabelHorizonPurge?.crossing ?? 0),
|
|
4523
|
+
unknown: (calendarSplit.labelHorizonPurge?.unknown ?? 0) + (datasetLabelHorizonPurge?.unknown ?? 0)
|
|
4524
|
+
}
|
|
4525
|
+
} : {},
|
|
4377
4526
|
scopeRows,
|
|
4378
4527
|
trainRows,
|
|
4379
4528
|
validationRows,
|
|
@@ -4411,6 +4560,7 @@ var runAiPocketSearchCommand = async ({
|
|
|
4411
4560
|
maxCombinations,
|
|
4412
4561
|
validationSplit,
|
|
4413
4562
|
testSplit,
|
|
4563
|
+
testSince,
|
|
4414
4564
|
maxBatch,
|
|
4415
4565
|
maxSymbolCountShare,
|
|
4416
4566
|
objective,
|
|
@@ -4458,6 +4608,7 @@ var runAiPocketSearchCommand = async ({
|
|
|
4458
4608
|
const research = runAiPocketSearchResearch({
|
|
4459
4609
|
rows,
|
|
4460
4610
|
options,
|
|
4611
|
+
datasetLabelHorizonPurge: evaluatedDataset.labelHorizonPurge,
|
|
4461
4612
|
onProgress: createAiPocketSearchResearchProgressPresenter()
|
|
4462
4613
|
});
|
|
4463
4614
|
const {
|
|
@@ -4531,6 +4682,9 @@ var runAiPocketSearchCommand = async ({
|
|
|
4531
4682
|
objective,
|
|
4532
4683
|
validationSplit,
|
|
4533
4684
|
testSplit,
|
|
4685
|
+
testSince,
|
|
4686
|
+
partitionMode: testSince == null ? "timestamp-ratio" : "calendar-cutoff",
|
|
4687
|
+
...research.labelHorizonPurge ? { labelHorizonPurge: research.labelHorizonPurge } : {},
|
|
4534
4688
|
sealedTest,
|
|
4535
4689
|
minValidationSupport: search.stats.cadence.minValidationSupport,
|
|
4536
4690
|
reportPath,
|
|
@@ -4667,6 +4821,11 @@ import_args.default.option(
|
|
|
4667
4821
|
"Trailing timestamp-grouped test share; default 0.4 (outer 60/40)",
|
|
4668
4822
|
AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS.testSplit
|
|
4669
4823
|
);
|
|
4824
|
+
import_args.default.option(
|
|
4825
|
+
["z", "testSince"],
|
|
4826
|
+
"Fixed calendar test boundary (UTC ISO or epoch ms); overrides the split ratio and requires validationSplit 0",
|
|
4827
|
+
""
|
|
4828
|
+
);
|
|
4670
4829
|
import_args.default.option(
|
|
4671
4830
|
["w", "sealTest"],
|
|
4672
4831
|
"Reserve test bounds without exposing its rows or economics to discovery",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "3.1.29-beta.
|
|
3
|
+
"version": "3.1.29-beta.270",
|
|
4
4
|
"description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"tradejs": "dist/cli.js"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@tradejs/connectors": "^3.1.29-beta.
|
|
41
|
-
"@tradejs/core": "^3.1.29-beta.
|
|
42
|
-
"@tradejs/indicators": "^3.1.29-beta.
|
|
43
|
-
"@tradejs/infra": "^3.1.29-beta.
|
|
44
|
-
"@tradejs/node": "^3.1.29-beta.
|
|
40
|
+
"@tradejs/connectors": "^3.1.29-beta.270",
|
|
41
|
+
"@tradejs/core": "^3.1.29-beta.270",
|
|
42
|
+
"@tradejs/indicators": "^3.1.29-beta.270",
|
|
43
|
+
"@tradejs/infra": "^3.1.29-beta.270",
|
|
44
|
+
"@tradejs/node": "^3.1.29-beta.270",
|
|
45
45
|
"@tradejs/strategy-kit": "3.0.6",
|
|
46
|
-
"@tradejs/types": "^3.1.29-beta.
|
|
46
|
+
"@tradejs/types": "^3.1.29-beta.270",
|
|
47
47
|
"args": "^5.0.3",
|
|
48
48
|
"bcryptjs": "^2.4.3",
|
|
49
49
|
"chalk": "4.1.2",
|