@tradejs/cli 1.0.9 → 1.0.10

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.
Files changed (76) hide show
  1. package/dist/cli.js +29497 -13537
  2. package/dist/lib/aiPocketSearch.js +1316 -0
  3. package/dist/lib/aiTrainCharts.js +711 -0
  4. package/dist/lib/aiTrainDataset.js +40 -0
  5. package/dist/lib/aiTrainEvaluationDump.js +76 -0
  6. package/dist/lib/aiTrainMetrics.js +148 -8
  7. package/dist/lib/aiTrainOptions.js +130 -0
  8. package/dist/lib/aiTrainQuarantine.js +199 -0
  9. package/dist/lib/aiTrainResearch.js +467 -0
  10. package/dist/lib/binanceMarketContextBackfill.js +841 -0
  11. package/dist/lib/binanceMarketData.js +392 -0
  12. package/dist/lib/coinMarketCapContextBackfill.js +1088 -0
  13. package/dist/lib/continuity.js +60 -0
  14. package/dist/lib/derivativesContextBackfill.js +490 -77
  15. package/dist/lib/executionCalibration.js +705 -0
  16. package/dist/lib/marketContextPrepare.js +4403 -0
  17. package/dist/lib/paritySummary.js +101 -0
  18. package/dist/lib/runBot.js +1 -0
  19. package/dist/lib/runEnvironment.js +2254 -0
  20. package/dist/lib/runFormatting.js +1657 -0
  21. package/dist/lib/runtimeDebugEvidence.js +526 -0
  22. package/dist/lib/runtimeModeConfig.js +53 -0
  23. package/dist/lib/runtimeParity.js +88 -11
  24. package/dist/lib/runtimeParityDetails.js +751 -0
  25. package/dist/lib/runtimeRedis.js +157 -0
  26. package/dist/lib/runtimeSignalsLoader.js +40 -6
  27. package/dist/lib/runtimeSignalsStorage.js +45 -22
  28. package/dist/lib/runtimeStrategyBacktest.js +134 -0
  29. package/dist/lib/runtimeTradeSync.js +263 -0
  30. package/dist/lib/telegramReports.js +9 -0
  31. package/dist/lib/tickerUniverseCache.js +116 -0
  32. package/dist/lib/timeWindow.js +3 -3
  33. package/dist/scripts/agentRun.js +14 -8
  34. package/dist/scripts/aiExport.js +1721 -7
  35. package/dist/scripts/aiExportSelect.js +16 -4
  36. package/dist/scripts/aiPocketSearch.js +4190 -0
  37. package/dist/scripts/aiTrain.js +1866 -87
  38. package/dist/scripts/backtest.js +4509 -818
  39. package/dist/scripts/binanceMarketIngest.js +565 -0
  40. package/dist/scripts/bot.js +16 -2
  41. package/dist/scripts/candlesMigrateProvider.js +32 -22
  42. package/dist/scripts/cleanDir.js +15 -2
  43. package/dist/scripts/cleanRedis.js +15 -2
  44. package/dist/scripts/cleanTests.js +38 -2
  45. package/dist/scripts/cleanupMarketContext.js +69 -0
  46. package/dist/scripts/continuity.js +148 -67
  47. package/dist/scripts/derivativesIngest.js +14 -4
  48. package/dist/scripts/derivativesIngestCoinalyzeAll.js +14 -4
  49. package/dist/scripts/doctor.js +14 -4
  50. package/dist/scripts/executionCalibration.js +792 -0
  51. package/dist/scripts/infraCommon.js +10 -0
  52. package/dist/scripts/infraDown.js +14 -4
  53. package/dist/scripts/infraInit.js +24 -4
  54. package/dist/scripts/infraUp.js +14 -4
  55. package/dist/scripts/marketWs.js +222 -0
  56. package/dist/scripts/migration.js +15 -2
  57. package/dist/scripts/mlExport.js +1698 -10
  58. package/dist/scripts/mlExportSelect.js +16 -4
  59. package/dist/scripts/mlInspect.js +13 -3
  60. package/dist/scripts/mlTrainLatestSelect.js +14 -4
  61. package/dist/scripts/replay.js +8824 -0
  62. package/dist/scripts/replayRunner.js +8827 -0
  63. package/dist/scripts/replayRuntimeEvidence.js +868 -0
  64. package/dist/scripts/researchAuto.js +286 -59
  65. package/dist/scripts/results.js +3 -3
  66. package/dist/scripts/runtimeEvidence.js +605 -0
  67. package/dist/scripts/runtimeParity.js +6362 -1043
  68. package/dist/scripts/serverHealth.js +588 -0
  69. package/dist/scripts/signals.js +5590 -511
  70. package/dist/scripts/signalsDaemon.js +6167 -0
  71. package/dist/scripts/signalsSummary.js +833 -248
  72. package/dist/scripts/test-ml.js +25 -3
  73. package/dist/scripts/test.js +26 -1
  74. package/dist/scripts/user-add.js +15 -2
  75. package/dist/workers/testerWorker.js +130 -21
  76. package/package.json +18 -12
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/runtimeRedis.ts
21
+ var runtimeRedis_exports = {};
22
+ __export(runtimeRedis_exports, {
23
+ getRuntimeStrategyConfigKeys: () => getRuntimeStrategyConfigKeys,
24
+ isRuntimeStrategyEnabled: () => isRuntimeStrategyEnabled,
25
+ isRuntimeTradeRecord: () => isRuntimeTradeRecord,
26
+ loadRuntimeStrategyConfigs: () => loadRuntimeStrategyConfigs,
27
+ loadRuntimeStrategyNames: () => loadRuntimeStrategyNames,
28
+ loadRuntimeTrades: () => loadRuntimeTrades,
29
+ loadStrategyResultSymbols: () => loadStrategyResultSymbols,
30
+ resolveStrategyConfigIdentityByKey: () => resolveStrategyConfigIdentityByKey,
31
+ resolveStrategyNameByConfigKey: () => resolveStrategyNameByConfigKey
32
+ });
33
+ module.exports = __toCommonJS(runtimeRedis_exports);
34
+ var import_redis = require("@tradejs/infra/redis");
35
+ var import_time = require("@tradejs/core/time");
36
+ var RESERVED_STRATEGY_NAMES = /* @__PURE__ */ new Set(["charts"]);
37
+ var RESERVED_CONFIG_IDS = /* @__PURE__ */ new Set(["results"]);
38
+ var resolveStrategyConfigIdentityByKey = (userName, key) => {
39
+ const parts = key.split(":");
40
+ if (parts.length !== 5) return null;
41
+ const [users, keyUserName, strategiesKey, strategyName, configId] = parts;
42
+ if (users !== "users" || keyUserName !== userName || strategiesKey !== "strategies" || !strategyName || !configId || RESERVED_STRATEGY_NAMES.has(strategyName) || RESERVED_CONFIG_IDS.has(configId) || !/^[a-zA-Z0-9_-]+$/.test(configId)) {
43
+ return null;
44
+ }
45
+ return { strategyName, configId };
46
+ };
47
+ var isRuntimeStrategyEnabled = (strategyConfig) => {
48
+ const enabled = strategyConfig.ENABLE;
49
+ return enabled !== false;
50
+ };
51
+ var isRuntimeTradeRecord = (value) => {
52
+ if (!value || typeof value !== "object") {
53
+ return false;
54
+ }
55
+ const record = value;
56
+ return typeof record.orderId === "string" && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.entryTimestamp === "number" && typeof record.entryPrice === "number" && typeof record.qty === "number" && (record.direction === "LONG" || record.direction === "SHORT");
57
+ };
58
+ var resolveStrategyNameByConfigKey = (userName, key) => {
59
+ return resolveStrategyConfigIdentityByKey(userName, key)?.strategyName ?? null;
60
+ };
61
+ var getRuntimeStrategyConfigKeys = async (userName) => {
62
+ const keys = await (0, import_redis.getKeys)(`${import_redis.redisKeys.strategies(userName)}:`);
63
+ return keys.filter((key) => resolveStrategyConfigIdentityByKey(userName, key)).sort((left, right) => left.localeCompare(right));
64
+ };
65
+ var loadRuntimeStrategyNames = async (userName) => [
66
+ ...new Set(
67
+ (await getRuntimeStrategyConfigKeys(userName)).map((key) => resolveStrategyNameByConfigKey(userName, key)).filter((value) => Boolean(value))
68
+ )
69
+ ].sort((left, right) => left.localeCompare(right));
70
+ var loadRuntimeStrategyConfigs = async (userName, {
71
+ onInvalidConfig
72
+ } = {}) => {
73
+ const configKeys = await getRuntimeStrategyConfigKeys(userName);
74
+ const strategyConfigs = await Promise.all(
75
+ configKeys.map(async (key) => {
76
+ const strategyName = resolveStrategyNameByConfigKey(userName, key);
77
+ const identity = resolveStrategyConfigIdentityByKey(userName, key);
78
+ if (!strategyName || !identity) {
79
+ return null;
80
+ }
81
+ const strategyConfig = await (0, import_redis.getData)(
82
+ key,
83
+ null
84
+ );
85
+ if (!strategyConfig || typeof strategyConfig !== "object" || Array.isArray(strategyConfig)) {
86
+ onInvalidConfig?.(key);
87
+ return null;
88
+ }
89
+ return {
90
+ key,
91
+ strategyName,
92
+ configId: identity.configId,
93
+ strategyConfig
94
+ };
95
+ })
96
+ );
97
+ return strategyConfigs.filter(Boolean);
98
+ };
99
+ var loadRuntimeTrades = async (userName, {
100
+ startTime,
101
+ endTime
102
+ } = {}) => {
103
+ const hasWindow = Number.isFinite(startTime) && Number.isFinite(endTime) && startTime != null && endTime != null;
104
+ const filterByWindow = (trade) => !hasWindow || trade.entryTimestamp >= startTime && trade.entryTimestamp <= endTime;
105
+ if (hasWindow) {
106
+ const dayKeys = (0, import_time.getRuntimeStorageDayKeys)(startTime, endTime);
107
+ const bucketTrades = (await Promise.all(
108
+ dayKeys.map(
109
+ (dayKey) => (0, import_redis.getHashJsonValues)(
110
+ import_redis.redisKeys.runtimeTradeBucket(userName, dayKey)
111
+ )
112
+ )
113
+ )).flat();
114
+ const dedupedBucketTrades = /* @__PURE__ */ new Map();
115
+ for (const trade of bucketTrades) {
116
+ if (!isRuntimeTradeRecord(trade)) {
117
+ continue;
118
+ }
119
+ dedupedBucketTrades.set(trade.orderId, trade);
120
+ }
121
+ const windowedTrades = [...dedupedBucketTrades.values()].filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
122
+ if (windowedTrades.length > 0 || dayKeys.length === 0) {
123
+ return windowedTrades;
124
+ }
125
+ }
126
+ const tradePrefix = import_redis.redisKeys.runtimeTrades(userName);
127
+ const bucketPrefix = import_redis.redisKeys.runtimeTradeBuckets(userName);
128
+ const keys = (await (0, import_redis.getKeys)(tradePrefix)).filter(
129
+ (key) => !key.startsWith(bucketPrefix)
130
+ );
131
+ const trades = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
132
+ return trades.filter(isRuntimeTradeRecord).filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
133
+ };
134
+ var loadStrategyResultSymbols = async ({
135
+ userName,
136
+ strategy
137
+ }) => {
138
+ const results = await (0, import_redis.getData)(
139
+ import_redis.redisKeys.strategyResults(userName, strategy),
140
+ {}
141
+ );
142
+ return Object.keys(results ?? {}).sort(
143
+ (left, right) => left.localeCompare(right)
144
+ );
145
+ };
146
+ // Annotate the CommonJS export names for ESM import in node:
147
+ 0 && (module.exports = {
148
+ getRuntimeStrategyConfigKeys,
149
+ isRuntimeStrategyEnabled,
150
+ isRuntimeTradeRecord,
151
+ loadRuntimeStrategyConfigs,
152
+ loadRuntimeStrategyNames,
153
+ loadRuntimeTrades,
154
+ loadStrategyResultSymbols,
155
+ resolveStrategyConfigIdentityByKey,
156
+ resolveStrategyNameByConfigKey
157
+ });
@@ -30,7 +30,8 @@ module.exports = __toCommonJS(runtimeSignalsLoader_exports);
30
30
  var import_redis = require("@tradejs/infra/redis");
31
31
 
32
32
  // src/lib/runtimeSignalsStorage.ts
33
- var RUNTIME_STORAGE_DAY_OFFSET_MS = 5 * 60 * 60 * 1e3;
33
+ var import_constants = require("@tradejs/core/constants");
34
+ var import_time = require("@tradejs/core/time");
34
35
  var isRuntimeSignalBucketRef = (value) => {
35
36
  if (!value || typeof value !== "object") {
36
37
  return false;
@@ -80,8 +81,34 @@ var isRuntimeSignalEvaluationRecord = (value) => {
80
81
  return typeof record.evaluationId === "string" && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.timestamp === "number" && (record.status === "signal" || record.status === "skip" || record.status === "error");
81
82
  };
82
83
  var sortByTimestamp = (records) => [...records].sort((left, right) => left.timestamp - right.timestamp);
83
- var loadRuntimeSignals = async (userName) => {
84
- const bucketKeys = await (0, import_redis.getKeys)(import_redis.redisKeys.runtimeSignalBuckets(userName));
84
+ var filterBucketKeysByWindow = (bucketKeys, prefix, startTime, endTime) => {
85
+ if (!Number.isFinite(startTime) || !Number.isFinite(endTime) || startTime == null || endTime == null) {
86
+ return bucketKeys;
87
+ }
88
+ const allowedDayKeys = new Set((0, import_time.getRuntimeStorageDayKeys)(startTime, endTime));
89
+ if (!allowedDayKeys.size) {
90
+ return [];
91
+ }
92
+ return bucketKeys.filter((key) => {
93
+ const suffix = key.slice(prefix.length);
94
+ const firstColon = suffix.indexOf(":");
95
+ if (firstColon <= 0) {
96
+ return false;
97
+ }
98
+ return allowedDayKeys.has(suffix.slice(0, firstColon));
99
+ });
100
+ };
101
+ var loadRuntimeSignals = async (userName, {
102
+ startTime,
103
+ endTime
104
+ } = {}) => {
105
+ const bucketPrefix = import_redis.redisKeys.runtimeSignalBuckets(userName);
106
+ const bucketKeys = filterBucketKeysByWindow(
107
+ await (0, import_redis.getKeys)(bucketPrefix),
108
+ bucketPrefix,
109
+ startTime,
110
+ endTime
111
+ );
85
112
  const refs = (await Promise.all(bucketKeys.map((key) => (0, import_redis.getHashJsonValues)(key)))).flat().filter(isRuntimeSignalBucketRef);
86
113
  const seen = /* @__PURE__ */ new Set();
87
114
  const payloads = await Promise.all(
@@ -100,9 +127,16 @@ var loadRuntimeSignals = async (userName) => {
100
127
  );
101
128
  return sortByTimestamp(payloads.filter(isSignalRecord));
102
129
  };
103
- var loadRuntimeSignalEvaluations = async (userName) => {
104
- const bucketKeys = await (0, import_redis.getKeys)(
105
- import_redis.redisKeys.runtimeSignalEvaluationBuckets(userName)
130
+ var loadRuntimeSignalEvaluations = async (userName, {
131
+ startTime,
132
+ endTime
133
+ } = {}) => {
134
+ const bucketPrefix = import_redis.redisKeys.runtimeSignalEvaluationBuckets(userName);
135
+ const bucketKeys = filterBucketKeysByWindow(
136
+ await (0, import_redis.getKeys)(bucketPrefix),
137
+ bucketPrefix,
138
+ startTime,
139
+ endTime
106
140
  );
107
141
  const evaluations = (await Promise.all(bucketKeys.map((key) => (0, import_redis.getHashJsonValues)(key)))).flat().filter(isRuntimeSignalEvaluationRecord);
108
142
  const deduped = /* @__PURE__ */ new Map();
@@ -20,42 +20,60 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/lib/runtimeSignalsStorage.ts
21
21
  var runtimeSignalsStorage_exports = {};
22
22
  __export(runtimeSignalsStorage_exports, {
23
+ DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS: () => DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS,
24
+ RUNTIME_SIGNAL_RETENTION_DAYS_ENV: () => RUNTIME_SIGNAL_RETENTION_DAYS_ENV,
23
25
  buildRuntimeSignalStatsIncrements: () => buildRuntimeSignalStatsIncrements,
24
- getRuntimeStorageDayKey: () => getRuntimeStorageDayKey,
25
- getRuntimeStorageDayKeys: () => getRuntimeStorageDayKeys,
26
+ getRuntimeSignalRetentionTtlSeconds: () => getRuntimeSignalRetentionTtlSeconds,
27
+ getRuntimeStorageDayKey: () => import_time.getRuntimeStorageDayKey,
28
+ getRuntimeStorageDayKeys: () => import_time.getRuntimeStorageDayKeys,
26
29
  isRuntimeSignalBucketRef: () => isRuntimeSignalBucketRef,
27
30
  normalizeRuntimeSignalSkipReason: () => normalizeRuntimeSignalSkipReason,
28
31
  parseRuntimeSignalStatsBucket: () => parseRuntimeSignalStatsBucket,
29
32
  shouldStoreDetailedRuntimeSignalEvaluation: () => shouldStoreDetailedRuntimeSignalEvaluation,
30
- toRuntimeSignalBucketRef: () => toRuntimeSignalBucketRef
33
+ shouldStoreRuntimeSignalDiagnostics: () => shouldStoreRuntimeSignalDiagnostics,
34
+ toRuntimeSignalBucketRef: () => toRuntimeSignalBucketRef,
35
+ toStoredRuntimeSignal: () => toStoredRuntimeSignal
31
36
  });
32
37
  module.exports = __toCommonJS(runtimeSignalsStorage_exports);
33
- var DAY_MS = 864e5;
34
- var RUNTIME_STORAGE_DAY_OFFSET_MS = 5 * 60 * 60 * 1e3;
35
- var toIsoDayKey = (timestamp) => new Date(timestamp).toISOString().slice(0, 10);
36
- var toRuntimeStorageDayTimestamp = (timestamp) => Math.floor((timestamp + RUNTIME_STORAGE_DAY_OFFSET_MS) / DAY_MS) * DAY_MS;
37
- var getRuntimeStorageDayKey = (timestamp) => toIsoDayKey(toRuntimeStorageDayTimestamp(timestamp));
38
- var getRuntimeStorageDayKeys = (startTime, endTime) => {
39
- if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) {
40
- return [];
38
+ var import_constants = require("@tradejs/core/constants");
39
+ var import_time = require("@tradejs/core/time");
40
+ var SECONDS_PER_DAY = 86400;
41
+ var RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
42
+ var DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants.TTL_3D;
43
+ var parsePositiveNumber = (value) => {
44
+ if (value == null || value === "") {
45
+ return null;
41
46
  }
42
- const start = Math.min(startTime, endTime);
43
- const endExclusive = Math.max(startTime, endTime);
44
- const normalizedEnd = Math.max(start, endExclusive - 1);
45
- const keys = [];
46
- const startDay = toRuntimeStorageDayTimestamp(start);
47
- const endDay = toRuntimeStorageDayTimestamp(normalizedEnd);
48
- for (let current = startDay; current <= endDay; current += DAY_MS) {
49
- keys.push(toIsoDayKey(current));
47
+ const parsed = Number(value);
48
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
49
+ };
50
+ var getRuntimeSignalRetentionTtlSeconds = () => {
51
+ const explicitDays = parsePositiveNumber(
52
+ process.env[RUNTIME_SIGNAL_RETENTION_DAYS_ENV]
53
+ );
54
+ if (explicitDays != null) {
55
+ return Math.ceil(explicitDays * SECONDS_PER_DAY);
50
56
  }
51
- return keys;
57
+ return DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS;
52
58
  };
53
59
  var toRuntimeSignalBucketRef = (signal) => ({
54
60
  signalId: signal.signalId,
55
61
  symbol: signal.symbol,
56
62
  strategy: signal.strategy,
57
- timestamp: signal.timestamp
63
+ timestamp: signal.timestamp,
64
+ ...signal.runtimeConfigId && signal.runtimeConfigId !== "config" ? { runtimeConfigId: signal.runtimeConfigId } : {}
58
65
  });
66
+ var shouldStoreRuntimeSignalDiagnostics = (signal) => signal.orderStatus === "completed" || signal.orderStatus === "failed";
67
+ var toStoredRuntimeSignal = (signal) => {
68
+ if (shouldStoreRuntimeSignalDiagnostics(signal)) {
69
+ return signal;
70
+ }
71
+ const stored = { ...signal };
72
+ delete stored.figures;
73
+ delete stored.indicators;
74
+ delete stored.additionalIndicators;
75
+ return stored;
76
+ };
59
77
  var isRuntimeSignalBucketRef = (value) => {
60
78
  if (!value || typeof value !== "object") {
61
79
  return false;
@@ -151,12 +169,17 @@ var parseRuntimeSignalStatsBucket = (value) => {
151
169
  };
152
170
  // Annotate the CommonJS export names for ESM import in node:
153
171
  0 && (module.exports = {
172
+ DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS,
173
+ RUNTIME_SIGNAL_RETENTION_DAYS_ENV,
154
174
  buildRuntimeSignalStatsIncrements,
175
+ getRuntimeSignalRetentionTtlSeconds,
155
176
  getRuntimeStorageDayKey,
156
177
  getRuntimeStorageDayKeys,
157
178
  isRuntimeSignalBucketRef,
158
179
  normalizeRuntimeSignalSkipReason,
159
180
  parseRuntimeSignalStatsBucket,
160
181
  shouldStoreDetailedRuntimeSignalEvaluation,
161
- toRuntimeSignalBucketRef
182
+ shouldStoreRuntimeSignalDiagnostics,
183
+ toRuntimeSignalBucketRef,
184
+ toStoredRuntimeSignal
162
185
  });
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/lib/runtimeStrategyBacktest.ts
31
+ var runtimeStrategyBacktest_exports = {};
32
+ __export(runtimeStrategyBacktest_exports, {
33
+ BACKTEST_CLI_RUNTIME_CONFIG_KEYS: () => BACKTEST_CLI_RUNTIME_CONFIG_KEYS,
34
+ loadRuntimeStrategyBacktestConfigs: () => loadRuntimeStrategyBacktestConfigs,
35
+ toStrategyConfigGrid: () => toStrategyConfigGrid
36
+ });
37
+ module.exports = __toCommonJS(runtimeStrategyBacktest_exports);
38
+ var import_chalk = __toESM(require("chalk"));
39
+
40
+ // src/lib/runtimeRedis.ts
41
+ var import_redis = require("@tradejs/infra/redis");
42
+ var import_time = require("@tradejs/core/time");
43
+ var RESERVED_STRATEGY_NAMES = /* @__PURE__ */ new Set(["charts"]);
44
+ var RESERVED_CONFIG_IDS = /* @__PURE__ */ new Set(["results"]);
45
+ var resolveStrategyConfigIdentityByKey = (userName, key) => {
46
+ const parts = key.split(":");
47
+ if (parts.length !== 5) return null;
48
+ const [users, keyUserName, strategiesKey, strategyName, configId] = parts;
49
+ if (users !== "users" || keyUserName !== userName || strategiesKey !== "strategies" || !strategyName || !configId || RESERVED_STRATEGY_NAMES.has(strategyName) || RESERVED_CONFIG_IDS.has(configId) || !/^[a-zA-Z0-9_-]+$/.test(configId)) {
50
+ return null;
51
+ }
52
+ return { strategyName, configId };
53
+ };
54
+ var isRuntimeStrategyEnabled = (strategyConfig) => {
55
+ const enabled = strategyConfig.ENABLE;
56
+ return enabled !== false;
57
+ };
58
+ var resolveStrategyNameByConfigKey = (userName, key) => {
59
+ return resolveStrategyConfigIdentityByKey(userName, key)?.strategyName ?? null;
60
+ };
61
+ var getRuntimeStrategyConfigKeys = async (userName) => {
62
+ const keys = await (0, import_redis.getKeys)(`${import_redis.redisKeys.strategies(userName)}:`);
63
+ return keys.filter((key) => resolveStrategyConfigIdentityByKey(userName, key)).sort((left, right) => left.localeCompare(right));
64
+ };
65
+ var loadRuntimeStrategyConfigs = async (userName, {
66
+ onInvalidConfig
67
+ } = {}) => {
68
+ const configKeys = await getRuntimeStrategyConfigKeys(userName);
69
+ const strategyConfigs = await Promise.all(
70
+ configKeys.map(async (key) => {
71
+ const strategyName = resolveStrategyNameByConfigKey(userName, key);
72
+ const identity = resolveStrategyConfigIdentityByKey(userName, key);
73
+ if (!strategyName || !identity) {
74
+ return null;
75
+ }
76
+ const strategyConfig = await (0, import_redis.getData)(
77
+ key,
78
+ null
79
+ );
80
+ if (!strategyConfig || typeof strategyConfig !== "object" || Array.isArray(strategyConfig)) {
81
+ onInvalidConfig?.(key);
82
+ return null;
83
+ }
84
+ return {
85
+ key,
86
+ strategyName,
87
+ configId: identity.configId,
88
+ strategyConfig
89
+ };
90
+ })
91
+ );
92
+ return strategyConfigs.filter(Boolean);
93
+ };
94
+
95
+ // src/lib/runtimeStrategyBacktest.ts
96
+ var BACKTEST_CLI_RUNTIME_CONFIG_KEYS = /* @__PURE__ */ new Set([
97
+ "ENV",
98
+ "INTERVAL",
99
+ "MAKE_ORDERS",
100
+ "CLOSE_OPPOSITE_POSITIONS",
101
+ "BACKTEST_PRICE_MODE",
102
+ "BACKTEST_ENTRY_DELAY_BARS"
103
+ ]);
104
+ var toStrategyConfigGrid = (strategyConfig) => Object.fromEntries(
105
+ Object.entries(strategyConfig).filter(([key]) => !BACKTEST_CLI_RUNTIME_CONFIG_KEYS.has(key)).map(([key, value]) => [key, [value]])
106
+ );
107
+ var loadRuntimeStrategyBacktestConfigs = async (userName) => {
108
+ const configs = await loadRuntimeStrategyConfigs(userName, {
109
+ onInvalidConfig: (key) => {
110
+ console.log(import_chalk.default.yellow(`Skip invalid runtime strategy config: ${key}`));
111
+ }
112
+ });
113
+ return configs.filter(({ configId }) => configId === "config").filter(({ strategyName, strategyConfig }) => {
114
+ const enabled = isRuntimeStrategyEnabled(strategyConfig);
115
+ if (!enabled) {
116
+ console.log(
117
+ import_chalk.default.yellow(
118
+ `Skip inactive runtime strategy config by ENABLE=false: ${strategyName}`
119
+ )
120
+ );
121
+ }
122
+ return enabled;
123
+ }).map(({ strategyName, strategyConfig }) => ({
124
+ strategyName,
125
+ strategyConfig,
126
+ backtestConfig: toStrategyConfigGrid(strategyConfig)
127
+ }));
128
+ };
129
+ // Annotate the CommonJS export names for ESM import in node:
130
+ 0 && (module.exports = {
131
+ BACKTEST_CLI_RUNTIME_CONFIG_KEYS,
132
+ loadRuntimeStrategyBacktestConfigs,
133
+ toStrategyConfigGrid
134
+ });