@tradejs/node 1.0.4 → 1.0.6

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,21 +1,29 @@
1
1
  import {
2
2
  buildMlPayload
3
- } from "./chunk-RBE4PZER.mjs";
3
+ } from "./chunk-PQH5PAFC.mjs";
4
4
  import {
5
5
  require_lodash
6
6
  } from "./chunk-GKDBAF3A.mjs";
7
7
  import {
8
- createLoadPineScript
9
- } from "./chunk-7ICOZAKA.mjs";
10
- import "./chunk-5YNMSWL3.mjs";
11
- import {
8
+ DEFAULT_AI_MODEL,
12
9
  MAX_AI_SERIES_POINTS,
13
10
  askAI,
14
11
  buildAiHumanPrompt,
15
12
  buildAiPayload,
13
+ buildAiPrompts,
16
14
  buildAiSystemPrompt,
15
+ ensureAiStrategyPluginsLoaded,
16
+ getDeterministicAiGateContext,
17
+ getOpenRouterModelKwargs,
18
+ resetAiRuntimeCache,
19
+ runAiPrompt,
20
+ runAiPromptLocal,
17
21
  trimSeriesDeep
18
- } from "./chunk-LMAKIC3C.mjs";
22
+ } from "./chunk-72FKXJ2I.mjs";
23
+ import {
24
+ createPineScriptLoader
25
+ } from "./chunk-H6LIYHU4.mjs";
26
+ import "./chunk-5YNMSWL3.mjs";
19
27
  import {
20
28
  ensureIndicatorPluginsLoaded,
21
29
  ensureStrategyPluginsLoaded,
@@ -28,10 +36,10 @@ import {
28
36
  registerStrategyEntries,
29
37
  resetStrategyRegistryCache,
30
38
  strategies
31
- } from "./chunk-ZY6ULOWK.mjs";
39
+ } from "./chunk-EOZSJKUM.mjs";
32
40
  import {
33
41
  getTradejsProjectCwd
34
- } from "./chunk-P2ZUWONT.mjs";
42
+ } from "./chunk-CGJ2UU6H.mjs";
35
43
  import {
36
44
  __toESM
37
45
  } from "./chunk-6DZX6EAA.mjs";
@@ -198,6 +206,7 @@ var enrichSignalWithMl = async ({
198
206
  var enrichSignalWithAi = async ({
199
207
  signal,
200
208
  symbol,
209
+ userName,
201
210
  direction,
202
211
  env,
203
212
  ai
@@ -206,8 +215,8 @@ var enrichSignalWithAi = async ({
206
215
  return void 0;
207
216
  }
208
217
  try {
209
- const { askAI: askAI2 } = await import("./ai-G7ATN4YL.mjs");
210
- const analysis = await askAI2(signal);
218
+ const { askAI: askAI2 } = await import("./ai.mjs");
219
+ const analysis = await askAI2(signal, { userName });
211
220
  if (typeof analysis?.quality === "number") {
212
221
  const normalizedQuality = Math.round(analysis.quality);
213
222
  const aiApprovedCurrentTrade = analysis?.direction === direction;
@@ -220,6 +229,7 @@ var enrichSignalWithAi = async ({
220
229
  };
221
230
  var enrichSignalWithMlAi = async ({
222
231
  signal,
232
+ userName,
223
233
  symbol,
224
234
  direction,
225
235
  env,
@@ -227,7 +237,37 @@ var enrichSignalWithMlAi = async ({
227
237
  ai
228
238
  }) => {
229
239
  await enrichSignalWithMl({ signal, env, ml });
230
- return enrichSignalWithAi({ signal, symbol, direction, env, ai });
240
+ return enrichSignalWithAi({ signal, userName, symbol, direction, env, ai });
241
+ };
242
+ var applyProtectiveOrders = async ({
243
+ connector,
244
+ symbol,
245
+ direction,
246
+ qty,
247
+ takeProfits,
248
+ stopLossPrice
249
+ }) => {
250
+ if (Array.isArray(takeProfits) && takeProfits.length > 0) {
251
+ const tpOk = await connector.setTakeProfits({
252
+ symbol,
253
+ direction,
254
+ qty,
255
+ takeProfits
256
+ });
257
+ if (!tpOk) {
258
+ throw new Error("SET_TAKE_PROFITS_FAILED");
259
+ }
260
+ }
261
+ if (typeof stopLossPrice === "number" && Number.isFinite(stopLossPrice)) {
262
+ const slOk = await connector.setStopLoss({
263
+ symbol,
264
+ direction,
265
+ stopLossPrice
266
+ });
267
+ if (!slOk) {
268
+ throw new Error("SET_STOP_LOSS_FAILED");
269
+ }
270
+ }
231
271
  };
232
272
  var executeEntryOrder = async ({
233
273
  connector,
@@ -242,19 +282,35 @@ var executeEntryOrder = async ({
242
282
  beforePlaceOrder
243
283
  }) => {
244
284
  await beforePlaceOrder?.();
245
- const orderPlaced = await connector.placeOrder(
246
- {
247
- symbol,
248
- qty,
249
- price: currentPrice,
250
- isLimit: false,
251
- timestamp,
252
- direction,
253
- signal
254
- },
255
- takeProfits,
256
- stopLossPrice
257
- );
285
+ const orderPlaced = await connector.placeOrder({
286
+ symbol,
287
+ qty,
288
+ price: currentPrice,
289
+ isLimit: false,
290
+ timestamp,
291
+ direction,
292
+ signal
293
+ });
294
+ if (orderPlaced) {
295
+ try {
296
+ await applyProtectiveOrders({
297
+ connector,
298
+ symbol,
299
+ direction,
300
+ qty,
301
+ takeProfits,
302
+ stopLossPrice
303
+ });
304
+ } catch (error) {
305
+ await connector.closePosition({
306
+ symbol,
307
+ price: currentPrice,
308
+ timestamp,
309
+ direction
310
+ });
311
+ throw error;
312
+ }
313
+ }
258
314
  signal.orderStatus = orderPlaced ? "completed" : "failed";
259
315
  signal.orderSkipReason = void 0;
260
316
  const currentPosition = await connector.getPosition(symbol);
@@ -264,6 +320,23 @@ var executeEntryOrder = async ({
264
320
  }
265
321
  return currentPrice;
266
322
  };
323
+ var updatePositionProtection = async ({
324
+ connector,
325
+ symbol,
326
+ direction,
327
+ qty,
328
+ takeProfits,
329
+ stopLossPrice
330
+ }) => {
331
+ await applyProtectiveOrders({
332
+ connector,
333
+ symbol,
334
+ direction,
335
+ qty,
336
+ takeProfits: takeProfits ?? [],
337
+ stopLossPrice: stopLossPrice ?? null
338
+ });
339
+ };
267
340
 
268
341
  // src/strategyHelpers/config.ts
269
342
  var import_lodash2 = __toESM(require_lodash());
@@ -336,19 +409,32 @@ var shouldExecuteEntryDecision = ({
336
409
  makeOrdersEnabled,
337
410
  env,
338
411
  signal,
412
+ aiEnabled,
339
413
  quality,
340
414
  minAiQuality
341
- }) => makeOrdersEnabled && (!signal || env === "BACKTEST" || quality == null || quality >= minAiQuality);
415
+ }) => {
416
+ if (!makeOrdersEnabled) {
417
+ return false;
418
+ }
419
+ if (!signal || env === "BACKTEST" || !aiEnabled) {
420
+ return true;
421
+ }
422
+ return Number.isFinite(quality) && quality >= minAiQuality;
423
+ };
342
424
  var getEntrySkipReason = ({
343
425
  makeOrdersEnabled,
344
426
  env,
427
+ aiEnabled,
345
428
  quality,
346
429
  minAiQuality
347
430
  }) => {
348
431
  if (!makeOrdersEnabled) {
349
432
  return "MAKE_ORDERS_DISABLED";
350
433
  }
351
- if (env !== "BACKTEST" && quality != null && Number.isFinite(quality) && quality < minAiQuality) {
434
+ if (env !== "BACKTEST" && aiEnabled && quality == null) {
435
+ return "AI_QUALITY_UNAVAILABLE";
436
+ }
437
+ if (env !== "BACKTEST" && aiEnabled && quality != null && Number.isFinite(quality) && quality < minAiQuality) {
352
438
  return `AI_QUALITY_BELOW_MIN (${quality} < ${minAiQuality})`;
353
439
  }
354
440
  return "ENTRY_POLICY_BLOCKED";
@@ -519,6 +605,33 @@ var handleExitDecision = async ({
519
605
  }
520
606
  return decision.code;
521
607
  };
608
+ var handleProtectDecision = async ({
609
+ connector,
610
+ symbol,
611
+ decision,
612
+ market,
613
+ onRuntimeError
614
+ }) => {
615
+ try {
616
+ await updatePositionProtection({
617
+ connector,
618
+ symbol,
619
+ direction: decision.protectPlan.direction,
620
+ takeProfits: decision.protectPlan.takeProfits ?? [],
621
+ stopLossPrice: decision.protectPlan.stopLossPrice ?? null
622
+ });
623
+ } catch (err) {
624
+ await onRuntimeError?.({
625
+ stage: "protectPosition",
626
+ error: err,
627
+ decision,
628
+ market
629
+ });
630
+ logger3.error("protect position error: %s %s", symbol, err);
631
+ return "ORDER_ERROR";
632
+ }
633
+ return decision.code;
634
+ };
522
635
  var executeEntryDecision = async ({
523
636
  connector,
524
637
  symbol,
@@ -597,17 +710,34 @@ var executeEntryDecision = async ({
597
710
  return signal;
598
711
  }
599
712
  await beforePlaceOrder();
600
- await connector.placeOrder(
601
- {
713
+ const orderPlaced = await connector.placeOrder({
714
+ symbol,
715
+ qty: decision.orderPlan.qty,
716
+ price: decision.entryContext.prices.currentPrice,
717
+ timestamp: decision.entryContext.timestamp,
718
+ direction: decision.entryContext.direction
719
+ });
720
+ if (!orderPlaced) {
721
+ throw new Error("PLACE_ORDER_FAILED");
722
+ }
723
+ try {
724
+ await updatePositionProtection({
725
+ connector,
602
726
  symbol,
727
+ direction: decision.entryContext.direction,
603
728
  qty: decision.orderPlan.qty,
729
+ takeProfits: decision.orderPlan.takeProfits,
730
+ stopLossPrice: decision.orderPlan.stopLossPrice
731
+ });
732
+ } catch (error) {
733
+ await connector.closePosition({
734
+ symbol,
604
735
  price: decision.entryContext.prices.currentPrice,
605
736
  timestamp: decision.entryContext.timestamp,
606
737
  direction: decision.entryContext.direction
607
- },
608
- decision.orderPlan.takeProfits,
609
- decision.orderPlan.stopLossPrice
610
- );
738
+ });
739
+ throw error;
740
+ }
611
741
  await invokeHook(
612
742
  "afterPlaceOrder",
613
743
  manifest?.hooks?.afterPlaceOrder,
@@ -658,7 +788,7 @@ var createStrategyRuntime = ({
658
788
  }
659
789
  return getStrategyManifest(name, projectRoot);
660
790
  };
661
- const loadPineScript = createLoadPineScript(
791
+ const loadPineScriptFile = createPineScriptLoader(
662
792
  strategyDirectory ? path.resolve(strategyDirectory) : path.resolve(
663
793
  projectRoot,
664
794
  "packages",
@@ -783,7 +913,7 @@ var createStrategyRuntime = ({
783
913
  connector,
784
914
  data,
785
915
  btcData,
786
- loadPineScript,
916
+ loadPineScriptFile,
787
917
  strategyApi,
788
918
  indicatorsState
789
919
  });
@@ -867,6 +997,30 @@ var createStrategyRuntime = ({
867
997
  }
868
998
  });
869
999
  }
1000
+ if (decision.kind === "protect") {
1001
+ if (!makeOrdersEnabled) {
1002
+ return decision.code;
1003
+ }
1004
+ return handleProtectDecision({
1005
+ connector,
1006
+ symbol,
1007
+ decision,
1008
+ market,
1009
+ onRuntimeError: async ({
1010
+ stage,
1011
+ error,
1012
+ decision: protectDecision,
1013
+ market: errorMarket
1014
+ }) => {
1015
+ await notifyRuntimeError({
1016
+ stage,
1017
+ error,
1018
+ decision: protectDecision,
1019
+ market: errorMarket
1020
+ });
1021
+ }
1022
+ });
1023
+ }
870
1024
  const runtime = resolveEntryRuntimePolicy({
871
1025
  decision,
872
1026
  config,
@@ -919,6 +1073,7 @@ var createStrategyRuntime = ({
919
1073
  try {
920
1074
  quality = await enrichSignalWithAi({
921
1075
  signal,
1076
+ userName,
922
1077
  symbol,
923
1078
  direction: signal.direction,
924
1079
  env,
@@ -954,6 +1109,7 @@ var createStrategyRuntime = ({
954
1109
  );
955
1110
  }
956
1111
  const minAiQuality = runtime.ai?.minQuality ?? 4;
1112
+ const aiEnabled = runtime.ai?.enabled !== false && runtime.ai != null;
957
1113
  const policy = buildHookPolicy({
958
1114
  quality,
959
1115
  makeOrdersEnabled,
@@ -963,6 +1119,7 @@ var createStrategyRuntime = ({
963
1119
  makeOrdersEnabled,
964
1120
  env,
965
1121
  signal,
1122
+ aiEnabled,
966
1123
  quality,
967
1124
  minAiQuality
968
1125
  });
@@ -972,6 +1129,7 @@ var createStrategyRuntime = ({
972
1129
  signal.orderSkipReason = getEntrySkipReason({
973
1130
  makeOrdersEnabled,
974
1131
  env,
1132
+ aiEnabled,
975
1133
  quality,
976
1134
  minAiQuality
977
1135
  });
@@ -1034,10 +1192,12 @@ var createCloseOppositeBeforePlaceOrderHook = ({
1034
1192
  };
1035
1193
  };
1036
1194
  export {
1195
+ DEFAULT_AI_MODEL,
1037
1196
  MAX_AI_SERIES_POINTS,
1038
1197
  askAI,
1039
1198
  buildAiHumanPrompt,
1040
1199
  buildAiPayload,
1200
+ buildAiPrompts,
1041
1201
  buildAiSystemPrompt,
1042
1202
  closeOppositePositionsBeforeOpen,
1043
1203
  createCloseOppositeBeforePlaceOrderHook,
@@ -1045,18 +1205,24 @@ export {
1045
1205
  enrichSignalWithAi,
1046
1206
  enrichSignalWithMl,
1047
1207
  enrichSignalWithMlAi,
1208
+ ensureAiStrategyPluginsLoaded,
1048
1209
  ensureIndicatorPluginsLoaded,
1049
1210
  ensureStrategyPluginsLoaded,
1050
1211
  executeEntryOrder,
1051
1212
  getAvailableStrategyNames,
1213
+ getDeterministicAiGateContext,
1214
+ getOpenRouterModelKwargs,
1052
1215
  getRegisteredManifests,
1053
1216
  getRegisteredStrategies,
1054
1217
  getStrategyCreator,
1055
1218
  getStrategyManifest,
1056
1219
  isKnownStrategy,
1057
1220
  registerStrategyEntries,
1221
+ resetAiRuntimeCache,
1058
1222
  resetStrategyRegistryCache,
1059
1223
  resolveStrategyConfig,
1224
+ runAiPrompt,
1225
+ runAiPromptLocal,
1060
1226
  strategies,
1061
1227
  trimSeriesDeep
1062
1228
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tradejs/node",
3
- "version": "1.0.4",
4
- "description": "Node-only TradeJS runtime for strategies, backtests, Pine loading, and plugin registries.",
3
+ "version": "1.0.6",
4
+ "description": "Node-only runtime for the TradeJS open-source framework: strategies, backtests, Pine loading, and plugin registries.",
5
5
  "keywords": [
6
6
  "tradejs",
7
7
  "trading",
@@ -11,10 +11,23 @@
11
11
  "strategy",
12
12
  "pine-script"
13
13
  ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/tradejs-dev/tradejs.git",
17
+ "directory": "packages/node"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/tradejs-dev/tradejs/issues"
21
+ },
14
22
  "files": [
15
23
  "dist"
16
24
  ],
17
25
  "exports": {
26
+ "./ai": {
27
+ "types": "./dist/ai.d.ts",
28
+ "import": "./dist/ai.mjs",
29
+ "require": "./dist/ai.js"
30
+ },
18
31
  "./backtest": {
19
32
  "types": "./dist/backtest.d.ts",
20
33
  "import": "./dist/backtest.mjs",
@@ -54,9 +67,9 @@
54
67
  "dependencies": {
55
68
  "@langchain/core": "^0.3.68",
56
69
  "@langchain/openai": "^0.6.11",
57
- "@tradejs/core": "^1.0.4",
58
- "@tradejs/infra": "^1.0.4",
59
- "@tradejs/types": "^1.0.4",
70
+ "@tradejs/core": "^1.0.6",
71
+ "@tradejs/infra": "^1.0.6",
72
+ "@tradejs/types": "^1.0.6",
60
73
  "chalk": "4.1.2",
61
74
  "ioredis": "5.8.0",
62
75
  "pinets": "0.8.12",
@@ -1,19 +0,0 @@
1
- import {
2
- MAX_AI_SERIES_POINTS,
3
- askAI,
4
- buildAiHumanPrompt,
5
- buildAiPayload,
6
- buildAiSystemPrompt,
7
- trimSeriesDeep
8
- } from "./chunk-LMAKIC3C.mjs";
9
- import "./chunk-ZY6ULOWK.mjs";
10
- import "./chunk-P2ZUWONT.mjs";
11
- import "./chunk-6DZX6EAA.mjs";
12
- export {
13
- MAX_AI_SERIES_POINTS,
14
- askAI,
15
- buildAiHumanPrompt,
16
- buildAiPayload,
17
- buildAiSystemPrompt,
18
- trimSeriesDeep
19
- };
@@ -1,13 +0,0 @@
1
- // src/constants.ts
2
- var { NODE_ENV } = process.env;
3
- var KLINE_CONCURRENCY_LIMIT = NODE_ENV === "production" ? 5 : 10;
4
- var TG_CONCURRENCY_LIMIT = 3;
5
- var AI_CONCURRENCY_LIMIT = 3;
6
- var SCREENSHOT_CONCURRENCY_LIMIT = NODE_ENV === "production" ? 1 : 2;
7
-
8
- export {
9
- KLINE_CONCURRENCY_LIMIT,
10
- TG_CONCURRENCY_LIMIT,
11
- AI_CONCURRENCY_LIMIT,
12
- SCREENSHOT_CONCURRENCY_LIMIT
13
- };