@tradejs/cli 1.0.8 → 1.0.9
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 +1405 -1258
- package/dist/lib/runtimeSignalsLoader.js +153 -0
- package/dist/lib/runtimeSignalsStorage.js +162 -0
- package/dist/scripts/agentRun.js +14 -0
- package/dist/scripts/researchAuto.js +3 -1
- package/dist/scripts/runtimeParity.js +69 -32
- package/dist/scripts/signals.js +117 -59
- package/dist/scripts/signalsSummary.js +167 -110
- package/package.json +9 -9
|
@@ -0,0 +1,153 @@
|
|
|
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/runtimeSignalsLoader.ts
|
|
21
|
+
var runtimeSignalsLoader_exports = {};
|
|
22
|
+
__export(runtimeSignalsLoader_exports, {
|
|
23
|
+
isRuntimeSignalEvaluationRecord: () => isRuntimeSignalEvaluationRecord,
|
|
24
|
+
isSignalRecord: () => isSignalRecord,
|
|
25
|
+
loadRuntimeSignalEvaluationStatsBuckets: () => loadRuntimeSignalEvaluationStatsBuckets,
|
|
26
|
+
loadRuntimeSignalEvaluations: () => loadRuntimeSignalEvaluations,
|
|
27
|
+
loadRuntimeSignals: () => loadRuntimeSignals
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(runtimeSignalsLoader_exports);
|
|
30
|
+
var import_redis = require("@tradejs/infra/redis");
|
|
31
|
+
|
|
32
|
+
// src/lib/runtimeSignalsStorage.ts
|
|
33
|
+
var RUNTIME_STORAGE_DAY_OFFSET_MS = 5 * 60 * 60 * 1e3;
|
|
34
|
+
var isRuntimeSignalBucketRef = (value) => {
|
|
35
|
+
if (!value || typeof value !== "object") {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const record = value;
|
|
39
|
+
return typeof record.signalId === "string" && typeof record.symbol === "string" && typeof record.strategy === "string" && typeof record.timestamp === "number";
|
|
40
|
+
};
|
|
41
|
+
var toCount = (value) => {
|
|
42
|
+
const parsed = Number.parseInt(String(value ?? "0"), 10);
|
|
43
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
44
|
+
};
|
|
45
|
+
var parseRuntimeSignalStatsBucket = (value) => {
|
|
46
|
+
const reasonGroups = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const [field, rawCount] of Object.entries(value)) {
|
|
48
|
+
if (!field.startsWith("reason:")) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const [, source, ...reasonParts] = field.split(":");
|
|
52
|
+
const reason = reasonParts.join(":");
|
|
53
|
+
if (!source || !reason) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const reasons = reasonGroups.get(source) ?? /* @__PURE__ */ new Map();
|
|
57
|
+
reasons.set(reason, toCount(rawCount));
|
|
58
|
+
reasonGroups.set(source, reasons);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
evaluated: toCount(value.evaluated),
|
|
62
|
+
signals: toCount(value.signals),
|
|
63
|
+
reasonGroups
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/lib/runtimeSignalsLoader.ts
|
|
68
|
+
var isSignalRecord = (value) => {
|
|
69
|
+
if (!value || typeof value !== "object") {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const record = value;
|
|
73
|
+
return typeof record.signalId === "string" && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.timestamp === "number";
|
|
74
|
+
};
|
|
75
|
+
var isRuntimeSignalEvaluationRecord = (value) => {
|
|
76
|
+
if (!value || typeof value !== "object") {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const record = value;
|
|
80
|
+
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
|
+
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));
|
|
85
|
+
const refs = (await Promise.all(bucketKeys.map((key) => (0, import_redis.getHashJsonValues)(key)))).flat().filter(isRuntimeSignalBucketRef);
|
|
86
|
+
const seen = /* @__PURE__ */ new Set();
|
|
87
|
+
const payloads = await Promise.all(
|
|
88
|
+
refs.map(async (ref) => {
|
|
89
|
+
const dedupeKey = `${ref.symbol}:${ref.signalId}`;
|
|
90
|
+
if (seen.has(dedupeKey)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
seen.add(dedupeKey);
|
|
94
|
+
const signal = await (0, import_redis.getData)(
|
|
95
|
+
import_redis.redisKeys.storeSignal(ref.symbol, ref.signalId),
|
|
96
|
+
null
|
|
97
|
+
);
|
|
98
|
+
return isSignalRecord(signal) ? signal : null;
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
return sortByTimestamp(payloads.filter(isSignalRecord));
|
|
102
|
+
};
|
|
103
|
+
var loadRuntimeSignalEvaluations = async (userName) => {
|
|
104
|
+
const bucketKeys = await (0, import_redis.getKeys)(
|
|
105
|
+
import_redis.redisKeys.runtimeSignalEvaluationBuckets(userName)
|
|
106
|
+
);
|
|
107
|
+
const evaluations = (await Promise.all(bucketKeys.map((key) => (0, import_redis.getHashJsonValues)(key)))).flat().filter(isRuntimeSignalEvaluationRecord);
|
|
108
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
109
|
+
for (const evaluation of evaluations) {
|
|
110
|
+
deduped.set(evaluation.evaluationId, evaluation);
|
|
111
|
+
}
|
|
112
|
+
return sortByTimestamp([...deduped.values()]);
|
|
113
|
+
};
|
|
114
|
+
var parseBucketKey = (prefix, key) => {
|
|
115
|
+
if (!key.startsWith(prefix)) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const suffix = key.slice(prefix.length);
|
|
119
|
+
const firstColon = suffix.indexOf(":");
|
|
120
|
+
if (firstColon <= 0 || firstColon >= suffix.length - 1) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
dayKey: suffix.slice(0, firstColon),
|
|
125
|
+
strategy: suffix.slice(firstColon + 1)
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
var loadRuntimeSignalEvaluationStatsBuckets = async (userName) => {
|
|
129
|
+
const prefix = import_redis.redisKeys.runtimeSignalEvaluationStatsBuckets(userName);
|
|
130
|
+
const keys = await (0, import_redis.getKeys)(prefix);
|
|
131
|
+
const entries = await Promise.all(
|
|
132
|
+
keys.map(async (key) => {
|
|
133
|
+
const parsedKey = parseBucketKey(prefix, key);
|
|
134
|
+
if (!parsedKey) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
key,
|
|
139
|
+
...parsedKey,
|
|
140
|
+
stats: parseRuntimeSignalStatsBucket(await (0, import_redis.getHashData)(key))
|
|
141
|
+
};
|
|
142
|
+
})
|
|
143
|
+
);
|
|
144
|
+
return entries.filter(Boolean);
|
|
145
|
+
};
|
|
146
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
147
|
+
0 && (module.exports = {
|
|
148
|
+
isRuntimeSignalEvaluationRecord,
|
|
149
|
+
isSignalRecord,
|
|
150
|
+
loadRuntimeSignalEvaluationStatsBuckets,
|
|
151
|
+
loadRuntimeSignalEvaluations,
|
|
152
|
+
loadRuntimeSignals
|
|
153
|
+
});
|
|
@@ -0,0 +1,162 @@
|
|
|
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/runtimeSignalsStorage.ts
|
|
21
|
+
var runtimeSignalsStorage_exports = {};
|
|
22
|
+
__export(runtimeSignalsStorage_exports, {
|
|
23
|
+
buildRuntimeSignalStatsIncrements: () => buildRuntimeSignalStatsIncrements,
|
|
24
|
+
getRuntimeStorageDayKey: () => getRuntimeStorageDayKey,
|
|
25
|
+
getRuntimeStorageDayKeys: () => getRuntimeStorageDayKeys,
|
|
26
|
+
isRuntimeSignalBucketRef: () => isRuntimeSignalBucketRef,
|
|
27
|
+
normalizeRuntimeSignalSkipReason: () => normalizeRuntimeSignalSkipReason,
|
|
28
|
+
parseRuntimeSignalStatsBucket: () => parseRuntimeSignalStatsBucket,
|
|
29
|
+
shouldStoreDetailedRuntimeSignalEvaluation: () => shouldStoreDetailedRuntimeSignalEvaluation,
|
|
30
|
+
toRuntimeSignalBucketRef: () => toRuntimeSignalBucketRef
|
|
31
|
+
});
|
|
32
|
+
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 [];
|
|
41
|
+
}
|
|
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));
|
|
50
|
+
}
|
|
51
|
+
return keys;
|
|
52
|
+
};
|
|
53
|
+
var toRuntimeSignalBucketRef = (signal) => ({
|
|
54
|
+
signalId: signal.signalId,
|
|
55
|
+
symbol: signal.symbol,
|
|
56
|
+
strategy: signal.strategy,
|
|
57
|
+
timestamp: signal.timestamp
|
|
58
|
+
});
|
|
59
|
+
var isRuntimeSignalBucketRef = (value) => {
|
|
60
|
+
if (!value || typeof value !== "object") {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const record = value;
|
|
64
|
+
return typeof record.signalId === "string" && typeof record.symbol === "string" && typeof record.strategy === "string" && typeof record.timestamp === "number";
|
|
65
|
+
};
|
|
66
|
+
var normalizeRuntimeSignalSkipReason = (reason, fallbackSource) => {
|
|
67
|
+
let source = fallbackSource;
|
|
68
|
+
let normalizedReason = reason;
|
|
69
|
+
if (reason.startsWith("AI_QUALITY_BELOW_MIN")) {
|
|
70
|
+
source = "AI";
|
|
71
|
+
normalizedReason = "MIN_AI_QUALITY";
|
|
72
|
+
} else if (reason === "AI_QUALITY_UNAVAILABLE") {
|
|
73
|
+
source = "AI";
|
|
74
|
+
normalizedReason = "QUALITY_UNAVAILABLE";
|
|
75
|
+
} else if (reason === "ML_RESULT_UNAVAILABLE") {
|
|
76
|
+
source = "ML";
|
|
77
|
+
normalizedReason = "RESULT_UNAVAILABLE";
|
|
78
|
+
} else if (reason.startsWith("ML_THRESHOLD_NOT_MET")) {
|
|
79
|
+
source = "ML";
|
|
80
|
+
normalizedReason = "ML_THRESHOLD";
|
|
81
|
+
} else if (reason.startsWith("HOOK_BEFORE_ENTRY_GATE:")) {
|
|
82
|
+
source = "hook";
|
|
83
|
+
normalizedReason = `BEFORE_ENTRY_GATE:${reason.slice(
|
|
84
|
+
"HOOK_BEFORE_ENTRY_GATE:".length
|
|
85
|
+
)}`;
|
|
86
|
+
} else if (reason === "HOOK_BEFORE_ENTRY_GATE") {
|
|
87
|
+
source = "hook";
|
|
88
|
+
normalizedReason = "BEFORE_ENTRY_GATE";
|
|
89
|
+
} else if (reason === "MAKE_ORDERS_DISABLED" || reason === "ENTRY_POLICY_BLOCKED") {
|
|
90
|
+
source = "policy";
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
source: `skip from ${source}`,
|
|
94
|
+
reason: normalizedReason
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
var buildStatsReasonField = (source, reason) => `reason:${source}:${reason}`;
|
|
98
|
+
var buildRuntimeSignalStatsIncrements = (evaluation) => {
|
|
99
|
+
const increments = {
|
|
100
|
+
evaluated: 1
|
|
101
|
+
};
|
|
102
|
+
if (evaluation.status === "signal") {
|
|
103
|
+
increments.signals = 1;
|
|
104
|
+
}
|
|
105
|
+
let skipReason = null;
|
|
106
|
+
let fallbackSource = "core";
|
|
107
|
+
if (evaluation.status === "skip") {
|
|
108
|
+
skipReason = evaluation.reason || "NO_SIGNAL";
|
|
109
|
+
fallbackSource = "core";
|
|
110
|
+
} else if (evaluation.status === "signal" && (evaluation.orderStatus === "skipped" || evaluation.orderStatus === "canceled")) {
|
|
111
|
+
skipReason = evaluation.orderSkipReason || evaluation.reason || `orderStatus=${evaluation.orderStatus}`;
|
|
112
|
+
fallbackSource = "runtime";
|
|
113
|
+
} else if (evaluation.status === "error") {
|
|
114
|
+
skipReason = evaluation.reason || "EVALUATION_ERROR";
|
|
115
|
+
fallbackSource = "runtime";
|
|
116
|
+
}
|
|
117
|
+
if (skipReason) {
|
|
118
|
+
const normalized = normalizeRuntimeSignalSkipReason(
|
|
119
|
+
skipReason,
|
|
120
|
+
fallbackSource
|
|
121
|
+
);
|
|
122
|
+
increments[buildStatsReasonField(normalized.source, normalized.reason)] = 1;
|
|
123
|
+
}
|
|
124
|
+
return increments;
|
|
125
|
+
};
|
|
126
|
+
var shouldStoreDetailedRuntimeSignalEvaluation = (evaluation) => evaluation.status !== "skip";
|
|
127
|
+
var toCount = (value) => {
|
|
128
|
+
const parsed = Number.parseInt(String(value ?? "0"), 10);
|
|
129
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
130
|
+
};
|
|
131
|
+
var parseRuntimeSignalStatsBucket = (value) => {
|
|
132
|
+
const reasonGroups = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const [field, rawCount] of Object.entries(value)) {
|
|
134
|
+
if (!field.startsWith("reason:")) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const [, source, ...reasonParts] = field.split(":");
|
|
138
|
+
const reason = reasonParts.join(":");
|
|
139
|
+
if (!source || !reason) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const reasons = reasonGroups.get(source) ?? /* @__PURE__ */ new Map();
|
|
143
|
+
reasons.set(reason, toCount(rawCount));
|
|
144
|
+
reasonGroups.set(source, reasons);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
evaluated: toCount(value.evaluated),
|
|
148
|
+
signals: toCount(value.signals),
|
|
149
|
+
reasonGroups
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
153
|
+
0 && (module.exports = {
|
|
154
|
+
buildRuntimeSignalStatsIncrements,
|
|
155
|
+
getRuntimeStorageDayKey,
|
|
156
|
+
getRuntimeStorageDayKeys,
|
|
157
|
+
isRuntimeSignalBucketRef,
|
|
158
|
+
normalizeRuntimeSignalSkipReason,
|
|
159
|
+
parseRuntimeSignalStatsBucket,
|
|
160
|
+
shouldStoreDetailedRuntimeSignalEvaluation,
|
|
161
|
+
toRuntimeSignalBucketRef
|
|
162
|
+
});
|
package/dist/scripts/agentRun.js
CHANGED
|
@@ -5,6 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
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
|
+
};
|
|
8
12
|
var __copyProps = (to, from, except, desc) => {
|
|
9
13
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
14
|
for (let key of __getOwnPropNames(from))
|
|
@@ -21,8 +25,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
26
|
mod
|
|
23
27
|
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
24
29
|
|
|
25
30
|
// src/scripts/agentRun.ts
|
|
31
|
+
var agentRun_exports = {};
|
|
32
|
+
__export(agentRun_exports, {
|
|
33
|
+
main: () => main
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(agentRun_exports);
|
|
26
36
|
var import_args = __toESM(require("args"));
|
|
27
37
|
var import_chalk = __toESM(require("chalk"));
|
|
28
38
|
var import_promises = __toESM(require("fs/promises"));
|
|
@@ -893,3 +903,7 @@ if (require.main === module) {
|
|
|
893
903
|
process.exit(1);
|
|
894
904
|
});
|
|
895
905
|
}
|
|
906
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
907
|
+
0 && (module.exports = {
|
|
908
|
+
main
|
|
909
|
+
});
|
|
@@ -37,6 +37,7 @@ __export(researchAuto_exports, {
|
|
|
37
37
|
getBacktestResultsPrefix: () => getBacktestResultsPrefix,
|
|
38
38
|
listMergedFiles: () => listMergedFiles,
|
|
39
39
|
listRuntimeStrategyNames: () => listRuntimeStrategyNames,
|
|
40
|
+
main: () => main,
|
|
40
41
|
parseJsonOutput: () => parseJsonOutput,
|
|
41
42
|
resolveStrategyNameByConfigKey: () => resolveStrategyNameByConfigKey,
|
|
42
43
|
resolveTarget: () => resolveTarget,
|
|
@@ -330,7 +331,7 @@ var runCliCommand = async (params) => {
|
|
|
330
331
|
return new Promise((resolve, reject) => {
|
|
331
332
|
const child = (0, import_node_child_process.spawn)(
|
|
332
333
|
"bash",
|
|
333
|
-
["./bin/run-cli-
|
|
334
|
+
["./bin/run-cli-runtime.sh", params.command, ...params.args],
|
|
334
335
|
{
|
|
335
336
|
cwd: projectRoot,
|
|
336
337
|
env,
|
|
@@ -836,6 +837,7 @@ if (require.main === module) {
|
|
|
836
837
|
getBacktestResultsPrefix,
|
|
837
838
|
listMergedFiles,
|
|
838
839
|
listRuntimeStrategyNames,
|
|
840
|
+
main,
|
|
839
841
|
parseJsonOutput,
|
|
840
842
|
resolveStrategyNameByConfigKey,
|
|
841
843
|
resolveTarget,
|
|
@@ -42,7 +42,7 @@ var import_connectors = require("@tradejs/connectors");
|
|
|
42
42
|
var import_constants = require("@tradejs/core/constants");
|
|
43
43
|
var import_time = require("@tradejs/core/time");
|
|
44
44
|
var import_logger = require("@tradejs/infra/logger");
|
|
45
|
-
var
|
|
45
|
+
var import_redis2 = require("@tradejs/infra/redis");
|
|
46
46
|
var import_cli2 = require("@tradejs/node/cli");
|
|
47
47
|
var import_backtest = require("@tradejs/node/backtest");
|
|
48
48
|
var import_connectors2 = require("@tradejs/node/connectors");
|
|
@@ -257,6 +257,67 @@ var normalizeCliArgv = (argv, legacyFlagMap) => argv.map((arg) => {
|
|
|
257
257
|
return `${normalizedFlag}=${rest.join("=")}`;
|
|
258
258
|
});
|
|
259
259
|
|
|
260
|
+
// src/lib/runtimeSignalsLoader.ts
|
|
261
|
+
var import_redis = require("@tradejs/infra/redis");
|
|
262
|
+
|
|
263
|
+
// src/lib/runtimeSignalsStorage.ts
|
|
264
|
+
var RUNTIME_STORAGE_DAY_OFFSET_MS = 5 * 60 * 60 * 1e3;
|
|
265
|
+
var isRuntimeSignalBucketRef = (value) => {
|
|
266
|
+
if (!value || typeof value !== "object") {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
const record = value;
|
|
270
|
+
return typeof record.signalId === "string" && typeof record.symbol === "string" && typeof record.strategy === "string" && typeof record.timestamp === "number";
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// src/lib/runtimeSignalsLoader.ts
|
|
274
|
+
var isSignalRecord = (value) => {
|
|
275
|
+
if (!value || typeof value !== "object") {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
const record = value;
|
|
279
|
+
return typeof record.signalId === "string" && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.timestamp === "number";
|
|
280
|
+
};
|
|
281
|
+
var isRuntimeSignalEvaluationRecord = (value) => {
|
|
282
|
+
if (!value || typeof value !== "object") {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
const record = value;
|
|
286
|
+
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");
|
|
287
|
+
};
|
|
288
|
+
var sortByTimestamp = (records) => [...records].sort((left, right) => left.timestamp - right.timestamp);
|
|
289
|
+
var loadRuntimeSignals = async (userName) => {
|
|
290
|
+
const bucketKeys = await (0, import_redis.getKeys)(import_redis.redisKeys.runtimeSignalBuckets(userName));
|
|
291
|
+
const refs = (await Promise.all(bucketKeys.map((key) => (0, import_redis.getHashJsonValues)(key)))).flat().filter(isRuntimeSignalBucketRef);
|
|
292
|
+
const seen = /* @__PURE__ */ new Set();
|
|
293
|
+
const payloads = await Promise.all(
|
|
294
|
+
refs.map(async (ref) => {
|
|
295
|
+
const dedupeKey = `${ref.symbol}:${ref.signalId}`;
|
|
296
|
+
if (seen.has(dedupeKey)) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
seen.add(dedupeKey);
|
|
300
|
+
const signal = await (0, import_redis.getData)(
|
|
301
|
+
import_redis.redisKeys.storeSignal(ref.symbol, ref.signalId),
|
|
302
|
+
null
|
|
303
|
+
);
|
|
304
|
+
return isSignalRecord(signal) ? signal : null;
|
|
305
|
+
})
|
|
306
|
+
);
|
|
307
|
+
return sortByTimestamp(payloads.filter(isSignalRecord));
|
|
308
|
+
};
|
|
309
|
+
var loadRuntimeSignalEvaluations = async (userName) => {
|
|
310
|
+
const bucketKeys = await (0, import_redis.getKeys)(
|
|
311
|
+
import_redis.redisKeys.runtimeSignalEvaluationBuckets(userName)
|
|
312
|
+
);
|
|
313
|
+
const evaluations = (await Promise.all(bucketKeys.map((key) => (0, import_redis.getHashJsonValues)(key)))).flat().filter(isRuntimeSignalEvaluationRecord);
|
|
314
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
315
|
+
for (const evaluation of evaluations) {
|
|
316
|
+
deduped.set(evaluation.evaluationId, evaluation);
|
|
317
|
+
}
|
|
318
|
+
return sortByTimestamp([...deduped.values()]);
|
|
319
|
+
};
|
|
320
|
+
|
|
260
321
|
// src/lib/telegramReports.ts
|
|
261
322
|
var import_cli = require("@tradejs/node/cli");
|
|
262
323
|
var TELEGRAM_REPORT_CHUNK_LIMIT = 3900;
|
|
@@ -497,20 +558,6 @@ var isRuntimeTradeRecord = (value) => {
|
|
|
497
558
|
const record = value;
|
|
498
559
|
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");
|
|
499
560
|
};
|
|
500
|
-
var isSignalRecord = (value) => {
|
|
501
|
-
if (!value || typeof value !== "object") {
|
|
502
|
-
return false;
|
|
503
|
-
}
|
|
504
|
-
const record = value;
|
|
505
|
-
return typeof record.signalId === "string" && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.timestamp === "number" && (record.direction === "LONG" || record.direction === "SHORT");
|
|
506
|
-
};
|
|
507
|
-
var isRuntimeSignalEvaluationRecord = (value) => {
|
|
508
|
-
if (!value || typeof value !== "object") {
|
|
509
|
-
return false;
|
|
510
|
-
}
|
|
511
|
-
const record = value;
|
|
512
|
-
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");
|
|
513
|
-
};
|
|
514
561
|
var resolveParityConnectorName = async (value) => {
|
|
515
562
|
const connectorName = await (0, import_connectors2.resolveConnectorName)(value, projectRoot);
|
|
516
563
|
if (connectorName) {
|
|
@@ -524,20 +571,10 @@ var resolveParityConnectorName = async (value) => {
|
|
|
524
571
|
return import_connectors2.DEFAULT_CONNECTOR_NAME;
|
|
525
572
|
};
|
|
526
573
|
var loadRuntimeTrades = async (userName) => {
|
|
527
|
-
const keys = await (0,
|
|
528
|
-
const trades = await Promise.all(keys.map((key) => (0,
|
|
574
|
+
const keys = await (0, import_redis2.getKeys)(import_redis2.redisKeys.runtimeTrades(userName));
|
|
575
|
+
const trades = await Promise.all(keys.map((key) => (0, import_redis2.getData)(key, null)));
|
|
529
576
|
return trades.filter(isRuntimeTradeRecord).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
|
|
530
577
|
};
|
|
531
|
-
var loadRuntimeSignals = async (userName) => {
|
|
532
|
-
const keys = await (0, import_redis.getKeys)(import_redis.redisKeys.runtimeSignals(userName));
|
|
533
|
-
const signals = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
|
|
534
|
-
return signals.filter(isSignalRecord).sort((left, right) => left.timestamp - right.timestamp);
|
|
535
|
-
};
|
|
536
|
-
var loadRuntimeSignalEvaluations = async (userName) => {
|
|
537
|
-
const keys = await (0, import_redis.getKeys)(import_redis.redisKeys.runtimeSignalEvaluations(userName));
|
|
538
|
-
const evaluations = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
|
|
539
|
-
return evaluations.filter(isRuntimeSignalEvaluationRecord).sort((left, right) => left.timestamp - right.timestamp);
|
|
540
|
-
};
|
|
541
578
|
var resolveStrategyNameByConfigKey = (userName, key) => {
|
|
542
579
|
const parts = key.split(":");
|
|
543
580
|
if (parts.length !== 5) {
|
|
@@ -550,15 +587,15 @@ var resolveStrategyNameByConfigKey = (userName, key) => {
|
|
|
550
587
|
return strategyName;
|
|
551
588
|
};
|
|
552
589
|
var loadConfiguredStrategyNames = async (userName) => {
|
|
553
|
-
const keys = await (0,
|
|
590
|
+
const keys = await (0, import_redis2.getKeys)(`${import_redis2.redisKeys.strategies(userName)}:`);
|
|
554
591
|
return keys.filter((key) => key.endsWith(":config")).map((key) => resolveStrategyNameByConfigKey(userName, key)).filter((value) => Boolean(value)).sort((left, right) => left.localeCompare(right));
|
|
555
592
|
};
|
|
556
593
|
var loadStrategyResultSymbols = async ({
|
|
557
594
|
userName,
|
|
558
595
|
strategy
|
|
559
596
|
}) => {
|
|
560
|
-
const results = await (0,
|
|
561
|
-
|
|
597
|
+
const results = await (0, import_redis2.getData)(
|
|
598
|
+
import_redis2.redisKeys.strategyResults(userName, strategy),
|
|
562
599
|
{}
|
|
563
600
|
);
|
|
564
601
|
return Object.keys(results ?? {}).sort(
|
|
@@ -709,8 +746,8 @@ var buildReplayConfig = async ({
|
|
|
709
746
|
toleranceMs
|
|
710
747
|
}) => {
|
|
711
748
|
const [userConfig, strategyResults] = await Promise.all([
|
|
712
|
-
(0,
|
|
713
|
-
(0,
|
|
749
|
+
(0, import_redis2.getData)(import_redis2.redisKeys.strategyConfig(userName, strategy), {}),
|
|
750
|
+
(0, import_redis2.getData)(import_redis2.redisKeys.strategyResults(userName, strategy), {})
|
|
714
751
|
]);
|
|
715
752
|
const typedResults = strategyResults ?? {};
|
|
716
753
|
const symbolResult = typedResults?.[symbol];
|