@tradejs/cli 3.1.10-beta.215 → 3.1.11-beta.216
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 +131 -28
- package/dist/lib/runEnvironment.js +18 -2
- package/dist/lib/runtimeEvidenceDeployment.js +9 -5
- package/dist/lib/runtimeRedis.js +13 -0
- package/dist/scripts/backtest.js +6 -3
- package/dist/scripts/replay.js +43 -12
- package/dist/scripts/replayRunner.js +43 -12
- package/dist/scripts/runtimeEvidence.js +4 -2
- package/dist/scripts/signals.js +113 -26
- package/dist/scripts/signalsDaemon.js +113 -26
- package/package.json +7 -7
package/dist/scripts/replay.js
CHANGED
|
@@ -499,6 +499,18 @@ var resolveRunConnectorName = async ({
|
|
|
499
499
|
);
|
|
500
500
|
return import_connectors3.DEFAULT_CONNECTOR_NAME;
|
|
501
501
|
};
|
|
502
|
+
var mergeRuntimeStrategySelections = (strategies) => {
|
|
503
|
+
if (strategies.some((strategy) => !strategy.selection?.tickers)) {
|
|
504
|
+
return void 0;
|
|
505
|
+
}
|
|
506
|
+
return {
|
|
507
|
+
tickers: [
|
|
508
|
+
...new Set(
|
|
509
|
+
strategies.flatMap((strategy) => strategy.selection?.tickers ?? [])
|
|
510
|
+
)
|
|
511
|
+
]
|
|
512
|
+
};
|
|
513
|
+
};
|
|
502
514
|
var loadDeploymentReplayStrategies = async ({
|
|
503
515
|
userName,
|
|
504
516
|
projectRoot,
|
|
@@ -518,14 +530,16 @@ var loadDeploymentReplayStrategies = async ({
|
|
|
518
530
|
strategyPackage,
|
|
519
531
|
strategyPackageVersion,
|
|
520
532
|
runtimePackageVersion,
|
|
521
|
-
sourceStrategyConfig
|
|
533
|
+
sourceStrategyConfig,
|
|
534
|
+
selection
|
|
522
535
|
}) => ({
|
|
523
536
|
strategyName,
|
|
524
537
|
version,
|
|
525
538
|
strategyPackage,
|
|
526
539
|
strategyPackageVersion,
|
|
527
540
|
runtimePackageVersion,
|
|
528
|
-
strategyConfig: sourceStrategyConfig
|
|
541
|
+
strategyConfig: sourceStrategyConfig,
|
|
542
|
+
...selection ? { selection } : {}
|
|
529
543
|
})
|
|
530
544
|
) : [];
|
|
531
545
|
if (!strategies.length) {
|
|
@@ -4663,6 +4677,7 @@ var INTERVALS = /* @__PURE__ */ new Set([
|
|
|
4663
4677
|
"M"
|
|
4664
4678
|
]);
|
|
4665
4679
|
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
4680
|
+
var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
|
|
4666
4681
|
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
4667
4682
|
if (!isRecord(value) || value.schemaVersion !== 1 || !isNonEmptyString(value.id) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
|
|
4668
4683
|
throw new Error(
|
|
@@ -4670,7 +4685,7 @@ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
|
4670
4685
|
);
|
|
4671
4686
|
}
|
|
4672
4687
|
const strategies = value.strategies.map((candidate) => {
|
|
4673
|
-
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !Number.isSafeInteger(candidate.version) || Number(candidate.version) <= 0 || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig)) {
|
|
4688
|
+
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !Number.isSafeInteger(candidate.version) || Number(candidate.version) <= 0 || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
|
|
4674
4689
|
throw new Error(
|
|
4675
4690
|
"Runtime evidence deployment strategy snapshot is invalid"
|
|
4676
4691
|
);
|
|
@@ -4710,11 +4725,12 @@ var runtimeDeploymentFromEvidence = (deployment) => ({
|
|
|
4710
4725
|
accountId: deployment.accountId,
|
|
4711
4726
|
enabled: deployment.enabled,
|
|
4712
4727
|
strategies: deployment.strategies.map(
|
|
4713
|
-
({ strategyName, version, enabled, controlState }) => ({
|
|
4728
|
+
({ strategyName, version, enabled, controlState, selection }) => ({
|
|
4714
4729
|
strategyName,
|
|
4715
4730
|
version,
|
|
4716
4731
|
enabled,
|
|
4717
|
-
controlState
|
|
4732
|
+
controlState,
|
|
4733
|
+
...selection ? { selection } : {}
|
|
4718
4734
|
})
|
|
4719
4735
|
),
|
|
4720
4736
|
...deployment.assetClasses ? { assetClasses: [...deployment.assetClasses] } : {},
|
|
@@ -5479,7 +5495,8 @@ var loadRuntimeStrategies = async (runtimeStrategies) => {
|
|
|
5479
5495
|
strategyPackage,
|
|
5480
5496
|
strategyPackageVersion,
|
|
5481
5497
|
runtimePackageVersion,
|
|
5482
|
-
strategyConfig
|
|
5498
|
+
strategyConfig,
|
|
5499
|
+
selection
|
|
5483
5500
|
} = runtimeStrategy;
|
|
5484
5501
|
const strategyCreator = await (0, import_strategies5.getStrategyCreator)(
|
|
5485
5502
|
strategyName,
|
|
@@ -5509,7 +5526,8 @@ var loadRuntimeStrategies = async (runtimeStrategies) => {
|
|
|
5509
5526
|
runtimePackageVersion,
|
|
5510
5527
|
strategyCreator,
|
|
5511
5528
|
strategyConfig,
|
|
5512
|
-
strategyResults
|
|
5529
|
+
strategyResults,
|
|
5530
|
+
...selection ? { selection } : {}
|
|
5513
5531
|
};
|
|
5514
5532
|
})
|
|
5515
5533
|
);
|
|
@@ -5594,6 +5612,14 @@ var buildAfterSignalsContext = ({
|
|
|
5594
5612
|
})
|
|
5595
5613
|
)
|
|
5596
5614
|
});
|
|
5615
|
+
var strategyIncludesSymbol = (strategy, symbol) => {
|
|
5616
|
+
const tickers = strategy.selection?.tickers;
|
|
5617
|
+
if (!tickers) return true;
|
|
5618
|
+
const normalizedSymbol = symbol.trim().toUpperCase();
|
|
5619
|
+
return tickers.some(
|
|
5620
|
+
(ticker) => ticker.trim().toUpperCase() === normalizedSymbol
|
|
5621
|
+
);
|
|
5622
|
+
};
|
|
5597
5623
|
var buildSymbolSharedReplayKey = ({
|
|
5598
5624
|
connectorName,
|
|
5599
5625
|
interval,
|
|
@@ -5697,7 +5723,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5697
5723
|
});
|
|
5698
5724
|
sharedReplayKeyPrefixes.push(sharedIndicatorsReplayKey);
|
|
5699
5725
|
const strategiesForSymbol = await Promise.all(
|
|
5700
|
-
loadedStrategies.map(
|
|
5726
|
+
loadedStrategies.filter((strategy) => strategyIncludesSymbol(strategy, symbol)).map(
|
|
5701
5727
|
async ({
|
|
5702
5728
|
strategyName,
|
|
5703
5729
|
version,
|
|
@@ -9104,14 +9130,16 @@ var replayBacktest = async () => {
|
|
|
9104
9130
|
strategyPackage,
|
|
9105
9131
|
strategyPackageVersion,
|
|
9106
9132
|
runtimePackageVersion,
|
|
9107
|
-
strategyConfig
|
|
9133
|
+
strategyConfig,
|
|
9134
|
+
selection
|
|
9108
9135
|
}) => ({
|
|
9109
9136
|
strategyName,
|
|
9110
9137
|
version,
|
|
9111
9138
|
strategyPackage,
|
|
9112
9139
|
strategyPackageVersion,
|
|
9113
9140
|
runtimePackageVersion,
|
|
9114
|
-
strategyConfig
|
|
9141
|
+
strategyConfig,
|
|
9142
|
+
...selection ? { selection } : {}
|
|
9115
9143
|
})
|
|
9116
9144
|
)
|
|
9117
9145
|
} : await loadDeploymentReplayStrategies({
|
|
@@ -9143,10 +9171,11 @@ var replayBacktest = async () => {
|
|
|
9143
9171
|
`Replay requires one deployment universe: ${[...strategyUniverses].join(",")}`
|
|
9144
9172
|
);
|
|
9145
9173
|
}
|
|
9174
|
+
const replaySelection = mergeRuntimeStrategySelections(replayStrategies);
|
|
9146
9175
|
const preparedRun = await prepareRunEnvironment({
|
|
9147
9176
|
connector: deployment.connectorName,
|
|
9148
9177
|
userName: replayUserName,
|
|
9149
|
-
tickers: replayFlags.tickers ?? deployment.tickers,
|
|
9178
|
+
tickers: replayFlags.tickers ?? replaySelection?.tickers?.join(",") ?? deployment.tickers?.join(","),
|
|
9150
9179
|
exclude: replayFlags.exclude,
|
|
9151
9180
|
tickersLimit: replayFlags.tickersLimit,
|
|
9152
9181
|
showTickersList: replayFlags.showTickersList,
|
|
@@ -9194,7 +9223,9 @@ var replayBacktest = async () => {
|
|
|
9194
9223
|
const replayResult = await runHistoricalSignalsReplay({
|
|
9195
9224
|
preparedRun,
|
|
9196
9225
|
interval: replayInterval,
|
|
9197
|
-
runtimeStrategies: replayStrategies
|
|
9226
|
+
runtimeStrategies: replayFlags.tickers ? replayStrategies.map(
|
|
9227
|
+
({ selection: _selection, ...strategy }) => strategy
|
|
9228
|
+
) : replayStrategies
|
|
9198
9229
|
});
|
|
9199
9230
|
for (const _strategy of replayResult.strategies) {
|
|
9200
9231
|
incrementSuccessTests();
|
|
@@ -502,6 +502,18 @@ var resolveRunConnectorName = async ({
|
|
|
502
502
|
);
|
|
503
503
|
return import_connectors3.DEFAULT_CONNECTOR_NAME;
|
|
504
504
|
};
|
|
505
|
+
var mergeRuntimeStrategySelections = (strategies) => {
|
|
506
|
+
if (strategies.some((strategy) => !strategy.selection?.tickers)) {
|
|
507
|
+
return void 0;
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
tickers: [
|
|
511
|
+
...new Set(
|
|
512
|
+
strategies.flatMap((strategy) => strategy.selection?.tickers ?? [])
|
|
513
|
+
)
|
|
514
|
+
]
|
|
515
|
+
};
|
|
516
|
+
};
|
|
505
517
|
var loadDeploymentReplayStrategies = async ({
|
|
506
518
|
userName,
|
|
507
519
|
projectRoot,
|
|
@@ -521,14 +533,16 @@ var loadDeploymentReplayStrategies = async ({
|
|
|
521
533
|
strategyPackage,
|
|
522
534
|
strategyPackageVersion,
|
|
523
535
|
runtimePackageVersion,
|
|
524
|
-
sourceStrategyConfig
|
|
536
|
+
sourceStrategyConfig,
|
|
537
|
+
selection
|
|
525
538
|
}) => ({
|
|
526
539
|
strategyName,
|
|
527
540
|
version,
|
|
528
541
|
strategyPackage,
|
|
529
542
|
strategyPackageVersion,
|
|
530
543
|
runtimePackageVersion,
|
|
531
|
-
strategyConfig: sourceStrategyConfig
|
|
544
|
+
strategyConfig: sourceStrategyConfig,
|
|
545
|
+
...selection ? { selection } : {}
|
|
532
546
|
})
|
|
533
547
|
) : [];
|
|
534
548
|
if (!strategies.length) {
|
|
@@ -4666,6 +4680,7 @@ var INTERVALS = /* @__PURE__ */ new Set([
|
|
|
4666
4680
|
"M"
|
|
4667
4681
|
]);
|
|
4668
4682
|
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
4683
|
+
var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
|
|
4669
4684
|
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
4670
4685
|
if (!isRecord(value) || value.schemaVersion !== 1 || !isNonEmptyString(value.id) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
|
|
4671
4686
|
throw new Error(
|
|
@@ -4673,7 +4688,7 @@ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
|
4673
4688
|
);
|
|
4674
4689
|
}
|
|
4675
4690
|
const strategies = value.strategies.map((candidate) => {
|
|
4676
|
-
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !Number.isSafeInteger(candidate.version) || Number(candidate.version) <= 0 || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig)) {
|
|
4691
|
+
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !Number.isSafeInteger(candidate.version) || Number(candidate.version) <= 0 || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
|
|
4677
4692
|
throw new Error(
|
|
4678
4693
|
"Runtime evidence deployment strategy snapshot is invalid"
|
|
4679
4694
|
);
|
|
@@ -4713,11 +4728,12 @@ var runtimeDeploymentFromEvidence = (deployment) => ({
|
|
|
4713
4728
|
accountId: deployment.accountId,
|
|
4714
4729
|
enabled: deployment.enabled,
|
|
4715
4730
|
strategies: deployment.strategies.map(
|
|
4716
|
-
({ strategyName, version, enabled, controlState }) => ({
|
|
4731
|
+
({ strategyName, version, enabled, controlState, selection }) => ({
|
|
4717
4732
|
strategyName,
|
|
4718
4733
|
version,
|
|
4719
4734
|
enabled,
|
|
4720
|
-
controlState
|
|
4735
|
+
controlState,
|
|
4736
|
+
...selection ? { selection } : {}
|
|
4721
4737
|
})
|
|
4722
4738
|
),
|
|
4723
4739
|
...deployment.assetClasses ? { assetClasses: [...deployment.assetClasses] } : {},
|
|
@@ -5482,7 +5498,8 @@ var loadRuntimeStrategies = async (runtimeStrategies) => {
|
|
|
5482
5498
|
strategyPackage,
|
|
5483
5499
|
strategyPackageVersion,
|
|
5484
5500
|
runtimePackageVersion,
|
|
5485
|
-
strategyConfig
|
|
5501
|
+
strategyConfig,
|
|
5502
|
+
selection
|
|
5486
5503
|
} = runtimeStrategy;
|
|
5487
5504
|
const strategyCreator = await (0, import_strategies5.getStrategyCreator)(
|
|
5488
5505
|
strategyName,
|
|
@@ -5512,7 +5529,8 @@ var loadRuntimeStrategies = async (runtimeStrategies) => {
|
|
|
5512
5529
|
runtimePackageVersion,
|
|
5513
5530
|
strategyCreator,
|
|
5514
5531
|
strategyConfig,
|
|
5515
|
-
strategyResults
|
|
5532
|
+
strategyResults,
|
|
5533
|
+
...selection ? { selection } : {}
|
|
5516
5534
|
};
|
|
5517
5535
|
})
|
|
5518
5536
|
);
|
|
@@ -5597,6 +5615,14 @@ var buildAfterSignalsContext = ({
|
|
|
5597
5615
|
})
|
|
5598
5616
|
)
|
|
5599
5617
|
});
|
|
5618
|
+
var strategyIncludesSymbol = (strategy, symbol) => {
|
|
5619
|
+
const tickers = strategy.selection?.tickers;
|
|
5620
|
+
if (!tickers) return true;
|
|
5621
|
+
const normalizedSymbol = symbol.trim().toUpperCase();
|
|
5622
|
+
return tickers.some(
|
|
5623
|
+
(ticker) => ticker.trim().toUpperCase() === normalizedSymbol
|
|
5624
|
+
);
|
|
5625
|
+
};
|
|
5600
5626
|
var buildSymbolSharedReplayKey = ({
|
|
5601
5627
|
connectorName,
|
|
5602
5628
|
interval,
|
|
@@ -5700,7 +5726,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5700
5726
|
});
|
|
5701
5727
|
sharedReplayKeyPrefixes.push(sharedIndicatorsReplayKey);
|
|
5702
5728
|
const strategiesForSymbol = await Promise.all(
|
|
5703
|
-
loadedStrategies.map(
|
|
5729
|
+
loadedStrategies.filter((strategy) => strategyIncludesSymbol(strategy, symbol)).map(
|
|
5704
5730
|
async ({
|
|
5705
5731
|
strategyName,
|
|
5706
5732
|
version,
|
|
@@ -9107,14 +9133,16 @@ var replayBacktest = async () => {
|
|
|
9107
9133
|
strategyPackage,
|
|
9108
9134
|
strategyPackageVersion,
|
|
9109
9135
|
runtimePackageVersion,
|
|
9110
|
-
strategyConfig
|
|
9136
|
+
strategyConfig,
|
|
9137
|
+
selection
|
|
9111
9138
|
}) => ({
|
|
9112
9139
|
strategyName,
|
|
9113
9140
|
version,
|
|
9114
9141
|
strategyPackage,
|
|
9115
9142
|
strategyPackageVersion,
|
|
9116
9143
|
runtimePackageVersion,
|
|
9117
|
-
strategyConfig
|
|
9144
|
+
strategyConfig,
|
|
9145
|
+
...selection ? { selection } : {}
|
|
9118
9146
|
})
|
|
9119
9147
|
)
|
|
9120
9148
|
} : await loadDeploymentReplayStrategies({
|
|
@@ -9146,10 +9174,11 @@ var replayBacktest = async () => {
|
|
|
9146
9174
|
`Replay requires one deployment universe: ${[...strategyUniverses].join(",")}`
|
|
9147
9175
|
);
|
|
9148
9176
|
}
|
|
9177
|
+
const replaySelection = mergeRuntimeStrategySelections(replayStrategies);
|
|
9149
9178
|
const preparedRun = await prepareRunEnvironment({
|
|
9150
9179
|
connector: deployment.connectorName,
|
|
9151
9180
|
userName: replayUserName,
|
|
9152
|
-
tickers: replayFlags.tickers ?? deployment.tickers,
|
|
9181
|
+
tickers: replayFlags.tickers ?? replaySelection?.tickers?.join(",") ?? deployment.tickers?.join(","),
|
|
9153
9182
|
exclude: replayFlags.exclude,
|
|
9154
9183
|
tickersLimit: replayFlags.tickersLimit,
|
|
9155
9184
|
showTickersList: replayFlags.showTickersList,
|
|
@@ -9197,7 +9226,9 @@ var replayBacktest = async () => {
|
|
|
9197
9226
|
const replayResult = await runHistoricalSignalsReplay({
|
|
9198
9227
|
preparedRun,
|
|
9199
9228
|
interval: replayInterval,
|
|
9200
|
-
runtimeStrategies: replayStrategies
|
|
9229
|
+
runtimeStrategies: replayFlags.tickers ? replayStrategies.map(
|
|
9230
|
+
({ selection: _selection, ...strategy }) => strategy
|
|
9231
|
+
) : replayStrategies
|
|
9201
9232
|
});
|
|
9202
9233
|
for (const _strategy of replayResult.strategies) {
|
|
9203
9234
|
incrementSuccessTests();
|
|
@@ -656,7 +656,8 @@ var resolveRuntimeEvidenceDeploymentSnapshot = async ({
|
|
|
656
656
|
strategyPackage,
|
|
657
657
|
strategyPackageVersion,
|
|
658
658
|
runtimePackageVersion,
|
|
659
|
-
sourceStrategyConfig
|
|
659
|
+
sourceStrategyConfig,
|
|
660
|
+
selection
|
|
660
661
|
}) => ({
|
|
661
662
|
strategyName,
|
|
662
663
|
version,
|
|
@@ -668,7 +669,8 @@ var resolveRuntimeEvidenceDeploymentSnapshot = async ({
|
|
|
668
669
|
strategyPackage,
|
|
669
670
|
strategyPackageVersion,
|
|
670
671
|
runtimePackageVersion,
|
|
671
|
-
strategyConfig: sourceStrategyConfig
|
|
672
|
+
strategyConfig: sourceStrategyConfig,
|
|
673
|
+
...selection ? { selection } : {}
|
|
672
674
|
})
|
|
673
675
|
),
|
|
674
676
|
...deployment.assetClasses ? { assetClasses: [...deployment.assetClasses] } : {},
|
package/dist/scripts/signals.js
CHANGED
|
@@ -48,7 +48,7 @@ var import_cli2 = require("@tradejs/node/cli");
|
|
|
48
48
|
var import_async3 = require("@tradejs/core/async");
|
|
49
49
|
var import_strategies5 = require("@tradejs/core/strategies");
|
|
50
50
|
var import_constants3 = require("@tradejs/core/constants");
|
|
51
|
-
var
|
|
51
|
+
var import_time3 = require("@tradejs/core/time");
|
|
52
52
|
var import_logger4 = require("@tradejs/infra/logger");
|
|
53
53
|
var import_runtimeHeartbeats = require("@tradejs/infra/runtimeHeartbeats");
|
|
54
54
|
var import_runtimeStrategies2 = require("@tradejs/node/runtimeStrategies");
|
|
@@ -65,6 +65,38 @@ var getClosedCandlesForInterval = (candles, currentTimestamp, intervalMs) => {
|
|
|
65
65
|
};
|
|
66
66
|
var alignSymbolWithBtcReference = (symbolCandles, btcCandles) => (0, import_indicators.alignSortedCandlesByTimestamp)(symbolCandles, btcCandles);
|
|
67
67
|
|
|
68
|
+
// src/lib/runtimeRedis.ts
|
|
69
|
+
var import_redis = require("@tradejs/infra/redis");
|
|
70
|
+
var import_time = require("@tradejs/core/time");
|
|
71
|
+
var import_runtimeStrategyConfigs = require("@tradejs/infra/runtimeStrategyConfigs");
|
|
72
|
+
var isRuntimeTradeRecord = (value) => {
|
|
73
|
+
if (!value || typeof value !== "object") {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const record = value;
|
|
77
|
+
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");
|
|
78
|
+
};
|
|
79
|
+
var loadRuntimeActiveTradeOrderIds = async (userName) => {
|
|
80
|
+
const keys = await (0, import_redis.getKeys)(import_redis.redisKeys.runtimeActiveTrades(userName));
|
|
81
|
+
const refs = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
|
|
82
|
+
return new Set(
|
|
83
|
+
refs.map(
|
|
84
|
+
(ref) => ref && typeof ref === "object" && "orderId" in ref && typeof ref.orderId === "string" && ref.orderId.trim() ? ref.orderId.trim() : null
|
|
85
|
+
).filter((orderId) => orderId != null)
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
var loadRuntimeActiveTrades = async (userName) => {
|
|
89
|
+
const orderIds = await loadRuntimeActiveTradeOrderIds(userName);
|
|
90
|
+
const trades = await Promise.all(
|
|
91
|
+
[...orderIds].map(
|
|
92
|
+
(orderId) => (0, import_redis.getData)(import_redis.redisKeys.runtimeTrade(userName, orderId), null)
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
return trades.filter(
|
|
96
|
+
(trade) => isRuntimeTradeRecord(trade) && trade.status === "active"
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
68
100
|
// src/lib/runFormatting.ts
|
|
69
101
|
var import_date_fns = require("date-fns");
|
|
70
102
|
var ListIt = require("list-it");
|
|
@@ -3746,7 +3778,7 @@ var import_logger = require("@tradejs/infra/logger");
|
|
|
3746
3778
|
|
|
3747
3779
|
// src/lib/runtimeSignalsStorage.ts
|
|
3748
3780
|
var import_constants2 = require("@tradejs/core/constants");
|
|
3749
|
-
var
|
|
3781
|
+
var import_time2 = require("@tradejs/core/time");
|
|
3750
3782
|
var SECONDS_PER_DAY = 86400;
|
|
3751
3783
|
var RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
|
|
3752
3784
|
var DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants2.TTL_3D;
|
|
@@ -3895,7 +3927,7 @@ var logStrategySkipStats = (runtimeStrategies, strategyStats) => {
|
|
|
3895
3927
|
};
|
|
3896
3928
|
|
|
3897
3929
|
// src/lib/signals/evaluations.ts
|
|
3898
|
-
var
|
|
3930
|
+
var import_redis2 = require("@tradejs/infra/redis");
|
|
3899
3931
|
|
|
3900
3932
|
// src/lib/runtimeLineage.ts
|
|
3901
3933
|
var import_node_child_process = require("child_process");
|
|
@@ -4247,7 +4279,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
4247
4279
|
if (evaluations.length === 0) return;
|
|
4248
4280
|
const evaluationsByDay = /* @__PURE__ */ new Map();
|
|
4249
4281
|
for (const evaluation of evaluations) {
|
|
4250
|
-
const dayKey = (0,
|
|
4282
|
+
const dayKey = (0, import_time2.getRuntimeStorageDayKey)(evaluation.timestamp);
|
|
4251
4283
|
const dayEvaluations = evaluationsByDay.get(dayKey) ?? [];
|
|
4252
4284
|
dayEvaluations.push(evaluation);
|
|
4253
4285
|
evaluationsByDay.set(dayKey, dayEvaluations);
|
|
@@ -4259,7 +4291,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
4259
4291
|
runtimeLineageScopeCacheDayKey = dayKey;
|
|
4260
4292
|
runtimeLineageScopeCacheLoaded = false;
|
|
4261
4293
|
}
|
|
4262
|
-
const lineageBucket =
|
|
4294
|
+
const lineageBucket = import_redis2.redisKeys.runtimeLineageScopeBucket(
|
|
4263
4295
|
dayEvaluations[0].userName,
|
|
4264
4296
|
dayKey
|
|
4265
4297
|
);
|
|
@@ -4267,7 +4299,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
4267
4299
|
(evaluation) => evaluation.runtimeLineage != null
|
|
4268
4300
|
);
|
|
4269
4301
|
if (lineageEvaluations.length > 0 && !runtimeLineageScopeCacheLoaded) {
|
|
4270
|
-
const storedScopes = await (0,
|
|
4302
|
+
const storedScopes = await (0, import_redis2.getHashJsonValues)(lineageBucket);
|
|
4271
4303
|
for (const scope of storedScopes) {
|
|
4272
4304
|
const lineageField = buildLineageField(scope);
|
|
4273
4305
|
runtimeLineageScopeCache.set(`${lineageBucket}:${lineageField}`, scope);
|
|
@@ -4308,7 +4340,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
4308
4340
|
lineageWrites.set(lineageField, scope);
|
|
4309
4341
|
}
|
|
4310
4342
|
if (lineageWrites.size > 0) {
|
|
4311
|
-
await (0,
|
|
4343
|
+
await (0, import_redis2.setHashJsonFields)(
|
|
4312
4344
|
lineageBucket,
|
|
4313
4345
|
[...lineageWrites].map(([field, data]) => ({ field, data })),
|
|
4314
4346
|
{
|
|
@@ -4320,7 +4352,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
4320
4352
|
const statsIncrements = /* @__PURE__ */ new Map();
|
|
4321
4353
|
for (const evaluation of dayEvaluations) {
|
|
4322
4354
|
if (shouldStoreDetailedRuntimeSignalEvaluation(evaluation)) {
|
|
4323
|
-
const bucket =
|
|
4355
|
+
const bucket = import_redis2.redisKeys.runtimeSignalEvaluationBucket(
|
|
4324
4356
|
evaluation.userName,
|
|
4325
4357
|
dayKey,
|
|
4326
4358
|
evaluation.strategy
|
|
@@ -4332,7 +4364,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
4332
4364
|
});
|
|
4333
4365
|
detailedWrites.set(bucket, entries);
|
|
4334
4366
|
}
|
|
4335
|
-
const statsBucket =
|
|
4367
|
+
const statsBucket = import_redis2.redisKeys.runtimeSignalEvaluationStatsBucket(
|
|
4336
4368
|
evaluation.userName,
|
|
4337
4369
|
dayKey,
|
|
4338
4370
|
evaluation.strategy,
|
|
@@ -4348,12 +4380,12 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
4348
4380
|
}
|
|
4349
4381
|
await Promise.all([
|
|
4350
4382
|
...[...detailedWrites].map(
|
|
4351
|
-
([bucket, entries]) => (0,
|
|
4383
|
+
([bucket, entries]) => (0, import_redis2.setHashJsonFields)(bucket, entries, {
|
|
4352
4384
|
expire: runtimeSignalRetentionTtl
|
|
4353
4385
|
})
|
|
4354
4386
|
),
|
|
4355
4387
|
...[...statsIncrements].map(
|
|
4356
|
-
([bucket, increments]) => (0,
|
|
4388
|
+
([bucket, increments]) => (0, import_redis2.incrHashFields)(bucket, increments, {
|
|
4357
4389
|
expire: runtimeSignalRetentionTtl
|
|
4358
4390
|
})
|
|
4359
4391
|
)
|
|
@@ -4369,9 +4401,9 @@ var createRuntimeSignalEvaluationBuffer = () => {
|
|
|
4369
4401
|
const runtimeSignalRetentionTtl = getRuntimeSignalRetentionTtlSeconds();
|
|
4370
4402
|
const signalRefsByBucket = /* @__PURE__ */ new Map();
|
|
4371
4403
|
for (const { userName, signal } of pendingSignals) {
|
|
4372
|
-
const bucket =
|
|
4404
|
+
const bucket = import_redis2.redisKeys.runtimeSignalBucket(
|
|
4373
4405
|
userName,
|
|
4374
|
-
(0,
|
|
4406
|
+
(0, import_time2.getRuntimeStorageDayKey)(signal.timestamp),
|
|
4375
4407
|
signal.strategy
|
|
4376
4408
|
);
|
|
4377
4409
|
const entries = signalRefsByBucket.get(bucket) ?? [];
|
|
@@ -4383,14 +4415,14 @@ var createRuntimeSignalEvaluationBuffer = () => {
|
|
|
4383
4415
|
}
|
|
4384
4416
|
await Promise.all([
|
|
4385
4417
|
...pendingSignals.map(
|
|
4386
|
-
({ signal }) => (0,
|
|
4387
|
-
|
|
4418
|
+
({ signal }) => (0, import_redis2.setData)(
|
|
4419
|
+
import_redis2.redisKeys.storeSignal(signal.symbol, signal.signalId),
|
|
4388
4420
|
toStoredRuntimeSignal(signal),
|
|
4389
4421
|
{ expire: runtimeSignalRetentionTtl }
|
|
4390
4422
|
)
|
|
4391
4423
|
),
|
|
4392
4424
|
...[...signalRefsByBucket].map(
|
|
4393
|
-
([bucket, entries]) => (0,
|
|
4425
|
+
([bucket, entries]) => (0, import_redis2.setHashJsonFields)(bucket, entries, {
|
|
4394
4426
|
expire: runtimeSignalRetentionTtl
|
|
4395
4427
|
})
|
|
4396
4428
|
)
|
|
@@ -4629,9 +4661,9 @@ var import_candles = require("@tradejs/infra/timescale/candles");
|
|
|
4629
4661
|
|
|
4630
4662
|
// src/lib/marketData/klineEvents.ts
|
|
4631
4663
|
var import_ioredis = __toESM(require("ioredis"));
|
|
4632
|
-
var
|
|
4664
|
+
var import_redis3 = require("@tradejs/infra/redis");
|
|
4633
4665
|
var MARKET_KLINE_CHANNEL = "tradejs:market:kline";
|
|
4634
|
-
var publishMarketKlineEvent = (event) => (0,
|
|
4666
|
+
var publishMarketKlineEvent = (event) => (0, import_redis3.publishData)(MARKET_KLINE_CHANNEL, event);
|
|
4635
4667
|
|
|
4636
4668
|
// src/lib/signals/klineFeed.ts
|
|
4637
4669
|
var FLUSH_DELAY_MS = 100;
|
|
@@ -5037,6 +5069,23 @@ var createSignalsTickerEvaluator = ({
|
|
|
5037
5069
|
// src/lib/signals/configuredScopes.ts
|
|
5038
5070
|
var sorted = (values) => values ? [...values].sort() : [];
|
|
5039
5071
|
var formatConfiguredStrategyIdentity = (strategy) => `${strategy.strategyName}@v${strategy.version}[${strategy.controlState}]`;
|
|
5072
|
+
var getConfiguredScopeActiveSymbols = ({
|
|
5073
|
+
trades,
|
|
5074
|
+
deploymentId,
|
|
5075
|
+
strategyNames,
|
|
5076
|
+
universe,
|
|
5077
|
+
accountId,
|
|
5078
|
+
interval
|
|
5079
|
+
}) => {
|
|
5080
|
+
const strategyNameSet = new Set(strategyNames);
|
|
5081
|
+
return [
|
|
5082
|
+
...new Set(
|
|
5083
|
+
trades.filter(
|
|
5084
|
+
(trade) => trade.status === "active" && trade.deploymentId === deploymentId && strategyNameSet.has(trade.strategy) && (trade.universe ?? "crypto") === universe && (!trade.accountId || trade.accountId === accountId) && (!trade.interval || String(trade.interval) === String(interval))
|
|
5085
|
+
).map(({ symbol }) => symbol)
|
|
5086
|
+
)
|
|
5087
|
+
].sort();
|
|
5088
|
+
};
|
|
5040
5089
|
var buildConfiguredSignalsScopes = ({
|
|
5041
5090
|
connectorName,
|
|
5042
5091
|
deployment,
|
|
@@ -5053,21 +5102,30 @@ var buildConfiguredSignalsScopes = ({
|
|
|
5053
5102
|
});
|
|
5054
5103
|
const groups = /* @__PURE__ */ new Map();
|
|
5055
5104
|
for (const strategy of strategies) {
|
|
5105
|
+
const selectionIdentity = JSON.stringify({
|
|
5106
|
+
tickers: sorted(strategy.selection?.tickers)
|
|
5107
|
+
});
|
|
5056
5108
|
const baseKey = [
|
|
5057
5109
|
connectorName,
|
|
5058
5110
|
strategy.universe,
|
|
5059
5111
|
strategy.accountId ?? "default",
|
|
5060
|
-
strategy.interval
|
|
5112
|
+
strategy.interval,
|
|
5113
|
+
selectionIdentity
|
|
5061
5114
|
].join(":");
|
|
5062
5115
|
const group = groups.get(baseKey) ?? {
|
|
5063
5116
|
scope: {
|
|
5064
5117
|
connectorName,
|
|
5065
5118
|
universe: strategy.universe,
|
|
5066
5119
|
accountId: strategy.accountId,
|
|
5067
|
-
interval: strategy.interval
|
|
5120
|
+
interval: strategy.interval,
|
|
5121
|
+
strategyNames: [],
|
|
5122
|
+
...strategy.selection ? {
|
|
5123
|
+
selection: { tickers: [...strategy.selection.tickers] }
|
|
5124
|
+
} : {}
|
|
5068
5125
|
},
|
|
5069
5126
|
strategyIdentities: []
|
|
5070
5127
|
};
|
|
5128
|
+
group.scope.strategyNames.push(strategy.strategyName);
|
|
5071
5129
|
group.strategyIdentities.push(formatConfiguredStrategyIdentity(strategy));
|
|
5072
5130
|
groups.set(baseKey, group);
|
|
5073
5131
|
}
|
|
@@ -5075,7 +5133,10 @@ var buildConfiguredSignalsScopes = ({
|
|
|
5075
5133
|
key: [baseKey, deploymentIdentity, ...group.strategyIdentities.sort()].join(
|
|
5076
5134
|
":"
|
|
5077
5135
|
),
|
|
5078
|
-
scope:
|
|
5136
|
+
scope: {
|
|
5137
|
+
...group.scope,
|
|
5138
|
+
strategyNames: [...group.scope.strategyNames].sort()
|
|
5139
|
+
}
|
|
5079
5140
|
}));
|
|
5080
5141
|
};
|
|
5081
5142
|
|
|
@@ -5188,6 +5249,10 @@ var createSignalsRunner = (config2) => {
|
|
|
5188
5249
|
interval: runtimeInterval,
|
|
5189
5250
|
intervalMs: runtimeIntervalMs,
|
|
5190
5251
|
deployment,
|
|
5252
|
+
...scope.strategyNames ? { strategyNames: [...scope.strategyNames] } : {},
|
|
5253
|
+
...scope.selection ? {
|
|
5254
|
+
selection: { tickers: [...scope.selection.tickers] }
|
|
5255
|
+
} : {},
|
|
5191
5256
|
startedAt: Date.now(),
|
|
5192
5257
|
marketConnector,
|
|
5193
5258
|
btcReferences,
|
|
@@ -5217,13 +5282,31 @@ var createSignalsRunner = (config2) => {
|
|
|
5217
5282
|
btcReferences,
|
|
5218
5283
|
lifecycle,
|
|
5219
5284
|
interval: interval2,
|
|
5220
|
-
intervalMs
|
|
5285
|
+
intervalMs,
|
|
5286
|
+
strategyNames,
|
|
5287
|
+
selection
|
|
5221
5288
|
} = session;
|
|
5222
5289
|
const universe = sessionUniverse ?? marketConnector.universe ?? "crypto";
|
|
5290
|
+
const selectedActiveSymbols = !config2.tickers && selection?.tickers?.length && strategyNames?.length ? getConfiguredScopeActiveSymbols({
|
|
5291
|
+
trades: await loadRuntimeActiveTrades(config2.userName),
|
|
5292
|
+
deploymentId: deployment?.id ?? "",
|
|
5293
|
+
strategyNames,
|
|
5294
|
+
universe,
|
|
5295
|
+
accountId,
|
|
5296
|
+
interval: interval2
|
|
5297
|
+
}) : [];
|
|
5298
|
+
const selectedTickers = selection?.tickers ? [.../* @__PURE__ */ new Set([...selection.tickers, ...selectedActiveSymbols])] : void 0;
|
|
5299
|
+
if (selectedActiveSymbols.length) {
|
|
5300
|
+
import_logger4.logger.info(
|
|
5301
|
+
import_chalk7.default.gray(
|
|
5302
|
+
`strategy selection retained active symbols: ${selectedActiveSymbols.join(", ")}`
|
|
5303
|
+
)
|
|
5304
|
+
);
|
|
5305
|
+
}
|
|
5223
5306
|
const tickers = await timeOperation2("tickers load", () => {
|
|
5224
5307
|
const baseArgs = [
|
|
5225
5308
|
marketConnector,
|
|
5226
|
-
config2.tickers || deployment?.tickers?.join(","),
|
|
5309
|
+
config2.tickers || selectedTickers?.join(",") || deployment?.tickers?.join(","),
|
|
5227
5310
|
config2.exclude,
|
|
5228
5311
|
config2.tickersLimit,
|
|
5229
5312
|
config2.chunk
|
|
@@ -5250,8 +5333,8 @@ var createSignalsRunner = (config2) => {
|
|
|
5250
5333
|
}
|
|
5251
5334
|
const projectConfig = await (0, import_cli2.loadTradejsConfig)(projectRoot);
|
|
5252
5335
|
projectHooks = projectConfig.hooks;
|
|
5253
|
-
const currentTimestamp = (0,
|
|
5254
|
-
const preloadStart = (0,
|
|
5336
|
+
const currentTimestamp = (0, import_time3.getTimestamp)();
|
|
5337
|
+
const preloadStart = (0, import_time3.getTimestamp)(import_constants3.SIGNALS_CLI_PRELOAD_DAYS);
|
|
5255
5338
|
if (!config2.cacheOnly && session.klineFeed) {
|
|
5256
5339
|
const expectedSymbols = universe === "crypto" ? [.../* @__PURE__ */ new Set([...tickers, "BTCUSDT", "ETHUSDT"])] : tickers;
|
|
5257
5340
|
session.klineFeed.setSubscriptions(expectedSymbols);
|
|
@@ -5366,7 +5449,7 @@ var createSignalsRunner = (config2) => {
|
|
|
5366
5449
|
const primaryEthByTimestamp = new Map(
|
|
5367
5450
|
primaryEthClosedData.map((candle) => [candle.timestamp, candle])
|
|
5368
5451
|
);
|
|
5369
|
-
const
|
|
5452
|
+
const configuredRuntimeStrategies = await (0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({
|
|
5370
5453
|
userName: config2.userName,
|
|
5371
5454
|
projectRoot,
|
|
5372
5455
|
deploymentId: deployment?.id ?? "",
|
|
@@ -5374,6 +5457,10 @@ var createSignalsRunner = (config2) => {
|
|
|
5374
5457
|
accountId,
|
|
5375
5458
|
interval: interval2
|
|
5376
5459
|
});
|
|
5460
|
+
const selectedStrategyNames = strategyNames?.length ? new Set(strategyNames) : null;
|
|
5461
|
+
const runtimeStrategies = selectedStrategyNames ? configuredRuntimeStrategies.filter(
|
|
5462
|
+
({ strategyName }) => selectedStrategyNames.has(strategyName)
|
|
5463
|
+
) : configuredRuntimeStrategies;
|
|
5377
5464
|
if (!runtimeStrategies.length) {
|
|
5378
5465
|
lifecycle.clear();
|
|
5379
5466
|
import_logger4.logger.warn(
|