@tradejs/node 3.1.11 → 3.1.12-beta.217
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/ai.js +0 -1
- package/dist/ai.mjs +1 -1
- package/dist/backtest.js +99 -82
- package/dist/backtest.mjs +2 -2
- package/dist/{chunk-B6X2HEGL.mjs → chunk-6PIVDS4M.mjs} +6 -6
- package/dist/{chunk-C3KRBNUR.mjs → chunk-IKRSNRP6.mjs} +58 -31
- package/dist/chunk-NQO2MFP6.mjs +552 -0
- package/dist/cli.js +108 -91
- package/dist/cli.mjs +1 -1
- package/dist/registry.js +86 -65
- package/dist/registry.mjs +2 -2
- package/dist/runtimeDashboard.js +420 -216
- package/dist/runtimeDashboard.mjs +9 -9
- package/dist/runtimeStrategies.d.mts +66 -6
- package/dist/runtimeStrategies.d.ts +66 -6
- package/dist/runtimeStrategies.js +450 -218
- package/dist/runtimeStrategies.mjs +11 -3
- package/dist/strategies.js +97 -76
- package/dist/strategies.mjs +2 -2
- package/package.json +14 -8
- package/dist/chunk-7BAL7EN3.mjs +0 -345
package/dist/runtimeDashboard.js
CHANGED
|
@@ -34,7 +34,7 @@ __export(runtimeDashboard_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(runtimeDashboard_exports);
|
|
36
36
|
var import_time4 = require("@tradejs/core/time");
|
|
37
|
-
var
|
|
37
|
+
var import_logger14 = require("@tradejs/infra/logger");
|
|
38
38
|
var import_tradingAccounts3 = require("@tradejs/infra/tradingAccounts");
|
|
39
39
|
var import_redis4 = require("@tradejs/infra/redis");
|
|
40
40
|
|
|
@@ -1329,6 +1329,7 @@ var syncRuntimeTrades = async ({
|
|
|
1329
1329
|
};
|
|
1330
1330
|
|
|
1331
1331
|
// src/runtimeStrategies.ts
|
|
1332
|
+
var import_node_crypto4 = require("crypto");
|
|
1332
1333
|
var import_promises = require("fs/promises");
|
|
1333
1334
|
var import_node_path = __toESM(require("path"));
|
|
1334
1335
|
var import_runtimeControls = require("@tradejs/infra/runtimeControls");
|
|
@@ -1337,10 +1338,10 @@ var import_tradingAccounts2 = require("@tradejs/infra/tradingAccounts");
|
|
|
1337
1338
|
// src/strategyRuntime.ts
|
|
1338
1339
|
var import_constants7 = require("@tradejs/core/constants");
|
|
1339
1340
|
var import_strategies6 = require("@tradejs/core/strategies");
|
|
1340
|
-
var
|
|
1341
|
+
var import_logger13 = require("@tradejs/infra/logger");
|
|
1341
1342
|
|
|
1342
1343
|
// src/strategyHelpers/runtime.ts
|
|
1343
|
-
var
|
|
1344
|
+
var import_logger11 = require("@tradejs/infra/logger");
|
|
1344
1345
|
var import_constants5 = require("@tradejs/core/constants");
|
|
1345
1346
|
var import_ml2 = require("@tradejs/infra/ml");
|
|
1346
1347
|
|
|
@@ -1922,7 +1923,6 @@ var buildAiMarketContext = (signal) => ({
|
|
|
1922
1923
|
|
|
1923
1924
|
// src/strategy/manifests.ts
|
|
1924
1925
|
var import_indicators = require("@tradejs/core/indicators");
|
|
1925
|
-
var import_logger5 = require("@tradejs/infra/logger");
|
|
1926
1926
|
var SHARED_STRATEGY_REGISTRY_KEY = "__tradejsNodeSharedStrategyRegistryV1__";
|
|
1927
1927
|
var sharedRegistryScope = globalThis;
|
|
1928
1928
|
var sharedStrategyRegistry = sharedRegistryScope[SHARED_STRATEGY_REGISTRY_KEY] ?? (sharedRegistryScope[SHARED_STRATEGY_REGISTRY_KEY] = {
|
|
@@ -1986,21 +1986,34 @@ var extractIndicatorPluginDefinition = (moduleExport) => {
|
|
|
1986
1986
|
);
|
|
1987
1987
|
return indicatorEntries ? { indicatorEntries } : null;
|
|
1988
1988
|
};
|
|
1989
|
-
var
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1989
|
+
var validateStrategyEntries = (moduleName, entries, state) => {
|
|
1990
|
+
const issues = [];
|
|
1991
|
+
const names = /* @__PURE__ */ new Set();
|
|
1992
|
+
entries.forEach((entry, index) => {
|
|
1993
|
+
const entryPath = `${moduleName}.strategyEntries[${index}]`;
|
|
1994
|
+
const strategyName = entry?.manifest?.name;
|
|
1995
|
+
if (typeof strategyName !== "string" || !strategyName.trim()) {
|
|
1996
|
+
issues.push(`${entryPath}: manifest.name is required`);
|
|
1997
|
+
} else if (names.has(strategyName) || state.strategyEntriesMap.has(strategyName)) {
|
|
1998
|
+
issues.push(`${entryPath}: duplicate strategy ${strategyName}`);
|
|
1999
|
+
} else {
|
|
2000
|
+
names.add(strategyName);
|
|
1995
2001
|
}
|
|
1996
|
-
if (
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
);
|
|
2002
|
-
continue;
|
|
2002
|
+
if (!entry || typeof entry !== "object" || !entry.defaults || typeof entry.defaults !== "object" || Array.isArray(entry.defaults)) {
|
|
2003
|
+
issues.push(`${entryPath}: defaults must be an object`);
|
|
2004
|
+
}
|
|
2005
|
+
if (typeof entry?.parseConfig !== "function") {
|
|
2006
|
+
issues.push(`${entryPath}: parseConfig is required`);
|
|
2003
2007
|
}
|
|
2008
|
+
if (typeof entry?.createCore !== "function") {
|
|
2009
|
+
issues.push(`${entryPath}: createCore is required`);
|
|
2010
|
+
}
|
|
2011
|
+
});
|
|
2012
|
+
return issues;
|
|
2013
|
+
};
|
|
2014
|
+
var registerEntries2 = (entries, source, state) => {
|
|
2015
|
+
for (const entry of entries) {
|
|
2016
|
+
const strategyName = entry.manifest.name;
|
|
2004
2017
|
state.strategyManifestsMap.set(strategyName, entry.manifest);
|
|
2005
2018
|
state.strategyEntriesMap.set(strategyName, entry);
|
|
2006
2019
|
state.strategySourcesMap.set(strategyName, source);
|
|
@@ -2057,6 +2070,7 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
|
|
|
2057
2070
|
if (!pluginModuleNames.length) {
|
|
2058
2071
|
return;
|
|
2059
2072
|
}
|
|
2073
|
+
const issues = [];
|
|
2060
2074
|
for (const moduleName of pluginModuleNames) {
|
|
2061
2075
|
try {
|
|
2062
2076
|
const resolvedModuleName = resolvePluginModuleSpecifier(
|
|
@@ -2070,24 +2084,30 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
|
|
|
2070
2084
|
if (strategySet.has(moduleName)) {
|
|
2071
2085
|
const pluginDefinition = extractStrategyPluginDefinition(moduleExport);
|
|
2072
2086
|
if (!pluginDefinition) {
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
moduleName
|
|
2087
|
+
issues.push(
|
|
2088
|
+
`${moduleName}: export { strategyEntries } is missing`
|
|
2076
2089
|
);
|
|
2077
2090
|
} else {
|
|
2078
|
-
|
|
2079
|
-
pluginDefinition.strategyEntries,
|
|
2091
|
+
const entryIssues = validateStrategyEntries(
|
|
2080
2092
|
moduleName,
|
|
2093
|
+
pluginDefinition.strategyEntries,
|
|
2081
2094
|
state
|
|
2082
2095
|
);
|
|
2096
|
+
issues.push(...entryIssues);
|
|
2097
|
+
if (entryIssues.length === 0) {
|
|
2098
|
+
registerEntries2(
|
|
2099
|
+
pluginDefinition.strategyEntries,
|
|
2100
|
+
moduleName,
|
|
2101
|
+
state
|
|
2102
|
+
);
|
|
2103
|
+
}
|
|
2083
2104
|
}
|
|
2084
2105
|
}
|
|
2085
2106
|
if (indicatorSet.has(moduleName)) {
|
|
2086
2107
|
const indicatorPluginDefinition = extractIndicatorPluginDefinition(moduleExport);
|
|
2087
2108
|
if (!indicatorPluginDefinition) {
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
moduleName
|
|
2109
|
+
issues.push(
|
|
2110
|
+
`${moduleName}: export { indicatorEntries } is missing`
|
|
2091
2111
|
);
|
|
2092
2112
|
} else {
|
|
2093
2113
|
(0, import_indicators.registerIndicatorEntries)(
|
|
@@ -2098,19 +2118,17 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
|
|
|
2098
2118
|
}
|
|
2099
2119
|
}
|
|
2100
2120
|
if (!strategySet.has(moduleName) && !indicatorSet.has(moduleName)) {
|
|
2101
|
-
|
|
2102
|
-
'Skip plugin "%s": no strategy/indicator sections requested in config',
|
|
2103
|
-
moduleName
|
|
2104
|
-
);
|
|
2121
|
+
issues.push(`${moduleName}: plugin is not declared in config`);
|
|
2105
2122
|
}
|
|
2106
2123
|
} catch (error) {
|
|
2107
|
-
|
|
2108
|
-
'Failed to load plugin "%s": %s',
|
|
2109
|
-
moduleName,
|
|
2110
|
-
String(error)
|
|
2111
|
-
);
|
|
2124
|
+
issues.push(`${moduleName}: failed to import: ${String(error)}`);
|
|
2112
2125
|
}
|
|
2113
2126
|
}
|
|
2127
|
+
if (issues.length > 0) {
|
|
2128
|
+
throw new Error(
|
|
2129
|
+
["Invalid TradeJS plugin catalog:", ...issues].join("\n")
|
|
2130
|
+
);
|
|
2131
|
+
}
|
|
2114
2132
|
})();
|
|
2115
2133
|
}
|
|
2116
2134
|
await state.pluginsLoadPromise;
|
|
@@ -2120,6 +2138,11 @@ var getStrategyCreator = async (name, cwd = getTradejsProjectCwd()) => {
|
|
|
2120
2138
|
const { state } = getStrategyRegistryState(cwd);
|
|
2121
2139
|
return state.strategyCreators.get(name);
|
|
2122
2140
|
};
|
|
2141
|
+
var getStrategyEntry = async (name, cwd = getTradejsProjectCwd()) => {
|
|
2142
|
+
await ensureStrategyPluginsLoaded(cwd);
|
|
2143
|
+
const { state } = getStrategyRegistryState(cwd);
|
|
2144
|
+
return state.strategyEntriesMap.get(name);
|
|
2145
|
+
};
|
|
2123
2146
|
var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd()) => {
|
|
2124
2147
|
await ensureStrategyPluginsLoaded(cwd);
|
|
2125
2148
|
const { state } = getStrategyRegistryState(cwd);
|
|
@@ -2772,7 +2795,7 @@ var import_node_crypto = require("crypto");
|
|
|
2772
2795
|
var import_constants3 = require("@tradejs/core/constants");
|
|
2773
2796
|
var import_time3 = require("@tradejs/core/time");
|
|
2774
2797
|
var import_trade = require("@tradejs/core/trade");
|
|
2775
|
-
var
|
|
2798
|
+
var import_logger5 = require("@tradejs/infra/logger");
|
|
2776
2799
|
var import_redis3 = require("@tradejs/infra/redis");
|
|
2777
2800
|
var now = () => Date.now();
|
|
2778
2801
|
var toRandomOrderSuffix = () => (0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12).toLowerCase();
|
|
@@ -2831,7 +2854,7 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
2831
2854
|
)
|
|
2832
2855
|
]);
|
|
2833
2856
|
} catch (error) {
|
|
2834
|
-
|
|
2857
|
+
import_logger5.logger.error(
|
|
2835
2858
|
"runtime trade open journal failed: %s %s",
|
|
2836
2859
|
record.symbol,
|
|
2837
2860
|
error?.message || String(error)
|
|
@@ -2898,7 +2921,7 @@ var recordRuntimeTradeIncrease = async (params) => {
|
|
|
2898
2921
|
)
|
|
2899
2922
|
]);
|
|
2900
2923
|
} catch (error) {
|
|
2901
|
-
|
|
2924
|
+
import_logger5.logger.error(
|
|
2902
2925
|
"runtime trade increase journal failed: %s %s",
|
|
2903
2926
|
symbol,
|
|
2904
2927
|
error?.message || String(error)
|
|
@@ -3005,7 +3028,7 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3005
3028
|
)
|
|
3006
3029
|
]);
|
|
3007
3030
|
} catch (error) {
|
|
3008
|
-
|
|
3031
|
+
import_logger5.logger.error(
|
|
3009
3032
|
"runtime trade close journal failed: %s %s",
|
|
3010
3033
|
symbol,
|
|
3011
3034
|
error?.message || String(error)
|
|
@@ -3015,11 +3038,11 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3015
3038
|
};
|
|
3016
3039
|
|
|
3017
3040
|
// src/strategyHelpers/marketContextStages.ts
|
|
3018
|
-
var
|
|
3041
|
+
var import_logger10 = require("@tradejs/infra/logger");
|
|
3019
3042
|
|
|
3020
3043
|
// src/strategyHelpers/binanceMarketContext.ts
|
|
3021
3044
|
var import_marketContext = require("@tradejs/infra/timescale/marketContext");
|
|
3022
|
-
var
|
|
3045
|
+
var import_logger6 = require("@tradejs/infra/logger");
|
|
3023
3046
|
var import_strategies = require("@tradejs/core/strategies");
|
|
3024
3047
|
|
|
3025
3048
|
// src/binanceBreadthUniverses.ts
|
|
@@ -3615,7 +3638,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3615
3638
|
throw error;
|
|
3616
3639
|
}
|
|
3617
3640
|
binanceMarketContextUnavailable = true;
|
|
3618
|
-
|
|
3641
|
+
import_logger6.logger.warn(
|
|
3619
3642
|
"Binance market context disabled after Timescale read failure: %s",
|
|
3620
3643
|
String(error)
|
|
3621
3644
|
);
|
|
@@ -3625,7 +3648,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3625
3648
|
|
|
3626
3649
|
// src/strategyHelpers/coinMarketCapContext.ts
|
|
3627
3650
|
var import_strategies2 = require("@tradejs/core/strategies");
|
|
3628
|
-
var
|
|
3651
|
+
var import_logger7 = require("@tradejs/infra/logger");
|
|
3629
3652
|
var import_marketContext2 = require("@tradejs/infra/timescale/marketContext");
|
|
3630
3653
|
var DEFAULT_MAX_AGE_MS = 48 * 60 * 6e4;
|
|
3631
3654
|
var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
|
|
@@ -4114,7 +4137,7 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4114
4137
|
throw error;
|
|
4115
4138
|
}
|
|
4116
4139
|
coinMarketCapContextUnavailable = true;
|
|
4117
|
-
|
|
4140
|
+
import_logger7.logger.warn(
|
|
4118
4141
|
"CoinMarketCap context disabled after Timescale read failure: %s",
|
|
4119
4142
|
String(error)
|
|
4120
4143
|
);
|
|
@@ -4128,7 +4151,7 @@ var import_data2 = require("@tradejs/core/data");
|
|
|
4128
4151
|
var import_strategies3 = require("@tradejs/core/strategies");
|
|
4129
4152
|
var import_constants4 = require("@tradejs/core/constants");
|
|
4130
4153
|
var import_derivatives = require("@tradejs/infra/timescale/derivatives");
|
|
4131
|
-
var
|
|
4154
|
+
var import_logger8 = require("@tradejs/infra/logger");
|
|
4132
4155
|
var STORED_INTERVALS = ["15m", "1h"];
|
|
4133
4156
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
4134
4157
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
@@ -4360,7 +4383,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4360
4383
|
throw error;
|
|
4361
4384
|
}
|
|
4362
4385
|
derivativesContextUnavailable = true;
|
|
4363
|
-
|
|
4386
|
+
import_logger8.logger.warn(
|
|
4364
4387
|
"Derivatives context disabled after Timescale read failure: %s",
|
|
4365
4388
|
String(error)
|
|
4366
4389
|
);
|
|
@@ -4372,7 +4395,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4372
4395
|
var import_data3 = require("@tradejs/core/data");
|
|
4373
4396
|
var import_strategies4 = require("@tradejs/core/strategies");
|
|
4374
4397
|
var import_hyperliquidWhales2 = require("@tradejs/infra/timescale/hyperliquidWhales");
|
|
4375
|
-
var
|
|
4398
|
+
var import_logger9 = require("@tradejs/infra/logger");
|
|
4376
4399
|
|
|
4377
4400
|
// src/hyperliquidWhaleUniverse.ts
|
|
4378
4401
|
var import_node_crypto3 = require("crypto");
|
|
@@ -4892,7 +4915,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
4892
4915
|
throw error;
|
|
4893
4916
|
}
|
|
4894
4917
|
hyperliquidWhaleContextUnavailable = true;
|
|
4895
|
-
|
|
4918
|
+
import_logger9.logger.warn(
|
|
4896
4919
|
"Hyperliquid whale context disabled after Timescale read failure: %s",
|
|
4897
4920
|
String(error)
|
|
4898
4921
|
);
|
|
@@ -4975,7 +4998,7 @@ var runMarketContextStage = async ({
|
|
|
4975
4998
|
elapsedMs: Date.now() - startedAt
|
|
4976
4999
|
};
|
|
4977
5000
|
if (status === "timed_out") {
|
|
4978
|
-
|
|
5001
|
+
import_logger10.logger.warn(
|
|
4979
5002
|
"Market context stage timed out: %s after %sms",
|
|
4980
5003
|
stage,
|
|
4981
5004
|
result.elapsedMs
|
|
@@ -5165,7 +5188,7 @@ var enrichSignalWithAi = async ({
|
|
|
5165
5188
|
signal.aiAnalysis = analysis;
|
|
5166
5189
|
return resolveAiQuality(analysis, direction);
|
|
5167
5190
|
} catch (err) {
|
|
5168
|
-
|
|
5191
|
+
import_logger11.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
|
|
5169
5192
|
}
|
|
5170
5193
|
return void 0;
|
|
5171
5194
|
};
|
|
@@ -5200,7 +5223,7 @@ var getOrderArrivalSnapshot = async ({
|
|
|
5200
5223
|
spreadBps
|
|
5201
5224
|
};
|
|
5202
5225
|
} catch (error) {
|
|
5203
|
-
|
|
5226
|
+
import_logger11.logger.warn(
|
|
5204
5227
|
"runtime order arrival snapshot failed: %s %s",
|
|
5205
5228
|
symbol,
|
|
5206
5229
|
error?.message || String(error)
|
|
@@ -5429,7 +5452,7 @@ var executeEntryOrder = async ({
|
|
|
5429
5452
|
deploymentId: signal.deploymentId,
|
|
5430
5453
|
policyProfileId: signal.policyProfileId,
|
|
5431
5454
|
runtimeConfigId: signal.runtimeConfigId,
|
|
5432
|
-
|
|
5455
|
+
strategyRevision: signal.strategyRevision,
|
|
5433
5456
|
runtimeLineage: signal.runtimeLineage,
|
|
5434
5457
|
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {}
|
|
5435
5458
|
});
|
|
@@ -5981,7 +6004,7 @@ var canUseSharedReplayState = ({
|
|
|
5981
6004
|
}) => (env === "BACKTEST" || env === "PARITY") && Boolean(sharedReplayKey);
|
|
5982
6005
|
|
|
5983
6006
|
// src/strategy/runtimeExecution.ts
|
|
5984
|
-
var
|
|
6007
|
+
var import_logger12 = require("@tradejs/infra/logger");
|
|
5985
6008
|
var import_types = require("@tradejs/types");
|
|
5986
6009
|
var buildExitOrderSignal = ({
|
|
5987
6010
|
strategyName,
|
|
@@ -6033,7 +6056,7 @@ var handleExitDecision = async ({
|
|
|
6033
6056
|
deploymentId: connector.deploymentId
|
|
6034
6057
|
});
|
|
6035
6058
|
if (!activeTrade) {
|
|
6036
|
-
|
|
6059
|
+
import_logger12.logger.warn(
|
|
6037
6060
|
"[%s] blocked closePosition for untracked runtime position: %s",
|
|
6038
6061
|
strategyName ?? "unknown",
|
|
6039
6062
|
symbol
|
|
@@ -6041,7 +6064,7 @@ var handleExitDecision = async ({
|
|
|
6041
6064
|
return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
|
|
6042
6065
|
}
|
|
6043
6066
|
if (!strategyName || activeTrade.strategy !== strategyName) {
|
|
6044
|
-
|
|
6067
|
+
import_logger12.logger.warn(
|
|
6045
6068
|
"[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
|
|
6046
6069
|
strategyName ?? "unknown",
|
|
6047
6070
|
symbol,
|
|
@@ -6093,7 +6116,7 @@ var handleExitDecision = async ({
|
|
|
6093
6116
|
exitType: closedTrade?.exitType ?? "exit"
|
|
6094
6117
|
});
|
|
6095
6118
|
} catch (notificationError) {
|
|
6096
|
-
|
|
6119
|
+
import_logger12.logger.error(
|
|
6097
6120
|
"runtime close notification error: %s %s",
|
|
6098
6121
|
symbol,
|
|
6099
6122
|
notificationError
|
|
@@ -6107,7 +6130,7 @@ var handleExitDecision = async ({
|
|
|
6107
6130
|
decision,
|
|
6108
6131
|
market
|
|
6109
6132
|
});
|
|
6110
|
-
|
|
6133
|
+
import_logger12.logger.error("close order error: %s %s", symbol, err);
|
|
6111
6134
|
return "ORDER_ERROR";
|
|
6112
6135
|
}
|
|
6113
6136
|
return decision.code;
|
|
@@ -6134,7 +6157,7 @@ var handleProtectDecision = async ({
|
|
|
6134
6157
|
decision,
|
|
6135
6158
|
market
|
|
6136
6159
|
});
|
|
6137
|
-
|
|
6160
|
+
import_logger12.logger.error("protect position error: %s %s", symbol, err);
|
|
6138
6161
|
return "ORDER_ERROR";
|
|
6139
6162
|
}
|
|
6140
6163
|
return decision.code;
|
|
@@ -6297,9 +6320,9 @@ var executeEntryDecision = async ({
|
|
|
6297
6320
|
market
|
|
6298
6321
|
});
|
|
6299
6322
|
if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
|
|
6300
|
-
|
|
6323
|
+
import_logger12.logger.warn("order warning: %s %s", symbol, err);
|
|
6301
6324
|
} else {
|
|
6302
|
-
|
|
6325
|
+
import_logger12.logger.error("order error: %s %s", symbol, err);
|
|
6303
6326
|
}
|
|
6304
6327
|
return signal ?? "ORDER_ERROR";
|
|
6305
6328
|
}
|
|
@@ -6340,7 +6363,7 @@ var createStrategyRuntime = ({
|
|
|
6340
6363
|
deploymentId: requestedDeploymentId,
|
|
6341
6364
|
policyProfileId,
|
|
6342
6365
|
runtimeConfigId,
|
|
6343
|
-
|
|
6366
|
+
strategyRevision,
|
|
6344
6367
|
entriesPaused = false,
|
|
6345
6368
|
runtimeLineage,
|
|
6346
6369
|
runtimeConfigSnapshot,
|
|
@@ -6453,7 +6476,7 @@ var createStrategyRuntime = ({
|
|
|
6453
6476
|
try {
|
|
6454
6477
|
await projectHook(errorParams);
|
|
6455
6478
|
} catch (hookError) {
|
|
6456
|
-
|
|
6479
|
+
import_logger13.logger.error(
|
|
6457
6480
|
"project hook onRuntimeError failed: %s %s",
|
|
6458
6481
|
strategyName,
|
|
6459
6482
|
hookError
|
|
@@ -6467,7 +6490,7 @@ var createStrategyRuntime = ({
|
|
|
6467
6490
|
try {
|
|
6468
6491
|
await onRuntimeError(errorParams);
|
|
6469
6492
|
} catch (hookError) {
|
|
6470
|
-
|
|
6493
|
+
import_logger13.logger.error(
|
|
6471
6494
|
"runtime hook onRuntimeError failed: %s %s",
|
|
6472
6495
|
strategyName,
|
|
6473
6496
|
hookError
|
|
@@ -6481,7 +6504,7 @@ var createStrategyRuntime = ({
|
|
|
6481
6504
|
try {
|
|
6482
6505
|
return await hook(params);
|
|
6483
6506
|
} catch (error) {
|
|
6484
|
-
|
|
6507
|
+
import_logger13.logger.error(
|
|
6485
6508
|
'strategy hook "%s" failed for %s: %s',
|
|
6486
6509
|
stage,
|
|
6487
6510
|
strategyName,
|
|
@@ -7012,8 +7035,8 @@ var createStrategyRuntime = ({
|
|
|
7012
7035
|
signal.signalId = `${signal.signalId}:${runtimeConfigId}`;
|
|
7013
7036
|
}
|
|
7014
7037
|
}
|
|
7015
|
-
if (
|
|
7016
|
-
signal.
|
|
7038
|
+
if (strategyRevision) {
|
|
7039
|
+
signal.strategyRevision = strategyRevision;
|
|
7017
7040
|
}
|
|
7018
7041
|
if (decisionHookCtx.policyProfileId) {
|
|
7019
7042
|
signal.policyProfileId = decisionHookCtx.policyProfileId;
|
|
@@ -7126,7 +7149,7 @@ var createStrategyRuntime = ({
|
|
|
7126
7149
|
if (signal) {
|
|
7127
7150
|
signal.orderStatus = "skipped";
|
|
7128
7151
|
signal.orderSkipReason = skipReason;
|
|
7129
|
-
signal.
|
|
7152
|
+
signal.strategyRevision = strategyRevision;
|
|
7130
7153
|
}
|
|
7131
7154
|
return signal ?? skipReason;
|
|
7132
7155
|
}
|
|
@@ -7238,6 +7261,7 @@ var createStrategyRuntime = ({
|
|
|
7238
7261
|
setStrategyRuntimeFactory(createStrategyRuntime);
|
|
7239
7262
|
|
|
7240
7263
|
// src/runtimeStrategies.ts
|
|
7264
|
+
var RUNTIME_PACKAGE_MANIFEST_SCHEMA = "tradejs-runtime-package-manifest/v1";
|
|
7241
7265
|
var INTERVALS = /* @__PURE__ */ new Set([
|
|
7242
7266
|
"1",
|
|
7243
7267
|
"3",
|
|
@@ -7264,7 +7288,7 @@ var DEPLOYMENT_KEYS = /* @__PURE__ */ new Set([
|
|
|
7264
7288
|
"assetClasses",
|
|
7265
7289
|
"tickers"
|
|
7266
7290
|
]);
|
|
7267
|
-
var STRATEGY_KEYS = /* @__PURE__ */ new Set(["
|
|
7291
|
+
var STRATEGY_KEYS = /* @__PURE__ */ new Set(["generation", "enabled", "selection", "config"]);
|
|
7268
7292
|
var SELECTION_KEYS = /* @__PURE__ */ new Set(["tickers"]);
|
|
7269
7293
|
var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
7270
7294
|
"ACCOUNT_ID",
|
|
@@ -7273,60 +7297,165 @@ var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
7273
7297
|
"ENABLE"
|
|
7274
7298
|
]);
|
|
7275
7299
|
var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
7276
|
-
var
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
await (0, import_promises.readFile)(candidate, "utf8")
|
|
7286
|
-
);
|
|
7287
|
-
} catch {
|
|
7288
|
-
}
|
|
7300
|
+
var normalizeForCanonicalJson = (value) => {
|
|
7301
|
+
if (Array.isArray(value)) return value.map(normalizeForCanonicalJson);
|
|
7302
|
+
if (isRecord(value)) {
|
|
7303
|
+
return Object.fromEntries(
|
|
7304
|
+
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nestedValue]) => [
|
|
7305
|
+
key,
|
|
7306
|
+
normalizeForCanonicalJson(nestedValue)
|
|
7307
|
+
])
|
|
7308
|
+
);
|
|
7289
7309
|
}
|
|
7290
|
-
return
|
|
7310
|
+
return value;
|
|
7291
7311
|
};
|
|
7292
|
-
var
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7312
|
+
var revision = (prefix, value) => `${prefix}:${(0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(normalizeForCanonicalJson(value))).digest("hex").slice(0, 16)}`;
|
|
7313
|
+
var computeStrategyRevision = ({
|
|
7314
|
+
strategyName,
|
|
7315
|
+
strategyPackage,
|
|
7316
|
+
strategyPackageVersion,
|
|
7317
|
+
strategyDependencyVersions,
|
|
7318
|
+
runtimePackageVersion,
|
|
7319
|
+
strategyConfig
|
|
7320
|
+
}) => revision("sr1", {
|
|
7321
|
+
schema: "tradejs-strategy-revision/v1",
|
|
7322
|
+
strategyName,
|
|
7323
|
+
strategyPackage,
|
|
7324
|
+
strategyPackageVersion,
|
|
7325
|
+
strategyDependencyVersions,
|
|
7326
|
+
runtimePackageVersion,
|
|
7327
|
+
strategyConfig
|
|
7328
|
+
});
|
|
7329
|
+
var computeDeploymentCompositionId = (value) => revision("dc1", {
|
|
7330
|
+
schema: "tradejs-deployment-composition/v1",
|
|
7331
|
+
...value,
|
|
7332
|
+
assetClasses: value.assetClasses ? [...value.assetClasses].sort((left, right) => left.localeCompare(right)) : void 0,
|
|
7333
|
+
strategies: [...value.strategies].sort(
|
|
7334
|
+
(left, right) => left.strategyName.localeCompare(right.strategyName)
|
|
7335
|
+
).map((strategy) => ({
|
|
7336
|
+
...strategy,
|
|
7337
|
+
selection: strategy.selection ? {
|
|
7338
|
+
tickers: [...strategy.selection.tickers].sort(
|
|
7339
|
+
(left, right) => left.localeCompare(right)
|
|
7340
|
+
)
|
|
7341
|
+
} : void 0
|
|
7342
|
+
}))
|
|
7343
|
+
});
|
|
7344
|
+
var readRuntimePackageManifest = async (projectRoot) => {
|
|
7345
|
+
const manifestPath = process.env.TRADEJS_RUNTIME_PACKAGE_MANIFEST?.trim() || import_node_path.default.join(projectRoot, "runtime-package-manifest.json");
|
|
7346
|
+
let value;
|
|
7296
7347
|
try {
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
"package.json"
|
|
7348
|
+
value = JSON.parse(await (0, import_promises.readFile)(manifestPath, "utf8"));
|
|
7349
|
+
} catch (error) {
|
|
7350
|
+
throw new Error(
|
|
7351
|
+
`Unable to read runtime package manifest ${manifestPath}: ${String(error)}`
|
|
7302
7352
|
);
|
|
7353
|
+
}
|
|
7354
|
+
if (!isRecord(value) || Object.keys(value).some(
|
|
7355
|
+
(key) => !["schema", "projectSha", "packages"].includes(key)
|
|
7356
|
+
) || value.schema !== RUNTIME_PACKAGE_MANIFEST_SCHEMA || typeof value.projectSha !== "string" || !/^[a-f0-9]{40}$/.test(value.projectSha) || !isRecord(value.packages) || Object.keys(value.packages).length === 0 || Object.entries(value.packages).some(
|
|
7357
|
+
([packageName, version]) => !packageName.trim() || typeof version !== "string" || !version.trim()
|
|
7358
|
+
)) {
|
|
7359
|
+
throw new Error(`Invalid runtime package manifest: ${manifestPath}`);
|
|
7360
|
+
}
|
|
7361
|
+
return value;
|
|
7362
|
+
};
|
|
7363
|
+
var readInstalledPackageMetadata = async ({
|
|
7364
|
+
projectRoot,
|
|
7365
|
+
packageName,
|
|
7366
|
+
projectPackage
|
|
7367
|
+
}) => {
|
|
7368
|
+
const packageJsonPath = projectPackage ? import_node_path.default.join(projectRoot, "package.json") : import_node_path.default.join(
|
|
7369
|
+
projectRoot,
|
|
7370
|
+
"node_modules",
|
|
7371
|
+
...packageName.split("/"),
|
|
7372
|
+
"package.json"
|
|
7373
|
+
);
|
|
7374
|
+
try {
|
|
7303
7375
|
const packageJson = JSON.parse(await (0, import_promises.readFile)(packageJsonPath, "utf8"));
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7376
|
+
if (packageJson.name !== void 0 && packageJson.name !== packageName || typeof packageJson.version !== "string" || !packageJson.version.trim()) {
|
|
7377
|
+
throw new Error("name or version is invalid");
|
|
7378
|
+
}
|
|
7379
|
+
const dependencyNames = [
|
|
7380
|
+
...isRecord(packageJson.dependencies) ? Object.keys(packageJson.dependencies) : [],
|
|
7381
|
+
...isRecord(packageJson.peerDependencies) ? Object.keys(packageJson.peerDependencies) : []
|
|
7382
|
+
];
|
|
7383
|
+
return {
|
|
7384
|
+
version: packageJson.version,
|
|
7385
|
+
runtimeDependencies: [...new Set(dependencyNames)].filter((name) => name.startsWith("@tradejs/")).sort((left, right) => left.localeCompare(right))
|
|
7386
|
+
};
|
|
7387
|
+
} catch (error) {
|
|
7388
|
+
throw new Error(
|
|
7389
|
+
`Installed package manifest not found for ${packageName}: ${String(error)}`
|
|
7390
|
+
);
|
|
7391
|
+
}
|
|
7392
|
+
};
|
|
7393
|
+
var resolveVerifiedPackageVersion = async ({
|
|
7394
|
+
projectRoot,
|
|
7395
|
+
packageName,
|
|
7396
|
+
manifest,
|
|
7397
|
+
projectPackage = false
|
|
7398
|
+
}) => {
|
|
7399
|
+
const declaredVersion = manifest.packages[packageName];
|
|
7400
|
+
if (!declaredVersion) {
|
|
7401
|
+
throw new Error(`Runtime package manifest is missing ${packageName}`);
|
|
7307
7402
|
}
|
|
7403
|
+
const installed = await readInstalledPackageMetadata({
|
|
7404
|
+
projectRoot,
|
|
7405
|
+
packageName,
|
|
7406
|
+
projectPackage
|
|
7407
|
+
});
|
|
7408
|
+
if (declaredVersion !== installed.version) {
|
|
7409
|
+
throw new Error(
|
|
7410
|
+
`Runtime package manifest mismatch for ${packageName}: declared=${declaredVersion} installed=${installed.version}`
|
|
7411
|
+
);
|
|
7412
|
+
}
|
|
7413
|
+
return installed.version;
|
|
7414
|
+
};
|
|
7415
|
+
var resolveVerifiedStrategyDependencyVersions = async ({
|
|
7416
|
+
projectRoot,
|
|
7417
|
+
strategyPackage,
|
|
7418
|
+
manifest
|
|
7419
|
+
}) => {
|
|
7420
|
+
const metadata = await readInstalledPackageMetadata({
|
|
7421
|
+
projectRoot,
|
|
7422
|
+
packageName: strategyPackage.name,
|
|
7423
|
+
projectPackage: strategyPackage.projectPackage
|
|
7424
|
+
});
|
|
7425
|
+
return Object.fromEntries(
|
|
7426
|
+
await Promise.all(
|
|
7427
|
+
metadata.runtimeDependencies.map(async (packageName) => [
|
|
7428
|
+
packageName,
|
|
7429
|
+
await resolveVerifiedPackageVersion({
|
|
7430
|
+
projectRoot,
|
|
7431
|
+
packageName,
|
|
7432
|
+
manifest
|
|
7433
|
+
})
|
|
7434
|
+
])
|
|
7435
|
+
)
|
|
7436
|
+
);
|
|
7308
7437
|
};
|
|
7309
|
-
var
|
|
7438
|
+
var resolveStrategyPackage = async ({
|
|
7310
7439
|
pluginSource,
|
|
7311
7440
|
projectRoot
|
|
7312
7441
|
}) => {
|
|
7313
7442
|
if (!pluginSource) return null;
|
|
7314
7443
|
if (!pluginSource.startsWith(".") && !import_node_path.default.isAbsolute(pluginSource)) {
|
|
7315
|
-
return pluginSource;
|
|
7444
|
+
return { name: pluginSource, projectPackage: false };
|
|
7316
7445
|
}
|
|
7317
7446
|
try {
|
|
7318
7447
|
const packageJson = JSON.parse(
|
|
7319
7448
|
await (0, import_promises.readFile)(import_node_path.default.join(projectRoot, "package.json"), "utf8")
|
|
7320
7449
|
);
|
|
7321
|
-
return typeof packageJson.name === "string" && packageJson.name.trim() ? packageJson.name : null;
|
|
7450
|
+
return typeof packageJson.name === "string" && packageJson.name.trim() ? { name: packageJson.name, projectPackage: true } : null;
|
|
7322
7451
|
} catch {
|
|
7323
7452
|
return null;
|
|
7324
7453
|
}
|
|
7325
7454
|
};
|
|
7326
|
-
var
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
);
|
|
7455
|
+
var verifyStringSet = (value) => value === void 0 || Array.isArray(value) && value.length > 0 && value.every(
|
|
7456
|
+
(item) => typeof item === "string" && item.length > 0 && item === item.trim()
|
|
7457
|
+
) && new Set(value).size === value.length;
|
|
7458
|
+
var verifyStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => SELECTION_KEYS.has(key)) && value.tickers !== void 0 && verifyStringSet(value.tickers);
|
|
7330
7459
|
var cloneSelection = (selection) => selection ? { tickers: [...selection.tickers] } : void 0;
|
|
7331
7460
|
var resolveStrategySelection = ({
|
|
7332
7461
|
deployment,
|
|
@@ -7335,13 +7464,13 @@ var resolveStrategySelection = ({
|
|
|
7335
7464
|
strategy.selection ?? (deployment.tickers ? { tickers: deployment.tickers } : void 0)
|
|
7336
7465
|
);
|
|
7337
7466
|
var verifyDeploymentDeclaration = (deploymentId, value) => {
|
|
7338
|
-
if (!deploymentId.trim() || !isRecord(value) || Object.keys(value).some((key) => !DEPLOYMENT_KEYS.has(key)) || typeof value.connectorName !== "string" || !value.connectorName.trim() || typeof value.accountId !== "string" || !value.accountId.trim() || value.label !== void 0 && typeof value.label !== "string" || value.provider !== void 0 && typeof value.provider !== "string" || value.enabled !== void 0 && typeof value.enabled !== "boolean" || !
|
|
7467
|
+
if (!deploymentId.trim() || !isRecord(value) || Object.keys(value).some((key) => !DEPLOYMENT_KEYS.has(key)) || typeof value.connectorName !== "string" || !value.connectorName.trim() || typeof value.accountId !== "string" || !value.accountId.trim() || value.label !== void 0 && typeof value.label !== "string" || value.provider !== void 0 && typeof value.provider !== "string" || value.enabled !== void 0 && typeof value.enabled !== "boolean" || !verifyStringSet(value.assetClasses) || !verifyStringSet(value.tickers) || !isRecord(value.strategies) || !Object.keys(value.strategies).length) {
|
|
7339
7468
|
throw new Error(`Invalid runtime deployment declaration: ${deploymentId}`);
|
|
7340
7469
|
}
|
|
7341
7470
|
for (const [strategyName, strategyValue] of Object.entries(
|
|
7342
7471
|
value.strategies
|
|
7343
7472
|
)) {
|
|
7344
|
-
if (!strategyName.trim() || !isRecord(strategyValue) || Object.keys(strategyValue).some((key) => !STRATEGY_KEYS.has(key)) ||
|
|
7473
|
+
if (!strategyName.trim() || !isRecord(strategyValue) || Object.keys(strategyValue).some((key) => !STRATEGY_KEYS.has(key)) || strategyValue.generation !== void 0 && (typeof strategyValue.generation !== "string" || !strategyValue.generation.trim()) || typeof strategyValue.enabled !== "boolean" || !verifyStrategySelection(strategyValue.selection) || !isRecord(strategyValue.config) || Object.keys(strategyValue.config).some(
|
|
7345
7474
|
(key) => FORBIDDEN_CONFIG_KEYS.has(key)
|
|
7346
7475
|
) || !INTERVALS.has(String(strategyValue.config.INTERVAL)) || !["crypto", "tradfi"].includes(String(strategyValue.config.UNIVERSE))) {
|
|
7347
7476
|
throw new Error(
|
|
@@ -7360,55 +7489,180 @@ var verifyRuntimeDeclaration = (value) => {
|
|
|
7360
7489
|
}
|
|
7361
7490
|
return value;
|
|
7362
7491
|
};
|
|
7363
|
-
var
|
|
7364
|
-
|
|
7492
|
+
var loadRuntimeDeclaration = async (projectRoot) => {
|
|
7493
|
+
const projectConfig = await loadTradejsConfig(projectRoot);
|
|
7494
|
+
if (!projectConfig.runtime) {
|
|
7495
|
+
throw new Error("Runtime declaration is required in tradejs.config.ts");
|
|
7496
|
+
}
|
|
7497
|
+
return verifyRuntimeDeclaration(projectConfig.runtime);
|
|
7498
|
+
};
|
|
7499
|
+
var resolveStrategyComposition = async ({
|
|
7500
|
+
strategyName,
|
|
7365
7501
|
declaration,
|
|
7502
|
+
deployment,
|
|
7503
|
+
projectRoot,
|
|
7504
|
+
packageManifest
|
|
7505
|
+
}) => {
|
|
7506
|
+
const [strategyEntry, strategyCreator, pluginSource] = await Promise.all([
|
|
7507
|
+
getStrategyEntry(strategyName, projectRoot),
|
|
7508
|
+
getStrategyCreator(strategyName, projectRoot),
|
|
7509
|
+
getStrategyPluginSource(strategyName, projectRoot)
|
|
7510
|
+
]);
|
|
7511
|
+
if (!strategyEntry || !strategyCreator) {
|
|
7512
|
+
throw new Error(`Unknown strategy: ${strategyName}`);
|
|
7513
|
+
}
|
|
7514
|
+
if (typeof strategyEntry.parseConfig !== "function") {
|
|
7515
|
+
throw new Error(`Strategy config parser is missing: ${strategyName}`);
|
|
7516
|
+
}
|
|
7517
|
+
const strategyPackage = await resolveStrategyPackage({
|
|
7518
|
+
pluginSource: pluginSource ?? null,
|
|
7519
|
+
projectRoot
|
|
7520
|
+
});
|
|
7521
|
+
if (!strategyPackage) {
|
|
7522
|
+
throw new Error(`Installed strategy package not found: ${strategyName}`);
|
|
7523
|
+
}
|
|
7524
|
+
const [
|
|
7525
|
+
strategyPackageVersion,
|
|
7526
|
+
strategyDependencyVersions,
|
|
7527
|
+
runtimePackageVersion
|
|
7528
|
+
] = await Promise.all([
|
|
7529
|
+
resolveVerifiedPackageVersion({
|
|
7530
|
+
projectRoot,
|
|
7531
|
+
packageName: strategyPackage.name,
|
|
7532
|
+
projectPackage: strategyPackage.projectPackage,
|
|
7533
|
+
manifest: packageManifest
|
|
7534
|
+
}),
|
|
7535
|
+
resolveVerifiedStrategyDependencyVersions({
|
|
7536
|
+
projectRoot,
|
|
7537
|
+
strategyPackage,
|
|
7538
|
+
manifest: packageManifest
|
|
7539
|
+
}),
|
|
7540
|
+
resolveVerifiedPackageVersion({
|
|
7541
|
+
projectRoot,
|
|
7542
|
+
packageName: "@tradejs/node",
|
|
7543
|
+
manifest: packageManifest
|
|
7544
|
+
})
|
|
7545
|
+
]);
|
|
7546
|
+
const parsedConfig = strategyEntry.parseConfig(declaration.config);
|
|
7547
|
+
if (!isRecord(parsedConfig)) {
|
|
7548
|
+
throw new Error(
|
|
7549
|
+
`Strategy config parser returned a non-object: ${strategyName}`
|
|
7550
|
+
);
|
|
7551
|
+
}
|
|
7552
|
+
const strategyConfig = parsedConfig;
|
|
7553
|
+
const selection = resolveStrategySelection({
|
|
7554
|
+
deployment,
|
|
7555
|
+
strategy: declaration
|
|
7556
|
+
});
|
|
7557
|
+
return {
|
|
7558
|
+
strategyName,
|
|
7559
|
+
strategyRevision: computeStrategyRevision({
|
|
7560
|
+
strategyName,
|
|
7561
|
+
strategyPackage: strategyPackage.name,
|
|
7562
|
+
strategyPackageVersion,
|
|
7563
|
+
strategyDependencyVersions,
|
|
7564
|
+
runtimePackageVersion,
|
|
7565
|
+
strategyConfig
|
|
7566
|
+
}),
|
|
7567
|
+
...declaration.generation ? { generation: declaration.generation } : {},
|
|
7568
|
+
enabled: declaration.enabled,
|
|
7569
|
+
interval: String(strategyConfig.INTERVAL),
|
|
7570
|
+
universe: strategyConfig.UNIVERSE,
|
|
7571
|
+
strategyPackage: strategyPackage.name,
|
|
7572
|
+
strategyPackageVersion,
|
|
7573
|
+
strategyDependencyVersions,
|
|
7574
|
+
runtimePackageVersion,
|
|
7575
|
+
strategyCreator,
|
|
7576
|
+
sourceStrategyConfig: declaration.config,
|
|
7577
|
+
strategyConfig,
|
|
7578
|
+
...selection ? { selection } : {}
|
|
7579
|
+
};
|
|
7580
|
+
};
|
|
7581
|
+
var resolveRuntimeComposition = async ({
|
|
7582
|
+
projectRoot
|
|
7583
|
+
}) => {
|
|
7584
|
+
const [runtime, packageManifest] = await Promise.all([
|
|
7585
|
+
loadRuntimeDeclaration(projectRoot),
|
|
7586
|
+
readRuntimePackageManifest(projectRoot)
|
|
7587
|
+
]);
|
|
7588
|
+
const deployments = await Promise.all(
|
|
7589
|
+
Object.entries(runtime.deployments).map(
|
|
7590
|
+
async ([deploymentId, declaration]) => {
|
|
7591
|
+
const strategies2 = await Promise.all(
|
|
7592
|
+
Object.entries(declaration.strategies).map(
|
|
7593
|
+
([strategyName, strategyDeclaration]) => resolveStrategyComposition({
|
|
7594
|
+
strategyName,
|
|
7595
|
+
declaration: strategyDeclaration,
|
|
7596
|
+
deployment: declaration,
|
|
7597
|
+
projectRoot,
|
|
7598
|
+
packageManifest
|
|
7599
|
+
})
|
|
7600
|
+
)
|
|
7601
|
+
);
|
|
7602
|
+
const provider = (declaration.provider || declaration.connectorName).trim().toLowerCase();
|
|
7603
|
+
return {
|
|
7604
|
+
deploymentId,
|
|
7605
|
+
deploymentCompositionId: computeDeploymentCompositionId({
|
|
7606
|
+
deploymentId,
|
|
7607
|
+
connectorName: declaration.connectorName.trim(),
|
|
7608
|
+
provider,
|
|
7609
|
+
accountId: declaration.accountId.trim(),
|
|
7610
|
+
enabled: declaration.enabled ?? true,
|
|
7611
|
+
...declaration.assetClasses ? { assetClasses: declaration.assetClasses } : {},
|
|
7612
|
+
strategies: strategies2.map((strategy) => ({
|
|
7613
|
+
strategyName: strategy.strategyName,
|
|
7614
|
+
strategyRevision: strategy.strategyRevision,
|
|
7615
|
+
enabled: strategy.enabled,
|
|
7616
|
+
...strategy.selection ? { selection: strategy.selection } : {}
|
|
7617
|
+
}))
|
|
7618
|
+
}),
|
|
7619
|
+
declaration,
|
|
7620
|
+
strategies: strategies2
|
|
7621
|
+
};
|
|
7622
|
+
}
|
|
7623
|
+
)
|
|
7624
|
+
);
|
|
7625
|
+
return {
|
|
7626
|
+
deployments: deployments.sort(
|
|
7627
|
+
(left, right) => left.deploymentId.localeCompare(right.deploymentId)
|
|
7628
|
+
)
|
|
7629
|
+
};
|
|
7630
|
+
};
|
|
7631
|
+
var toRuntimeDeployment = ({
|
|
7632
|
+
composition,
|
|
7366
7633
|
controls
|
|
7367
7634
|
}) => {
|
|
7635
|
+
const { declaration, deploymentId } = composition;
|
|
7368
7636
|
const deploymentEnabled = declaration.enabled ?? true;
|
|
7369
7637
|
return {
|
|
7370
|
-
id,
|
|
7371
|
-
|
|
7638
|
+
id: deploymentId,
|
|
7639
|
+
deploymentCompositionId: composition.deploymentCompositionId,
|
|
7640
|
+
label: declaration.label?.trim() || deploymentId,
|
|
7372
7641
|
connectorName: declaration.connectorName.trim(),
|
|
7373
7642
|
provider: (declaration.provider || declaration.connectorName).trim().toLowerCase(),
|
|
7374
7643
|
accountId: declaration.accountId.trim(),
|
|
7375
7644
|
enabled: deploymentEnabled,
|
|
7376
|
-
strategies:
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
strategyName,
|
|
7384
|
-
version: strategy.version,
|
|
7385
|
-
enabled: strategy.enabled,
|
|
7386
|
-
controlState: deploymentEnabled && strategy.enabled && !controls.deployments[id]?.[strategyName]?.entriesPaused ? "active" : "entries_paused",
|
|
7387
|
-
...selection ? { selection } : {}
|
|
7388
|
-
};
|
|
7389
|
-
}
|
|
7390
|
-
),
|
|
7645
|
+
strategies: composition.strategies.map((strategy) => ({
|
|
7646
|
+
strategyName: strategy.strategyName,
|
|
7647
|
+
strategyRevision: strategy.strategyRevision,
|
|
7648
|
+
enabled: strategy.enabled,
|
|
7649
|
+
controlState: deploymentEnabled && strategy.enabled && !controls.deployments[deploymentId]?.[strategy.strategyName]?.entriesPaused ? "active" : "entries_paused",
|
|
7650
|
+
...strategy.selection ? { selection: strategy.selection } : {}
|
|
7651
|
+
})),
|
|
7391
7652
|
...declaration.assetClasses ? { assetClasses: declaration.assetClasses } : {},
|
|
7392
7653
|
...declaration.tickers ? { tickers: declaration.tickers } : {}
|
|
7393
7654
|
};
|
|
7394
7655
|
};
|
|
7395
|
-
var loadRuntimeDeclaration = async (projectRoot) => {
|
|
7396
|
-
const projectConfig = await loadTradejsConfig(projectRoot);
|
|
7397
|
-
if (!projectConfig.runtime) {
|
|
7398
|
-
throw new Error("Runtime declaration is required in tradejs.config.ts");
|
|
7399
|
-
}
|
|
7400
|
-
return verifyRuntimeDeclaration(projectConfig.runtime);
|
|
7401
|
-
};
|
|
7402
7656
|
var listRuntimeDeployments = async ({
|
|
7403
7657
|
userName,
|
|
7404
7658
|
projectRoot
|
|
7405
7659
|
}) => {
|
|
7406
|
-
const [
|
|
7407
|
-
|
|
7660
|
+
const [composition, controls] = await Promise.all([
|
|
7661
|
+
resolveRuntimeComposition({ projectRoot }),
|
|
7408
7662
|
(0, import_runtimeControls.getRuntimeControls)(userName)
|
|
7409
7663
|
]);
|
|
7410
|
-
return
|
|
7411
|
-
(
|
|
7664
|
+
return composition.deployments.map(
|
|
7665
|
+
(deploymentComposition) => toRuntimeDeployment({ composition: deploymentComposition, controls })
|
|
7412
7666
|
).sort((left, right) => left.label.localeCompare(right.label));
|
|
7413
7667
|
};
|
|
7414
7668
|
var resolveAccountId = async ({
|
|
@@ -7435,87 +7689,37 @@ var loadResolvedRuntimeStrategies = async ({
|
|
|
7435
7689
|
accountId,
|
|
7436
7690
|
interval
|
|
7437
7691
|
}) => {
|
|
7438
|
-
const [
|
|
7439
|
-
|
|
7440
|
-
(0, import_runtimeControls.getRuntimeControls)(userName)
|
|
7441
|
-
readPackageManifest(projectRoot)
|
|
7692
|
+
const [composition, controls] = await Promise.all([
|
|
7693
|
+
resolveRuntimeComposition({ projectRoot }),
|
|
7694
|
+
(0, import_runtimeControls.getRuntimeControls)(userName)
|
|
7442
7695
|
]);
|
|
7443
|
-
const
|
|
7444
|
-
|
|
7696
|
+
const deploymentComposition = composition.deployments.find(
|
|
7697
|
+
(candidate) => candidate.deploymentId === deploymentId
|
|
7698
|
+
);
|
|
7699
|
+
if (!deploymentComposition) {
|
|
7445
7700
|
throw new Error(`Runtime deployment not found: ${deploymentId}`);
|
|
7446
7701
|
}
|
|
7447
7702
|
const deployment = toRuntimeDeployment({
|
|
7448
|
-
|
|
7449
|
-
declaration,
|
|
7703
|
+
composition: deploymentComposition,
|
|
7450
7704
|
controls
|
|
7451
7705
|
});
|
|
7452
7706
|
const strategies2 = await Promise.all(
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
projectRoot,
|
|
7470
|
-
strategyPackage,
|
|
7471
|
-
packageManifest
|
|
7472
|
-
),
|
|
7473
|
-
resolveInstalledPackageVersion(
|
|
7474
|
-
projectRoot,
|
|
7475
|
-
"@tradejs/node",
|
|
7476
|
-
packageManifest
|
|
7477
|
-
)
|
|
7478
|
-
]);
|
|
7479
|
-
if (!strategyPackage || !strategyPackageVersion) {
|
|
7480
|
-
throw new Error(
|
|
7481
|
-
`Installed strategy package not found: ${strategyName}`
|
|
7482
|
-
);
|
|
7483
|
-
}
|
|
7484
|
-
if (!runtimePackageVersion) {
|
|
7485
|
-
throw new Error("Installed @tradejs/node package version not found");
|
|
7486
|
-
}
|
|
7487
|
-
const strategyView = deployment.strategies.find(
|
|
7488
|
-
(candidate) => candidate.strategyName === strategyName
|
|
7489
|
-
);
|
|
7490
|
-
const selection = resolveStrategySelection({
|
|
7491
|
-
deployment: declaration,
|
|
7492
|
-
strategy: strategyDeclaration
|
|
7493
|
-
});
|
|
7494
|
-
const strategyConfig = strategyDeclaration.config;
|
|
7495
|
-
const strategyUniverse = strategyConfig.UNIVERSE;
|
|
7496
|
-
const resolvedAccountId = await resolveAccountId({
|
|
7497
|
-
userName,
|
|
7498
|
-
deployment,
|
|
7499
|
-
universe: strategyUniverse
|
|
7500
|
-
});
|
|
7501
|
-
return {
|
|
7502
|
-
strategyName,
|
|
7503
|
-
version: strategyDeclaration.version,
|
|
7504
|
-
enabled: strategyDeclaration.enabled,
|
|
7505
|
-
controlState: strategyView?.controlState ?? "entries_paused",
|
|
7506
|
-
interval: String(strategyConfig.INTERVAL),
|
|
7507
|
-
universe: strategyUniverse,
|
|
7508
|
-
accountId: resolvedAccountId,
|
|
7509
|
-
strategyPackage,
|
|
7510
|
-
strategyPackageVersion,
|
|
7511
|
-
runtimePackageVersion,
|
|
7512
|
-
strategyCreator,
|
|
7513
|
-
sourceStrategyConfig: strategyConfig,
|
|
7514
|
-
strategyConfig,
|
|
7515
|
-
...selection ? { selection } : {}
|
|
7516
|
-
};
|
|
7517
|
-
}
|
|
7518
|
-
)
|
|
7707
|
+
deploymentComposition.strategies.map(async (strategy) => {
|
|
7708
|
+
const strategyView = deployment.strategies.find(
|
|
7709
|
+
(candidate) => candidate.strategyName === strategy.strategyName
|
|
7710
|
+
);
|
|
7711
|
+
const resolvedAccountId = await resolveAccountId({
|
|
7712
|
+
userName,
|
|
7713
|
+
deployment,
|
|
7714
|
+
universe: strategy.universe
|
|
7715
|
+
});
|
|
7716
|
+
return {
|
|
7717
|
+
...strategy,
|
|
7718
|
+
deploymentCompositionId: deploymentComposition.deploymentCompositionId,
|
|
7719
|
+
accountId: resolvedAccountId,
|
|
7720
|
+
controlState: strategyView?.controlState ?? "entries_paused"
|
|
7721
|
+
};
|
|
7722
|
+
})
|
|
7519
7723
|
);
|
|
7520
7724
|
const filtered = strategies2.filter(
|
|
7521
7725
|
(candidate) => (!universe || candidate.universe === universe) && (!interval || String(candidate.interval) === String(interval)) && (!accountId || candidate.accountId === accountId)
|
|
@@ -7615,7 +7819,7 @@ var loadExchangeRange = async ({
|
|
|
7615
7819
|
} catch (error) {
|
|
7616
7820
|
const message = error?.message || String(error);
|
|
7617
7821
|
errors?.push(`${label}: ${message}`);
|
|
7618
|
-
|
|
7822
|
+
import_logger14.logger.warn("strategies runtime: %s failed: %s", label, message);
|
|
7619
7823
|
return [];
|
|
7620
7824
|
}
|
|
7621
7825
|
};
|
|
@@ -7655,7 +7859,7 @@ var loadClosedPnlRows = async ({
|
|
|
7655
7859
|
} catch (error) {
|
|
7656
7860
|
const message = error?.message || String(error);
|
|
7657
7861
|
errors?.push(`getClosedPnl: ${message}`);
|
|
7658
|
-
|
|
7862
|
+
import_logger14.logger.warn("strategies runtime: getClosedPnl failed: %s", message);
|
|
7659
7863
|
return [];
|
|
7660
7864
|
}
|
|
7661
7865
|
};
|
|
@@ -7688,7 +7892,7 @@ var loadExchangeEntryRows = async ({
|
|
|
7688
7892
|
} catch (error) {
|
|
7689
7893
|
const message = error?.message || String(error);
|
|
7690
7894
|
errors?.push(`getEntryExecutions: ${message}`);
|
|
7691
|
-
|
|
7895
|
+
import_logger14.logger.warn("strategies runtime: getEntryExecutions failed: %s", message);
|
|
7692
7896
|
return [];
|
|
7693
7897
|
}
|
|
7694
7898
|
};
|
|
@@ -7704,7 +7908,7 @@ var loadOpenPositions = async (connector, errors) => {
|
|
|
7704
7908
|
} catch (error) {
|
|
7705
7909
|
const message = error?.message || String(error);
|
|
7706
7910
|
errors?.push(`getOpenPositionPnl: ${message}`);
|
|
7707
|
-
|
|
7911
|
+
import_logger14.logger.warn("strategies runtime: getOpenPositionPnl failed: %s", message);
|
|
7708
7912
|
return { positions: [], reliable: false };
|
|
7709
7913
|
}
|
|
7710
7914
|
};
|
|
@@ -7822,7 +8026,7 @@ var loadRuntimeDashboard = async ({
|
|
|
7822
8026
|
);
|
|
7823
8027
|
const runtimeIdentityKey = (trade) => (0, import_runtimeTrades3.buildRuntimeStrategyIdentityKey)({
|
|
7824
8028
|
strategyName: trade.strategy,
|
|
7825
|
-
configId: trade.
|
|
8029
|
+
configId: trade.strategyRevision,
|
|
7826
8030
|
universe: trade.universe,
|
|
7827
8031
|
accountId: trade.accountId,
|
|
7828
8032
|
deploymentId: trade.deploymentId,
|
|
@@ -7835,7 +8039,7 @@ var loadRuntimeDashboard = async ({
|
|
|
7835
8039
|
) ?? []) {
|
|
7836
8040
|
const strategyUniverse = resolvedStrategy.universe;
|
|
7837
8041
|
const strategyInterval = resolvedStrategy.interval;
|
|
7838
|
-
const strategyConfigId =
|
|
8042
|
+
const strategyConfigId = resolvedStrategy.strategyRevision;
|
|
7839
8043
|
const strategyPolicyProfileId = typeof resolvedStrategy.strategyConfig.POLICY_PROFILE_ID === "string" ? resolvedStrategy.strategyConfig.POLICY_PROFILE_ID : void 0;
|
|
7840
8044
|
const runtimeKey = (0, import_runtimeTrades3.buildRuntimeStrategyIdentityKey)({
|
|
7841
8045
|
strategyName: resolvedStrategy.strategyName,
|
|
@@ -7848,7 +8052,7 @@ var loadRuntimeDashboard = async ({
|
|
|
7848
8052
|
identityByKey.set(runtimeKey, {
|
|
7849
8053
|
strategyName: resolvedStrategy.strategyName,
|
|
7850
8054
|
configId: strategyConfigId,
|
|
7851
|
-
|
|
8055
|
+
strategyRevision: resolvedStrategy.strategyRevision,
|
|
7852
8056
|
controlState: resolvedStrategy.controlState,
|
|
7853
8057
|
interval: strategyInterval,
|
|
7854
8058
|
universe: strategyUniverse,
|
|
@@ -7868,8 +8072,8 @@ var loadRuntimeDashboard = async ({
|
|
|
7868
8072
|
const key = runtimeIdentityKey(trade);
|
|
7869
8073
|
const configuredIdentity = identityByKey.get(key);
|
|
7870
8074
|
if (!configuredIdentity) continue;
|
|
7871
|
-
const
|
|
7872
|
-
if (
|
|
8075
|
+
const strategyRevision = trade.strategyRevision ?? (trade.runtimeLineage?.schemaVersion === 3 ? trade.runtimeLineage.strategyRevision : void 0);
|
|
8076
|
+
if (strategyRevision !== configuredIdentity.strategyRevision) continue;
|
|
7873
8077
|
identityByKey.set(key, {
|
|
7874
8078
|
...configuredIdentity,
|
|
7875
8079
|
interval: String(
|
|
@@ -7896,7 +8100,7 @@ var loadRuntimeDashboard = async ({
|
|
|
7896
8100
|
runtimeKey,
|
|
7897
8101
|
strategyName,
|
|
7898
8102
|
configId: identity.configId,
|
|
7899
|
-
|
|
8103
|
+
strategyRevision: identity.strategyRevision,
|
|
7900
8104
|
controlState: identity.controlState,
|
|
7901
8105
|
interval: identity.interval,
|
|
7902
8106
|
universe: identity.universe,
|