@tradejs/cli 2.0.8 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -107,6 +107,15 @@ var loadRuntimeTrades = async (userName, {
107
107
  const trades = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
108
108
  return trades.filter(isRuntimeTradeRecord).filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
109
109
  };
110
+ var loadRuntimeActiveTradeOrderIds = async (userName) => {
111
+ const keys = await (0, import_redis.getKeys)(import_redis.redisKeys.runtimeActiveTrades(userName));
112
+ const refs = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
113
+ return new Set(
114
+ refs.map(
115
+ (ref) => ref && typeof ref === "object" && "orderId" in ref && typeof ref.orderId === "string" && ref.orderId.trim() ? ref.orderId.trim() : null
116
+ ).filter((orderId) => orderId != null)
117
+ );
118
+ };
110
119
 
111
120
  // src/lib/runtimeTradeSync.ts
112
121
  var import_constants = require("@tradejs/core/constants");
@@ -636,7 +645,8 @@ var buildRuntimeDebugReportPayload = async ({
636
645
  );
637
646
  const activeTradeKey = import_redis4.redisKeys.runtimeActiveTrade(
638
647
  userName,
639
- trade.symbol
648
+ trade.symbol,
649
+ trade.deploymentId ?? trade.accountId
640
650
  );
641
651
  const signalKey = trade.signalId != null ? import_redis4.redisKeys.storeSignal(trade.symbol, trade.signalId) : null;
642
652
  const evaluationBucketKey = import_redis4.redisKeys.runtimeSignalEvaluationBucket(
@@ -771,6 +781,7 @@ var buildRuntimeDebugReportAttachment = async (params) => {
771
781
  };
772
782
 
773
783
  // src/scripts/signalsSummary.ts
784
+ var import_tradingAccounts = require("@tradejs/infra/tradingAccounts");
774
785
  import_args.default.option(["u", "user"], "Use user config", "root");
775
786
  import_args.default.option(
776
787
  "connector",
@@ -883,6 +894,108 @@ var resolveSummaryConnectorName = async (value) => {
883
894
  );
884
895
  return import_connectors.DEFAULT_CONNECTOR_NAME;
885
896
  };
897
+ var groupRuntimeTradesByConnectorScope = ({
898
+ trades,
899
+ deployments,
900
+ fallbackConnectorName
901
+ }) => {
902
+ const deploymentById = new Map(
903
+ deployments.map((deployment) => [deployment.id, deployment])
904
+ );
905
+ const scopes = /* @__PURE__ */ new Map();
906
+ for (const trade of trades) {
907
+ const deployment = trade.deploymentId ? deploymentById.get(trade.deploymentId) : void 0;
908
+ const connectorName = deployment?.connectorName ?? fallbackConnectorName;
909
+ const universe = trade.universe ?? deployment?.universe ?? "crypto";
910
+ const accountId = trade.accountId ?? deployment?.accountId;
911
+ const deploymentId = trade.deploymentId;
912
+ const scopeKey = JSON.stringify([
913
+ connectorName,
914
+ universe,
915
+ accountId ?? null,
916
+ deploymentId ?? null
917
+ ]);
918
+ const scope = scopes.get(scopeKey) ?? {
919
+ connectorName,
920
+ universe,
921
+ ...accountId ? { accountId } : {},
922
+ ...deploymentId ? { deploymentId } : {},
923
+ trades: []
924
+ };
925
+ scope.trades.push(trade);
926
+ scopes.set(scopeKey, scope);
927
+ }
928
+ return [...scopes.values()];
929
+ };
930
+ var syncRuntimeTradeScopes = async ({
931
+ userName,
932
+ startTime,
933
+ endTime,
934
+ fallbackConnectorName,
935
+ trades,
936
+ deployments
937
+ }) => {
938
+ const scopes = groupRuntimeTradesByConnectorScope({
939
+ trades,
940
+ deployments,
941
+ fallbackConnectorName
942
+ });
943
+ const syncedTrades = [];
944
+ const connectorNames = /* @__PURE__ */ new Set();
945
+ for (const scope of scopes) {
946
+ const connectorName = await resolveSummaryConnectorName(
947
+ scope.connectorName
948
+ );
949
+ const connectorFactory = await (0, import_connectors.getConnectorCreatorByName)(
950
+ connectorName,
951
+ projectRoot
952
+ );
953
+ if (!connectorFactory) {
954
+ throw new Error(`Connector "${connectorName}" is not registered`);
955
+ }
956
+ const connector = await connectorFactory({
957
+ userName,
958
+ universe: scope.universe,
959
+ accountId: scope.accountId,
960
+ deploymentId: scope.deploymentId
961
+ });
962
+ connectorNames.add(connectorName);
963
+ syncedTrades.push(
964
+ ...await syncRuntimeTrades({
965
+ userName,
966
+ connector,
967
+ trades: scope.trades,
968
+ startTime,
969
+ endTime,
970
+ openPositionCallbacks: {
971
+ onError: (error) => {
972
+ import_logger.logger.warn(
973
+ "signals summary: getOpenPositionPnl failed for scope account=%s deployment=%s: %s",
974
+ scope.accountId ?? "default",
975
+ scope.deploymentId ?? "default",
976
+ formatRuntimeTradeSyncError(error)
977
+ );
978
+ }
979
+ },
980
+ closedPnlCallbacks: {
981
+ onError: (error) => {
982
+ import_logger.logger.warn(
983
+ "signals summary: getClosedPnl failed for scope account=%s deployment=%s: %s",
984
+ scope.accountId ?? "default",
985
+ scope.deploymentId ?? "default",
986
+ formatRuntimeTradeSyncError(error)
987
+ );
988
+ }
989
+ }
990
+ })
991
+ );
992
+ }
993
+ return {
994
+ trades: syncedTrades,
995
+ connectorNames: [...connectorNames].sort(),
996
+ scopesCount: scopes.length
997
+ };
998
+ };
886
999
  var createRuntimeSignalStats = () => ({
887
1000
  evaluated: 0,
888
1001
  signals: 0,
@@ -1192,46 +1305,35 @@ var signalsSummary = async () => {
1192
1305
  );
1193
1306
  const endTime = Date.now();
1194
1307
  const startTime = endTime - hours * 60 * 60 * 1e3;
1195
- const connectorName = await resolveSummaryConnectorName(flags.connector);
1196
- const connectorFactory = await (0, import_connectors.getConnectorCreatorByName)(
1197
- connectorName,
1198
- projectRoot
1308
+ const fallbackConnectorName = await resolveSummaryConnectorName(
1309
+ flags.connector
1199
1310
  );
1200
- if (!connectorFactory) {
1201
- throw new Error(`Connector "${connectorName}" is not registered`);
1202
- }
1203
- const connector = await connectorFactory({
1204
- userName: flags.user
1205
- });
1206
- const [configuredStrategyNames, signals, evaluationStatsBuckets, trades] = await Promise.all([
1311
+ const [
1312
+ configuredStrategyNames,
1313
+ signals,
1314
+ evaluationStatsBuckets,
1315
+ trades,
1316
+ runtimeDeployments
1317
+ ] = await Promise.all([
1207
1318
  loadRuntimeStrategyNames(flags.user),
1208
1319
  loadRuntimeSignals(flags.user, { startTime, endTime }),
1209
1320
  loadRuntimeSignalEvaluationStatsBuckets(flags.user),
1210
- loadRuntimeTrades(flags.user)
1321
+ loadRuntimeTrades(flags.user),
1322
+ (0, import_tradingAccounts.listRuntimeDeployments)(flags.user)
1211
1323
  ]);
1212
- const syncedTrades = await syncRuntimeTrades({
1324
+ const {
1325
+ trades: syncedTrades,
1326
+ connectorNames,
1327
+ scopesCount
1328
+ } = await syncRuntimeTradeScopes({
1213
1329
  userName: flags.user,
1214
- connector,
1215
- trades,
1216
1330
  startTime,
1217
1331
  endTime,
1218
- openPositionCallbacks: {
1219
- onError: (error) => {
1220
- import_logger.logger.warn(
1221
- "signals summary: getOpenPositionPnl failed: %s",
1222
- formatRuntimeTradeSyncError(error)
1223
- );
1224
- }
1225
- },
1226
- closedPnlCallbacks: {
1227
- onError: (error) => {
1228
- import_logger.logger.warn(
1229
- "signals summary: getClosedPnl failed: %s",
1230
- formatRuntimeTradeSyncError(error)
1231
- );
1232
- }
1233
- }
1332
+ fallbackConnectorName,
1333
+ trades,
1334
+ deployments: runtimeDeployments
1234
1335
  });
1336
+ const activeTradeOrderIds = await loadRuntimeActiveTradeOrderIds(flags.user);
1235
1337
  const windowSignals = signals.filter(
1236
1338
  (signal) => signal.timestamp >= startTime && signal.timestamp < endTime
1237
1339
  );
@@ -1249,7 +1351,7 @@ var signalsSummary = async () => {
1249
1351
  (trade) => isRuntimeTradeClosedInWindow(trade, startTime, endTime)
1250
1352
  );
1251
1353
  const openSnapshotTrades = syncedTrades.filter(
1252
- (trade) => trade.status === "active" && typeof trade.entryTimestamp === "number" && Number.isFinite(trade.entryTimestamp) && trade.entryTimestamp < endTime
1354
+ (trade) => trade.status === "active" && activeTradeOrderIds.has(trade.orderId) && typeof trade.entryTimestamp === "number" && Number.isFinite(trade.entryTimestamp) && trade.entryTimestamp < endTime
1253
1355
  );
1254
1356
  const windowTrades = [...windowClosedTrades, ...openSnapshotTrades];
1255
1357
  const windowTradeSignalIds = new Set(
@@ -1272,12 +1374,13 @@ var signalsSummary = async () => {
1272
1374
  0
1273
1375
  );
1274
1376
  import_logger.logger.info(
1275
- "signals summary window=%sh signals=%s evaluations=%s trades=%s connector=%s user=%s",
1377
+ "signals summary window=%sh signals=%s evaluations=%s trades=%s connectors=%s scopes=%s user=%s",
1276
1378
  hours,
1277
1379
  windowSignals.length,
1278
1380
  windowEvaluationsCount,
1279
1381
  windowClosedTrades.length,
1280
- connectorName,
1382
+ connectorNames.join(",") || fallbackConnectorName,
1383
+ scopesCount,
1281
1384
  flags.user
1282
1385
  );
1283
1386
  const debugAttachment = shouldAttachDebugReport(flags.debugAttachment) ? await buildRuntimeDebugReportAttachment({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/cli",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
5
5
  "keywords": [
6
6
  "tradejs",
@@ -29,14 +29,14 @@
29
29
  "tradejs": "dist/cli.js"
30
30
  },
31
31
  "dependencies": {
32
- "@tradejs/base": "^2.0.8",
33
- "@tradejs/connectors": "^2.0.8",
34
- "@tradejs/core": "^2.0.8",
35
- "@tradejs/indicators": "^2.0.8",
36
- "@tradejs/infra": "^2.0.8",
37
- "@tradejs/node": "^2.0.8",
38
- "@tradejs/strategies": "^2.0.8",
39
- "@tradejs/types": "^2.0.8",
32
+ "@tradejs/base": "^2.0.10",
33
+ "@tradejs/connectors": "^2.0.10",
34
+ "@tradejs/core": "^2.0.10",
35
+ "@tradejs/indicators": "^2.0.10",
36
+ "@tradejs/infra": "^2.0.10",
37
+ "@tradejs/node": "^2.0.10",
38
+ "@tradejs/strategies": "^2.0.10",
39
+ "@tradejs/types": "^2.0.10",
40
40
  "args": "^5.0.3",
41
41
  "bcryptjs": "^2.4.3",
42
42
  "chalk": "4.1.2",