@tradejs/node 3.1.29-beta.291 → 3.1.29-beta.292

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.
@@ -931,39 +931,72 @@ function createPortfolioCoordinator({
931
931
  );
932
932
  if (admitted.result) return { reason: admitted.result };
933
933
  let submitted = false;
934
+ let retry = 0;
935
+ let attemptId = entry.id;
936
+ let needsReservation = false;
934
937
  try {
935
938
  const value = await send(
936
939
  async (qty) => {
937
940
  if (!Number.isFinite(qty) || qty <= 0)
938
941
  throw new Error("Invalid submitted portfolio quantity");
939
- submitted = true;
940
- const update = await updateReservation(now2, entry.id, true, qty);
942
+ if (needsReservation) {
943
+ attemptId = `${entry.id.slice(0, 30)}r${++retry}`;
944
+ const admission = await transact(
945
+ now2,
946
+ (s, o) => {
947
+ const r = (0, import_portfolio.reservePortfolioEntry)(policy, strategy, s, o, {
948
+ ...entry,
949
+ id: attemptId,
950
+ qty,
951
+ submitted: true,
952
+ oppositeHandled: false
953
+ });
954
+ return { state: r.state, result: r.reason };
955
+ },
956
+ true
957
+ );
958
+ if (admission.result) throw new Error(admission.result);
959
+ needsReservation = false;
960
+ submitted = true;
961
+ return attemptId;
962
+ }
963
+ const update = await updateReservation(now2, attemptId, true, qty);
941
964
  if (!update.result)
942
965
  throw new Error("PORTFOLIO_SUBMISSION_NO_LONGER_ADMITTED");
966
+ submitted = true;
967
+ return attemptId;
943
968
  },
944
- async () => {
969
+ async (retrying = false) => {
945
970
  await transact(
946
971
  now2,
947
972
  (s) => ({
948
973
  state: {
949
974
  ...s,
950
- reservations: s.reservations.filter((r) => r.id !== entry.id),
975
+ reservations: s.reservations.filter(
976
+ (r) => r.id !== attemptId
977
+ ),
951
978
  completedSignals: {
952
- ...s.completedSignals,
953
- [entry.signalId]: now2
979
+ ...Object.fromEntries(
980
+ Object.entries(s.completedSignals).filter(
981
+ ([id]) => !retrying || id !== entry.signalId
982
+ )
983
+ ),
984
+ ...retrying ? {} : { [entry.signalId]: now2 }
954
985
  }
955
986
  },
956
987
  result: void 0
957
988
  }),
958
989
  true
959
990
  );
991
+ submitted = false;
992
+ needsReservation = retrying;
960
993
  }
961
994
  );
962
- if (!submitted) await updateReservation(now2, entry.id, false);
995
+ if (!submitted) await updateReservation(now2, attemptId, false);
963
996
  else await tick(now2, true);
964
997
  return { value };
965
998
  } catch (error) {
966
- if (!submitted) await updateReservation(now2, entry.id, false);
999
+ if (!submitted) await updateReservation(now2, attemptId, false);
967
1000
  throw error;
968
1001
  }
969
1002
  }
@@ -1331,7 +1364,9 @@ function getPortfolioRuntime({
1331
1364
  env,
1332
1365
  userName,
1333
1366
  accountId,
1334
- deploymentId
1367
+ deploymentId,
1368
+ symbol,
1369
+ canClose
1335
1370
  }) {
1336
1371
  const policy = (0, import_portfolio2.parsePortfolioPolicy)(value);
1337
1372
  if (!policy) return void 0;
@@ -1362,8 +1397,13 @@ function getPortfolioRuntime({
1362
1397
  if (existing) {
1363
1398
  if (existing.fingerprint !== fingerprint3)
1364
1399
  throw new Error("Conflicting portfolio configuration for the same scope");
1400
+ if (symbol && canClose)
1401
+ existing.permissions.set(JSON.stringify([strategy, symbol]), canClose);
1365
1402
  return existing.coordinator;
1366
1403
  }
1404
+ const permissions = /* @__PURE__ */ new Map();
1405
+ if (symbol && canClose)
1406
+ permissions.set(JSON.stringify([strategy, symbol]), canClose);
1367
1407
  const coordinator = createPortfolioCoordinator({
1368
1408
  policy,
1369
1409
  strategy,
@@ -1384,6 +1424,10 @@ function getPortfolioRuntime({
1384
1424
  },
1385
1425
  observe: (asOf, reservations) => replay ? connector.getPortfolioObservation(asOf, reservations) : observeRuntimePortfolio(connector, binding, asOf, reservations),
1386
1426
  async close(position, intent, asOf) {
1427
+ const permission = permissions.get(
1428
+ JSON.stringify([position.strategy, position.symbol])
1429
+ );
1430
+ if (!permission || !await permission(position, intent, asOf)) return;
1387
1431
  if (!replay) {
1388
1432
  const trade = await getActiveRuntimeTrade({
1389
1433
  ...binding,
@@ -1418,7 +1462,7 @@ function getPortfolioRuntime({
1418
1462
  }
1419
1463
  }
1420
1464
  });
1421
- registry.set(cacheKey, { fingerprint: fingerprint3, coordinator });
1465
+ registry.set(cacheKey, { fingerprint: fingerprint3, coordinator, permissions });
1422
1466
  return coordinator;
1423
1467
  }
1424
1468
 
@@ -6253,7 +6297,7 @@ var executeEntryOrder = async ({
6253
6297
  }) => {
6254
6298
  await beforePlaceOrder?.();
6255
6299
  const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
6256
- const orderId = signal.orderId || createRuntimeOrderId(signal.strategy);
6300
+ let orderId = signal.orderId || createRuntimeOrderId(signal.strategy);
6257
6301
  const signalTimestamp = signal.timestamp;
6258
6302
  const signalClosePrice = currentPrice;
6259
6303
  signal.orderId = orderId;
@@ -6326,11 +6370,12 @@ var executeEntryOrder = async ({
6326
6370
  ...beforeSubmit || markPortfolioSubmitted ? {
6327
6371
  beforeSubmit: async (context) => {
6328
6372
  await beforeSubmit?.(context);
6329
- await markPortfolioSubmitted?.(context.qty);
6373
+ return markPortfolioSubmitted?.(context.qty);
6330
6374
  }
6331
6375
  } : {}
6332
6376
  });
6333
6377
  const orderAckTime = Date.now();
6378
+ if (markPortfolioSubmitted && signal.orderId) orderId = signal.orderId;
6334
6379
  const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
6335
6380
  const currentPosition = await connector.getPosition(symbol);
6336
6381
  const fillTime = Date.now();
@@ -7618,7 +7663,27 @@ var createStrategyRuntime = ({
7618
7663
  const projectConfig = await loadTradejsConfig(projectRoot);
7619
7664
  const projectHooks = projectConfig.hooks;
7620
7665
  const env = String(config.ENV ?? "BACKTEST");
7666
+ let portfolioMarket;
7621
7667
  const portfolio = getPortfolioRuntime({
7668
+ symbol,
7669
+ canClose: async (position, intent, asOf) => {
7670
+ if (!portfolioMarket || portfolioMarket.candle.timestamp > asOf || !isRuntimeOrderExecutionEnabled({ config, env, connector }))
7671
+ return false;
7672
+ const gate = await authorizeClose(
7673
+ {
7674
+ kind: "exit",
7675
+ code: intent.reason,
7676
+ closePlan: {
7677
+ direction: position.direction,
7678
+ price: position.markPrice,
7679
+ timestamp: asOf
7680
+ }
7681
+ },
7682
+ portfolioMarket,
7683
+ position.strategy
7684
+ );
7685
+ return gate?.allow !== false;
7686
+ },
7622
7687
  connectorName,
7623
7688
  value: baseConfig?.PORTFOLIO_POLICY ?? config.PORTFOLIO_POLICY,
7624
7689
  strategy: strategyName,
@@ -7793,7 +7858,10 @@ var createStrategyRuntime = ({
7793
7858
  return invokeHook(stage, hook, params, errorContext);
7794
7859
  };
7795
7860
  const invokeGateHooks = async (stage, hook, params, errorContext = {}) => {
7796
- const failureResult = stage === "beforeEntryGate" ? { allow: false, reason: "ERROR" } : void 0;
7861
+ const failureResult = {
7862
+ allow: false,
7863
+ reason: "ERROR"
7864
+ };
7797
7865
  const projectResults = await invokeProjectHooks(
7798
7866
  stage,
7799
7867
  params,
@@ -7814,6 +7882,12 @@ var createStrategyRuntime = ({
7814
7882
  failureResult
7815
7883
  );
7816
7884
  };
7885
+ const authorizeClose = (decision, market, owner = strategyName) => invokeGateHooks(
7886
+ "beforeClosePosition",
7887
+ resolveManifest(owner)?.hooks?.beforeClosePosition,
7888
+ { ctx: getHookCtx(owner), market, decision },
7889
+ { decision, market }
7890
+ );
7817
7891
  const applyProjectAfterCoreDecisionHooks = async ({
7818
7892
  hookCtx,
7819
7893
  market,
@@ -8127,6 +8201,7 @@ var createStrategyRuntime = ({
8127
8201
  });
8128
8202
  };
8129
8203
  const runWithDecisionOverride = async (candle, btcCandle, options = {}) => {
8204
+ portfolioMarket = { candle, btcCandle };
8130
8205
  if (portfolioContext)
8131
8206
  await portfolioContext(
8132
8207
  env === "BACKTEST" || env === "PARITY" ? candle.timestamp : Date.now()
@@ -8233,15 +8308,10 @@ var createStrategyRuntime = ({
8233
8308
  if (!makeOrdersEnabled) {
8234
8309
  return decision.code;
8235
8310
  }
8236
- const closeGate = await invokeGateHooks(
8237
- "beforeClosePosition",
8238
- decisionManifest?.hooks?.beforeClosePosition,
8239
- {
8240
- ctx: decisionHookCtx,
8241
- market,
8242
- decision
8243
- },
8244
- { decision, market }
8311
+ const closeGate = await authorizeClose(
8312
+ decision,
8313
+ market,
8314
+ decisionHookCtx.strategyName
8245
8315
  );
8246
8316
  if (closeGate?.allow === false) {
8247
8317
  return closeGate.reason ? `CLOSE_BLOCKED_BY_HOOK:${closeGate.reason}` : "CLOSE_BLOCKED_BY_HOOK";
@@ -9,8 +9,8 @@ import {
9
9
  resolveRuntimeComposition,
10
10
  verifyRuntimeDeclaration
11
11
  } from "./chunk-W6PPAADK.mjs";
12
- import "./chunk-HRON2EAI.mjs";
13
- import "./chunk-UUNEWAT4.mjs";
12
+ import "./chunk-EVKQ4DI6.mjs";
13
+ import "./chunk-NJEYNGRU.mjs";
14
14
  import "./chunk-PYJWXAYR.mjs";
15
15
  import "./chunk-LZDXRXIU.mjs";
16
16
  import "./chunk-YR55Q355.mjs";
@@ -86,8 +86,8 @@ interface ExecuteEntryOrderParams {
86
86
  beforePlaceOrder?: () => Promise<void>;
87
87
  recordRuntimeTrade?: boolean;
88
88
  executionLimits?: EntryExecutionLimits;
89
- markPortfolioSubmitted?: (qty: number) => Promise<void>;
90
- rejectPortfolioSubmission?: () => Promise<void>;
89
+ markPortfolioSubmitted?: (qty: number) => Promise<string>;
90
+ rejectPortfolioSubmission?: (retrying?: boolean) => Promise<void>;
91
91
  }
92
92
  declare const executeEntryOrder: ({ connector, userName, symbol, direction, qty, currentPrice, timestamp, takeProfits, stopLossPrice, positionIntent, signal, beforePlaceOrder, recordRuntimeTrade, leverage, executionLimits, markPortfolioSubmitted, rejectPortfolioSubmission, }: ExecuteEntryOrderParams) => Promise<number>;
93
93
 
@@ -86,8 +86,8 @@ interface ExecuteEntryOrderParams {
86
86
  beforePlaceOrder?: () => Promise<void>;
87
87
  recordRuntimeTrade?: boolean;
88
88
  executionLimits?: EntryExecutionLimits;
89
- markPortfolioSubmitted?: (qty: number) => Promise<void>;
90
- rejectPortfolioSubmission?: () => Promise<void>;
89
+ markPortfolioSubmitted?: (qty: number) => Promise<string>;
90
+ rejectPortfolioSubmission?: (retrying?: boolean) => Promise<void>;
91
91
  }
92
92
  declare const executeEntryOrder: ({ connector, userName, symbol, direction, qty, currentPrice, timestamp, takeProfits, stopLossPrice, positionIntent, signal, beforePlaceOrder, recordRuntimeTrade, leverage, executionLimits, markPortfolioSubmitted, rejectPortfolioSubmission, }: ExecuteEntryOrderParams) => Promise<number>;
93
93
 
@@ -2853,39 +2853,72 @@ function createPortfolioCoordinator({
2853
2853
  );
2854
2854
  if (admitted.result) return { reason: admitted.result };
2855
2855
  let submitted = false;
2856
+ let retry = 0;
2857
+ let attemptId = entry.id;
2858
+ let needsReservation = false;
2856
2859
  try {
2857
2860
  const value = await send(
2858
2861
  async (qty) => {
2859
2862
  if (!Number.isFinite(qty) || qty <= 0)
2860
2863
  throw new Error("Invalid submitted portfolio quantity");
2861
- submitted = true;
2862
- const update = await updateReservation(now2, entry.id, true, qty);
2864
+ if (needsReservation) {
2865
+ attemptId = `${entry.id.slice(0, 30)}r${++retry}`;
2866
+ const admission = await transact(
2867
+ now2,
2868
+ (s, o) => {
2869
+ const r = (0, import_portfolio.reservePortfolioEntry)(policy, strategy, s, o, {
2870
+ ...entry,
2871
+ id: attemptId,
2872
+ qty,
2873
+ submitted: true,
2874
+ oppositeHandled: false
2875
+ });
2876
+ return { state: r.state, result: r.reason };
2877
+ },
2878
+ true
2879
+ );
2880
+ if (admission.result) throw new Error(admission.result);
2881
+ needsReservation = false;
2882
+ submitted = true;
2883
+ return attemptId;
2884
+ }
2885
+ const update = await updateReservation(now2, attemptId, true, qty);
2863
2886
  if (!update.result)
2864
2887
  throw new Error("PORTFOLIO_SUBMISSION_NO_LONGER_ADMITTED");
2888
+ submitted = true;
2889
+ return attemptId;
2865
2890
  },
2866
- async () => {
2891
+ async (retrying = false) => {
2867
2892
  await transact(
2868
2893
  now2,
2869
2894
  (s) => ({
2870
2895
  state: {
2871
2896
  ...s,
2872
- reservations: s.reservations.filter((r) => r.id !== entry.id),
2897
+ reservations: s.reservations.filter(
2898
+ (r) => r.id !== attemptId
2899
+ ),
2873
2900
  completedSignals: {
2874
- ...s.completedSignals,
2875
- [entry.signalId]: now2
2901
+ ...Object.fromEntries(
2902
+ Object.entries(s.completedSignals).filter(
2903
+ ([id]) => !retrying || id !== entry.signalId
2904
+ )
2905
+ ),
2906
+ ...retrying ? {} : { [entry.signalId]: now2 }
2876
2907
  }
2877
2908
  },
2878
2909
  result: void 0
2879
2910
  }),
2880
2911
  true
2881
2912
  );
2913
+ submitted = false;
2914
+ needsReservation = retrying;
2882
2915
  }
2883
2916
  );
2884
- if (!submitted) await updateReservation(now2, entry.id, false);
2917
+ if (!submitted) await updateReservation(now2, attemptId, false);
2885
2918
  else await tick(now2, true);
2886
2919
  return { value };
2887
2920
  } catch (error) {
2888
- if (!submitted) await updateReservation(now2, entry.id, false);
2921
+ if (!submitted) await updateReservation(now2, attemptId, false);
2889
2922
  throw error;
2890
2923
  }
2891
2924
  }
@@ -3253,7 +3286,9 @@ function getPortfolioRuntime({
3253
3286
  env,
3254
3287
  userName,
3255
3288
  accountId,
3256
- deploymentId
3289
+ deploymentId,
3290
+ symbol,
3291
+ canClose
3257
3292
  }) {
3258
3293
  const policy = (0, import_portfolio2.parsePortfolioPolicy)(value);
3259
3294
  if (!policy) return void 0;
@@ -3284,8 +3319,13 @@ function getPortfolioRuntime({
3284
3319
  if (existing) {
3285
3320
  if (existing.fingerprint !== fingerprint3)
3286
3321
  throw new Error("Conflicting portfolio configuration for the same scope");
3322
+ if (symbol && canClose)
3323
+ existing.permissions.set(JSON.stringify([strategy, symbol]), canClose);
3287
3324
  return existing.coordinator;
3288
3325
  }
3326
+ const permissions = /* @__PURE__ */ new Map();
3327
+ if (symbol && canClose)
3328
+ permissions.set(JSON.stringify([strategy, symbol]), canClose);
3289
3329
  const coordinator = createPortfolioCoordinator({
3290
3330
  policy,
3291
3331
  strategy,
@@ -3306,6 +3346,10 @@ function getPortfolioRuntime({
3306
3346
  },
3307
3347
  observe: (asOf, reservations) => replay ? connector.getPortfolioObservation(asOf, reservations) : observeRuntimePortfolio(connector, binding, asOf, reservations),
3308
3348
  async close(position, intent, asOf) {
3349
+ const permission = permissions.get(
3350
+ JSON.stringify([position.strategy, position.symbol])
3351
+ );
3352
+ if (!permission || !await permission(position, intent, asOf)) return;
3309
3353
  if (!replay) {
3310
3354
  const trade = await getActiveRuntimeTrade({
3311
3355
  ...binding,
@@ -3340,7 +3384,7 @@ function getPortfolioRuntime({
3340
3384
  }
3341
3385
  }
3342
3386
  });
3343
- registry.set(cacheKey, { fingerprint: fingerprint3, coordinator });
3387
+ registry.set(cacheKey, { fingerprint: fingerprint3, coordinator, permissions });
3344
3388
  return coordinator;
3345
3389
  }
3346
3390
 
@@ -6515,7 +6559,7 @@ var executeEntryOrder = async ({
6515
6559
  }) => {
6516
6560
  await beforePlaceOrder?.();
6517
6561
  const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
6518
- const orderId = signal.orderId || createRuntimeOrderId(signal.strategy);
6562
+ let orderId = signal.orderId || createRuntimeOrderId(signal.strategy);
6519
6563
  const signalTimestamp = signal.timestamp;
6520
6564
  const signalClosePrice = currentPrice;
6521
6565
  signal.orderId = orderId;
@@ -6588,11 +6632,12 @@ var executeEntryOrder = async ({
6588
6632
  ...beforeSubmit || markPortfolioSubmitted ? {
6589
6633
  beforeSubmit: async (context) => {
6590
6634
  await beforeSubmit?.(context);
6591
- await markPortfolioSubmitted?.(context.qty);
6635
+ return markPortfolioSubmitted?.(context.qty);
6592
6636
  }
6593
6637
  } : {}
6594
6638
  });
6595
6639
  const orderAckTime = Date.now();
6640
+ if (markPortfolioSubmitted && signal.orderId) orderId = signal.orderId;
6596
6641
  const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
6597
6642
  const currentPosition = await connector.getPosition(symbol);
6598
6643
  const fillTime = Date.now();
@@ -7880,7 +7925,27 @@ var createStrategyRuntime = ({
7880
7925
  const projectConfig = await loadTradejsConfig(projectRoot);
7881
7926
  const projectHooks = projectConfig.hooks;
7882
7927
  const env = String(config.ENV ?? "BACKTEST");
7928
+ let portfolioMarket;
7883
7929
  const portfolio = getPortfolioRuntime({
7930
+ symbol,
7931
+ canClose: async (position, intent, asOf) => {
7932
+ if (!portfolioMarket || portfolioMarket.candle.timestamp > asOf || !isRuntimeOrderExecutionEnabled({ config, env, connector }))
7933
+ return false;
7934
+ const gate = await authorizeClose(
7935
+ {
7936
+ kind: "exit",
7937
+ code: intent.reason,
7938
+ closePlan: {
7939
+ direction: position.direction,
7940
+ price: position.markPrice,
7941
+ timestamp: asOf
7942
+ }
7943
+ },
7944
+ portfolioMarket,
7945
+ position.strategy
7946
+ );
7947
+ return gate?.allow !== false;
7948
+ },
7884
7949
  connectorName,
7885
7950
  value: baseConfig?.PORTFOLIO_POLICY ?? config.PORTFOLIO_POLICY,
7886
7951
  strategy: strategyName,
@@ -8055,7 +8120,10 @@ var createStrategyRuntime = ({
8055
8120
  return invokeHook(stage, hook, params, errorContext);
8056
8121
  };
8057
8122
  const invokeGateHooks = async (stage, hook, params, errorContext = {}) => {
8058
- const failureResult = stage === "beforeEntryGate" ? { allow: false, reason: "ERROR" } : void 0;
8123
+ const failureResult = {
8124
+ allow: false,
8125
+ reason: "ERROR"
8126
+ };
8059
8127
  const projectResults = await invokeProjectHooks(
8060
8128
  stage,
8061
8129
  params,
@@ -8076,6 +8144,12 @@ var createStrategyRuntime = ({
8076
8144
  failureResult
8077
8145
  );
8078
8146
  };
8147
+ const authorizeClose = (decision, market, owner = strategyName) => invokeGateHooks(
8148
+ "beforeClosePosition",
8149
+ resolveManifest(owner)?.hooks?.beforeClosePosition,
8150
+ { ctx: getHookCtx(owner), market, decision },
8151
+ { decision, market }
8152
+ );
8079
8153
  const applyProjectAfterCoreDecisionHooks = async ({
8080
8154
  hookCtx,
8081
8155
  market,
@@ -8389,6 +8463,7 @@ var createStrategyRuntime = ({
8389
8463
  });
8390
8464
  };
8391
8465
  const runWithDecisionOverride = async (candle, btcCandle, options = {}) => {
8466
+ portfolioMarket = { candle, btcCandle };
8392
8467
  if (portfolioContext)
8393
8468
  await portfolioContext(
8394
8469
  env === "BACKTEST" || env === "PARITY" ? candle.timestamp : Date.now()
@@ -8495,15 +8570,10 @@ var createStrategyRuntime = ({
8495
8570
  if (!makeOrdersEnabled) {
8496
8571
  return decision.code;
8497
8572
  }
8498
- const closeGate = await invokeGateHooks(
8499
- "beforeClosePosition",
8500
- decisionManifest?.hooks?.beforeClosePosition,
8501
- {
8502
- ctx: decisionHookCtx,
8503
- market,
8504
- decision
8505
- },
8506
- { decision, market }
8573
+ const closeGate = await authorizeClose(
8574
+ decision,
8575
+ market,
8576
+ decisionHookCtx.strategyName
8507
8577
  );
8508
8578
  if (closeGate?.allow === false) {
8509
8579
  return closeGate.reason ? `CLOSE_BLOCKED_BY_HOOK:${closeGate.reason}` : "CLOSE_BLOCKED_BY_HOOK";
@@ -23,8 +23,8 @@ import {
23
23
  resolveHyperliquidPerpFromSignalSymbol,
24
24
  resolveStrategyConfig,
25
25
  validateEntryProtectionAtArrival
26
- } from "./chunk-HRON2EAI.mjs";
27
- import "./chunk-UUNEWAT4.mjs";
26
+ } from "./chunk-EVKQ4DI6.mjs";
27
+ import "./chunk-NJEYNGRU.mjs";
28
28
  import {
29
29
  DEFAULT_AI_MODEL,
30
30
  MAX_AI_SERIES_POINTS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/node",
3
- "version": "3.1.29-beta.291",
3
+ "version": "3.1.29-beta.292",
4
4
  "description": "Node-only runtime for the TradeJS TypeScript framework: strategies, backtests, Pine strategy loading, and plugin registries.",
5
5
  "keywords": [
6
6
  "tradejs",
@@ -110,9 +110,9 @@
110
110
  "dependencies": {
111
111
  "@langchain/core": "^1.2.3",
112
112
  "@langchain/openai": "^1.5.5",
113
- "@tradejs/core": "^3.1.29-beta.291",
114
- "@tradejs/infra": "^3.1.29-beta.291",
115
- "@tradejs/types": "^3.1.29-beta.291",
113
+ "@tradejs/core": "^3.1.29-beta.292",
114
+ "@tradejs/infra": "^3.1.29-beta.292",
115
+ "@tradejs/types": "^3.1.29-beta.292",
116
116
  "@types/node": "^24",
117
117
  "chalk": "4.1.2",
118
118
  "ioredis": "5.11.1",
@@ -125,7 +125,7 @@
125
125
  "typescript": "^5.9"
126
126
  },
127
127
  "devDependencies": {
128
- "@tradejs/indicators": "^3.1.29-beta.291",
128
+ "@tradejs/indicators": "^3.1.29-beta.292",
129
129
  "@tradejs/strategy-adaptive-momentum-ribbon": "3.0.5",
130
130
  "@tradejs/strategy-hyperliquid-consensus": "3.0.5",
131
131
  "@tradejs/strategy-kit": "3.0.6",