@tradejs/node 2.0.5 → 2.0.7

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.
@@ -1,9 +1,14 @@
1
1
  import {
2
+ BINANCE_BREADTH_UNIVERSE_KEYS,
3
+ buildBinanceBreadthUniverseSnapshot,
2
4
  buildMlPayload,
3
5
  enrichSignalWithBinanceMarketContext,
4
6
  enrichSignalWithCoinMarketCapContext,
5
- enrichSignalWithDerivativesContext
6
- } from "./chunk-2DZCHRP6.mjs";
7
+ enrichSignalWithDerivativesContext,
8
+ getBinanceBreadthUniverseSnapshot,
9
+ getBinanceBreadthUniverses,
10
+ getPrimaryBinanceBreadthUniverse
11
+ } from "./chunk-76TEMQKX.mjs";
7
12
  import {
8
13
  require_lodash
9
14
  } from "./chunk-GPR56UYQ.mjs";
@@ -24,7 +29,7 @@ import {
24
29
  runAiPrompt,
25
30
  runAiPromptLocal,
26
31
  trimSeriesDeep
27
- } from "./chunk-IUZML4RK.mjs";
32
+ } from "./chunk-PD25CABK.mjs";
28
33
  import {
29
34
  createPineScriptLoader
30
35
  } from "./chunk-IQKMII6L.mjs";
@@ -243,7 +248,7 @@ var getActiveRuntimeTrade = async (params) => {
243
248
  redisKeys.runtimeTrade(userName, orderId),
244
249
  null
245
250
  );
246
- if (!existing) {
251
+ if (!existing || existing.status !== "active") {
247
252
  await delKey(
248
253
  redisKeys.runtimeActiveTrade(userName, symbol, deploymentId ?? accountId)
249
254
  );
@@ -463,7 +468,7 @@ var enrichSignalWithMlAi = async ({
463
468
  return enrichSignalWithAi({ signal, userName, symbol, direction, env, ai });
464
469
  };
465
470
  var toFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
466
- var getArrivalSnapshot = async ({
471
+ var getOrderArrivalSnapshot = async ({
467
472
  connector,
468
473
  symbol
469
474
  }) => {
@@ -508,6 +513,29 @@ var getArrivalSnapshot = async ({
508
513
  };
509
514
  }
510
515
  };
516
+ var validateEntryProtectionAtArrival = ({
517
+ direction,
518
+ signalPrice,
519
+ bid,
520
+ ask,
521
+ arrivalMid,
522
+ takeProfits,
523
+ stopLossPrice
524
+ }) => {
525
+ const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
526
+ const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
527
+ if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
528
+ throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
529
+ }
530
+ for (const takeProfit of takeProfits) {
531
+ if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
532
+ throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
533
+ }
534
+ }
535
+ if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
536
+ throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
537
+ }
538
+ };
511
539
  var resolveRuntimeTelemetryQuality = ({
512
540
  signalClosePrice,
513
541
  arrivalMid,
@@ -582,7 +610,22 @@ var executeEntryOrder = async ({
582
610
  signal.orderQty = qty;
583
611
  signal.orderValue = qty * currentPrice;
584
612
  signal.orderFailureReason = void 0;
585
- const arrivalSnapshot = await getArrivalSnapshot({ connector, symbol });
613
+ const arrivalSnapshot = await getOrderArrivalSnapshot({ connector, symbol });
614
+ try {
615
+ validateEntryProtectionAtArrival({
616
+ direction,
617
+ signalPrice: currentPrice,
618
+ bid: arrivalSnapshot.bid,
619
+ ask: arrivalSnapshot.ask,
620
+ arrivalMid: arrivalSnapshot.arrivalMid,
621
+ takeProfits,
622
+ stopLossPrice
623
+ });
624
+ } catch (error) {
625
+ signal.orderStatus = "failed";
626
+ signal.orderFailureReason = error.message;
627
+ throw error;
628
+ }
586
629
  const orderSubmitTime = Date.now();
587
630
  const orderPlaced = await connector.placeOrder({
588
631
  symbol,
@@ -771,6 +814,9 @@ var resolveStrategyConfig = async ({
771
814
  };
772
815
 
773
816
  // src/strategyRuntime.ts
817
+ import {
818
+ BACKTEST_WARNING_CODES
819
+ } from "@tradejs/types";
774
820
  var buildExitOrderSignal = ({
775
821
  strategyName,
776
822
  symbol,
@@ -1479,6 +1525,19 @@ var executeEntryDecision = async ({
1479
1525
  return signal;
1480
1526
  }
1481
1527
  await beforePlaceOrder();
1528
+ const arrivalSnapshot = await getOrderArrivalSnapshot({
1529
+ connector,
1530
+ symbol
1531
+ });
1532
+ validateEntryProtectionAtArrival({
1533
+ direction: decision.entryContext.direction,
1534
+ signalPrice: decision.entryContext.prices.currentPrice,
1535
+ bid: arrivalSnapshot.bid,
1536
+ ask: arrivalSnapshot.ask,
1537
+ arrivalMid: arrivalSnapshot.arrivalMid,
1538
+ takeProfits: decision.orderPlan.takeProfits,
1539
+ stopLossPrice: decision.orderPlan.stopLossPrice
1540
+ });
1482
1541
  const orderPlaced = await connector.placeOrder({
1483
1542
  symbol,
1484
1543
  qty: decision.orderPlan.qty,
@@ -1540,7 +1599,11 @@ var executeEntryDecision = async ({
1540
1599
  entry,
1541
1600
  market
1542
1601
  });
1543
- logger3.error("order error: %s %s", symbol, err);
1602
+ if (err?.message === BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
1603
+ logger3.warn("order warning: %s %s", symbol, err);
1604
+ } else {
1605
+ logger3.error("order error: %s %s", symbol, err);
1606
+ }
1544
1607
  return signal ?? "ORDER_ERROR";
1545
1608
  }
1546
1609
  return signal ?? decision.code;
@@ -2804,6 +2867,7 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
2804
2867
  };
2805
2868
  };
2806
2869
  export {
2870
+ BINANCE_BREADTH_UNIVERSE_KEYS,
2807
2871
  DEFAULT_AI_MODEL,
2808
2872
  MAX_AI_SERIES_POINTS,
2809
2873
  askAI,
@@ -2811,6 +2875,7 @@ export {
2811
2875
  buildAiPayload,
2812
2876
  buildAiPrompts,
2813
2877
  buildAiSystemPrompt,
2878
+ buildBinanceBreadthUniverseSnapshot,
2814
2879
  buildCompactAiIndicatorsSnapshot,
2815
2880
  closeOppositePositionsBeforeOpen,
2816
2881
  createCloseAllOnGlobalProfitBeforeSignalsHook,
@@ -2828,8 +2893,12 @@ export {
2828
2893
  ensureStrategyPluginsLoaded,
2829
2894
  executeEntryOrder,
2830
2895
  getAvailableStrategyNames,
2896
+ getBinanceBreadthUniverseSnapshot,
2897
+ getBinanceBreadthUniverses,
2831
2898
  getDeterministicAiGateContext,
2832
2899
  getOpenRouterModelKwargs,
2900
+ getOrderArrivalSnapshot,
2901
+ getPrimaryBinanceBreadthUniverse,
2833
2902
  getRegisteredManifests,
2834
2903
  getRegisteredStrategies,
2835
2904
  getStrategyCreator,
@@ -2842,5 +2911,6 @@ export {
2842
2911
  runAiPrompt,
2843
2912
  runAiPromptLocal,
2844
2913
  strategies,
2845
- trimSeriesDeep
2914
+ trimSeriesDeep,
2915
+ validateEntryProtectionAtArrival
2846
2916
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/node",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
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",
@@ -65,23 +65,23 @@
65
65
  }
66
66
  },
67
67
  "dependencies": {
68
- "@langchain/core": "^1.1.42",
69
- "@langchain/openai": "^1.4.5",
70
- "@tradejs/core": "^2.0.5",
71
- "@tradejs/infra": "^2.0.5",
72
- "@tradejs/types": "^2.0.5",
68
+ "@langchain/core": "^1.2.3",
69
+ "@langchain/openai": "^1.5.5",
70
+ "@tradejs/core": "^2.0.7",
71
+ "@tradejs/infra": "^2.0.7",
72
+ "@tradejs/types": "^2.0.7",
73
73
  "chalk": "4.1.2",
74
- "ioredis": "5.8.0",
74
+ "ioredis": "5.11.1",
75
75
  "pinets": "0.8.12",
76
76
  "progress": "^2.0.3",
77
- "puppeteer": "24.15.0",
77
+ "puppeteer": "24.43.1",
78
78
  "ts-node": "^10.9.2",
79
79
  "tsconfig-paths": "^4.2.0"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@types/node": "^24",
83
83
  "tsup": "^8.5.1",
84
- "typescript": "^5.1"
84
+ "typescript": "^5.9"
85
85
  },
86
86
  "scripts": {
87
87
  "build": "tsup",