@tradejs/node 3.1.29-beta.283 → 3.1.29-beta.284
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/backtest.d.mts +13 -2
- package/dist/backtest.d.ts +13 -2
- package/dist/backtest.js +161 -7
- package/dist/backtest.mjs +28 -6
- package/dist/{chunk-SKY2HNZU.mjs → chunk-K56EW2BB.mjs} +140 -1
- package/dist/diagnostics.js +130 -1
- package/dist/diagnostics.mjs +1 -1
- package/dist/mcp.js +130 -1
- package/dist/mcp.mjs +1 -1
- package/dist/registry.js +130 -1
- package/dist/registry.mjs +1 -1
- package/dist/runtimeDashboard.js +130 -1
- package/dist/runtimeDashboard.mjs +1 -1
- package/dist/runtimeStrategies.js +130 -1
- package/dist/runtimeStrategies.mjs +1 -1
- package/dist/strategies.js +130 -1
- package/dist/strategies.mjs +1 -1
- package/package.json +5 -5
|
@@ -6192,6 +6192,112 @@ var buildAiHookContext = ({
|
|
|
6192
6192
|
};
|
|
6193
6193
|
};
|
|
6194
6194
|
|
|
6195
|
+
// src/researchEntryPolicy.ts
|
|
6196
|
+
var forbidden = /(?:^|\.)(?:__proto__|prototype|constructor|profit|pnl|outcome|tradeResult|backtestExecution|quality|deterministicQuality|approvalAllowedNow|timestamp|knownAt|source|coverage|points|rows|length)(?:\.|$)/i;
|
|
6197
|
+
var buildResearchEntryPayload = (signal, payload = buildAiPayload(signal)) => {
|
|
6198
|
+
const additional = payload.additionalIndicators && typeof payload.additionalIndicators === "object" ? payload.additionalIndicators : {};
|
|
6199
|
+
const raw = signal.additionalIndicators?.baseContext;
|
|
6200
|
+
const adapted = additional.baseContext;
|
|
6201
|
+
return {
|
|
6202
|
+
...payload,
|
|
6203
|
+
additionalIndicators: {
|
|
6204
|
+
...additional,
|
|
6205
|
+
...signal.additionalIndicators?.jev && typeof signal.additionalIndicators.jev === "object" ? { jev: signal.additionalIndicators.jev } : {},
|
|
6206
|
+
baseContext: {
|
|
6207
|
+
...raw && typeof raw === "object" ? raw : {},
|
|
6208
|
+
...adapted && typeof adapted === "object" ? adapted : {}
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
};
|
|
6212
|
+
};
|
|
6213
|
+
var parseResearchEntryPolicy = (value) => {
|
|
6214
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6215
|
+
throw new Error("Invalid research entry policy");
|
|
6216
|
+
const policy = value;
|
|
6217
|
+
if (policy.schema !== "tradejs-research-entry-policy/v1" || typeof policy.strategy !== "string" || !policy.strategy.trim() || !["current-gate", "rules"].includes(policy.mode) || !Number.isInteger(policy.minQuality) || policy.minQuality < 1 || policy.minQuality > 5 || !policy.rules || typeof policy.rules !== "object")
|
|
6218
|
+
throw new Error("Invalid research entry policy contract");
|
|
6219
|
+
if (policy.directions !== void 0 && (!Array.isArray(policy.directions) || policy.directions.length > 2 || new Set(policy.directions).size !== policy.directions.length || policy.directions.some((side) => !["LONG", "SHORT"].includes(side))))
|
|
6220
|
+
throw new Error("Invalid research policy directions");
|
|
6221
|
+
for (const side of ["LONG", "SHORT"]) {
|
|
6222
|
+
const predicates = policy.rules[side];
|
|
6223
|
+
if (predicates === null) continue;
|
|
6224
|
+
if (!Array.isArray(predicates) || predicates.length > 4)
|
|
6225
|
+
throw new Error(
|
|
6226
|
+
"Research policy needs bounded rules for both directions"
|
|
6227
|
+
);
|
|
6228
|
+
for (const predicate of predicates) {
|
|
6229
|
+
if (!predicate || typeof predicate.path !== "string" || !/^additionalIndicators\.[a-zA-Z0-9_.]+$/.test(predicate.path) || forbidden.test(predicate.path) || !["<=", ">=", "=="].includes(predicate.op) || (predicate.op === "==" ? !["string", "boolean"].includes(typeof predicate.value) : typeof predicate.value !== "number" || !Number.isFinite(predicate.value)))
|
|
6230
|
+
throw new Error(
|
|
6231
|
+
"Research policy contains an unsupported or non-causal predicate"
|
|
6232
|
+
);
|
|
6233
|
+
}
|
|
6234
|
+
}
|
|
6235
|
+
return policy;
|
|
6236
|
+
};
|
|
6237
|
+
var matchesResearchEntryRules = (payload, predicates) => predicates.every((predicate) => {
|
|
6238
|
+
const value = predicate.path.split(".").reduce(
|
|
6239
|
+
(current, key) => current != null && typeof current === "object" && Object.hasOwn(current, key) ? Reflect.get(current, key) : void 0,
|
|
6240
|
+
payload
|
|
6241
|
+
);
|
|
6242
|
+
if (value == null) return false;
|
|
6243
|
+
if (predicate.op === "==") return value === predicate.value;
|
|
6244
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return false;
|
|
6245
|
+
return predicate.op === "<=" ? value <= predicate.value : value >= predicate.value;
|
|
6246
|
+
});
|
|
6247
|
+
var evaluateResearchEntryPolicy = async (policy, signal, onDecision) => {
|
|
6248
|
+
if (signal.strategy !== policy.strategy)
|
|
6249
|
+
throw new Error("Research policy strategy mismatch");
|
|
6250
|
+
if (policy.directions && !policy.directions.includes(signal.direction) || policy.mode === "rules" && policy.rules[signal.direction] === null) {
|
|
6251
|
+
onDecision?.({
|
|
6252
|
+
mode: policy.mode,
|
|
6253
|
+
allowed: false,
|
|
6254
|
+
reason: "DIRECTION_BLOCKED"
|
|
6255
|
+
});
|
|
6256
|
+
return false;
|
|
6257
|
+
}
|
|
6258
|
+
if (policy.mode === "current-gate") {
|
|
6259
|
+
const analysis = await runAiPromptLocal(signal);
|
|
6260
|
+
const allowed2 = analysis.direction === signal.direction && typeof analysis.quality === "number" && analysis.quality >= policy.minQuality;
|
|
6261
|
+
onDecision?.({
|
|
6262
|
+
mode: policy.mode,
|
|
6263
|
+
allowed: allowed2,
|
|
6264
|
+
quality: analysis.quality ?? null,
|
|
6265
|
+
reason: allowed2 ? "CURRENT_GATE_APPROVED" : "CURRENT_GATE_REJECTED"
|
|
6266
|
+
});
|
|
6267
|
+
return allowed2;
|
|
6268
|
+
}
|
|
6269
|
+
const original = buildAiPayload(signal);
|
|
6270
|
+
const gateContext = getDeterministicAiGateContext(original);
|
|
6271
|
+
if (Array.isArray(gateContext?.structuralHardBlockReasons) && gateContext.structuralHardBlockReasons.length) {
|
|
6272
|
+
onDecision?.({
|
|
6273
|
+
mode: policy.mode,
|
|
6274
|
+
allowed: false,
|
|
6275
|
+
reason: "STRUCTURAL_HARD_BLOCK"
|
|
6276
|
+
});
|
|
6277
|
+
return false;
|
|
6278
|
+
}
|
|
6279
|
+
const rules = policy.rules[signal.direction];
|
|
6280
|
+
const payload = buildResearchEntryPayload(signal, original);
|
|
6281
|
+
const allowed = rules !== null && matchesResearchEntryRules(payload, rules);
|
|
6282
|
+
onDecision?.({
|
|
6283
|
+
mode: policy.mode,
|
|
6284
|
+
allowed,
|
|
6285
|
+
reason: allowed ? "RULES_APPROVED" : "PREDICATE_REJECTED",
|
|
6286
|
+
predicates: rules?.map((rule) => {
|
|
6287
|
+
const value = rule.path.split(".").reduce(
|
|
6288
|
+
(current, key) => current && typeof current === "object" && Object.hasOwn(current, key) ? Reflect.get(current, key) : void 0,
|
|
6289
|
+
payload
|
|
6290
|
+
);
|
|
6291
|
+
return {
|
|
6292
|
+
path: rule.path,
|
|
6293
|
+
actual: typeof value === "number" && Number.isFinite(value) || typeof value === "string" || typeof value === "boolean" ? value : null,
|
|
6294
|
+
passed: matchesResearchEntryRules(payload, [rule])
|
|
6295
|
+
};
|
|
6296
|
+
})
|
|
6297
|
+
});
|
|
6298
|
+
return allowed;
|
|
6299
|
+
};
|
|
6300
|
+
|
|
6195
6301
|
// src/strategy/runtimeDecisionTelemetry.ts
|
|
6196
6302
|
var finitePositive = (value) => {
|
|
6197
6303
|
const parsed = Number(value);
|
|
@@ -6730,6 +6836,12 @@ var createStrategyRuntime = ({
|
|
|
6730
6836
|
const projectConfig = await loadTradejsConfig(projectRoot);
|
|
6731
6837
|
const projectHooks = projectConfig.hooks;
|
|
6732
6838
|
const env = String(config.ENV ?? "BACKTEST");
|
|
6839
|
+
const researchPolicyValue = baseConfig?.RESEARCH_ENTRY_POLICY ?? config.RESEARCH_ENTRY_POLICY;
|
|
6840
|
+
const researchEntryPolicy = researchPolicyValue == null ? void 0 : parseResearchEntryPolicy(researchPolicyValue);
|
|
6841
|
+
if (researchEntryPolicy && (env !== "BACKTEST" || Reflect.get(connector, "__tradejsTestConnector") !== true))
|
|
6842
|
+
throw new Error(
|
|
6843
|
+
"Research entry policies require a BACKTEST simulation connector"
|
|
6844
|
+
);
|
|
6733
6845
|
const jev = (0, import_jev6.parseJevConfig)(config.JEV);
|
|
6734
6846
|
if (jev && env !== "BACKTEST" && jev.source === "provider" && !jev.provider)
|
|
6735
6847
|
throw new Error(
|
|
@@ -7440,7 +7552,8 @@ var createStrategyRuntime = ({
|
|
|
7440
7552
|
await enrichSignalWithMarketContextStages({
|
|
7441
7553
|
signal,
|
|
7442
7554
|
env,
|
|
7443
|
-
includeHyperliquidWhales:
|
|
7555
|
+
includeHyperliquidWhales: Boolean(researchEntryPolicy),
|
|
7556
|
+
...researchEntryPolicy ? { coinMarketCapEnabled: true } : {}
|
|
7444
7557
|
});
|
|
7445
7558
|
if (jev) {
|
|
7446
7559
|
await assessSignalWithJev({
|
|
@@ -7538,6 +7651,22 @@ var createStrategyRuntime = ({
|
|
|
7538
7651
|
}
|
|
7539
7652
|
return signal ?? decision.code;
|
|
7540
7653
|
}
|
|
7654
|
+
if (researchEntryPolicy && (!signal || !await evaluateResearchEntryPolicy(
|
|
7655
|
+
researchEntryPolicy,
|
|
7656
|
+
signal,
|
|
7657
|
+
(decision2) => {
|
|
7658
|
+
signal.additionalIndicators = {
|
|
7659
|
+
...signal.additionalIndicators,
|
|
7660
|
+
researchEntryDecision: decision2
|
|
7661
|
+
};
|
|
7662
|
+
}
|
|
7663
|
+
))) {
|
|
7664
|
+
if (signal) {
|
|
7665
|
+
signal.orderStatus = "skipped";
|
|
7666
|
+
signal.orderSkipReason = "RESEARCH_ENTRY_POLICY_REJECTED";
|
|
7667
|
+
}
|
|
7668
|
+
return signal ?? "RESEARCH_ENTRY_POLICY_REJECTED";
|
|
7669
|
+
}
|
|
7541
7670
|
const entryGate = await invokeGateHooks(
|
|
7542
7671
|
"beforeEntryGate",
|
|
7543
7672
|
decisionManifest?.hooks?.beforeEntryGate,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resolveRuntimeComposition,
|
|
10
10
|
verifyRuntimeDeclaration
|
|
11
11
|
} from "./chunk-BO42QWAB.mjs";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-K56EW2BB.mjs";
|
|
13
13
|
import "./chunk-UL5Z46JL.mjs";
|
|
14
14
|
import "./chunk-LZDXRXIU.mjs";
|
|
15
15
|
import "./chunk-YR55Q355.mjs";
|
package/dist/strategies.js
CHANGED
|
@@ -6454,6 +6454,112 @@ var buildAiHookContext = ({
|
|
|
6454
6454
|
};
|
|
6455
6455
|
};
|
|
6456
6456
|
|
|
6457
|
+
// src/researchEntryPolicy.ts
|
|
6458
|
+
var forbidden = /(?:^|\.)(?:__proto__|prototype|constructor|profit|pnl|outcome|tradeResult|backtestExecution|quality|deterministicQuality|approvalAllowedNow|timestamp|knownAt|source|coverage|points|rows|length)(?:\.|$)/i;
|
|
6459
|
+
var buildResearchEntryPayload = (signal, payload = buildAiPayload(signal)) => {
|
|
6460
|
+
const additional = payload.additionalIndicators && typeof payload.additionalIndicators === "object" ? payload.additionalIndicators : {};
|
|
6461
|
+
const raw = signal.additionalIndicators?.baseContext;
|
|
6462
|
+
const adapted = additional.baseContext;
|
|
6463
|
+
return {
|
|
6464
|
+
...payload,
|
|
6465
|
+
additionalIndicators: {
|
|
6466
|
+
...additional,
|
|
6467
|
+
...signal.additionalIndicators?.jev && typeof signal.additionalIndicators.jev === "object" ? { jev: signal.additionalIndicators.jev } : {},
|
|
6468
|
+
baseContext: {
|
|
6469
|
+
...raw && typeof raw === "object" ? raw : {},
|
|
6470
|
+
...adapted && typeof adapted === "object" ? adapted : {}
|
|
6471
|
+
}
|
|
6472
|
+
}
|
|
6473
|
+
};
|
|
6474
|
+
};
|
|
6475
|
+
var parseResearchEntryPolicy = (value) => {
|
|
6476
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6477
|
+
throw new Error("Invalid research entry policy");
|
|
6478
|
+
const policy = value;
|
|
6479
|
+
if (policy.schema !== "tradejs-research-entry-policy/v1" || typeof policy.strategy !== "string" || !policy.strategy.trim() || !["current-gate", "rules"].includes(policy.mode) || !Number.isInteger(policy.minQuality) || policy.minQuality < 1 || policy.minQuality > 5 || !policy.rules || typeof policy.rules !== "object")
|
|
6480
|
+
throw new Error("Invalid research entry policy contract");
|
|
6481
|
+
if (policy.directions !== void 0 && (!Array.isArray(policy.directions) || policy.directions.length > 2 || new Set(policy.directions).size !== policy.directions.length || policy.directions.some((side) => !["LONG", "SHORT"].includes(side))))
|
|
6482
|
+
throw new Error("Invalid research policy directions");
|
|
6483
|
+
for (const side of ["LONG", "SHORT"]) {
|
|
6484
|
+
const predicates = policy.rules[side];
|
|
6485
|
+
if (predicates === null) continue;
|
|
6486
|
+
if (!Array.isArray(predicates) || predicates.length > 4)
|
|
6487
|
+
throw new Error(
|
|
6488
|
+
"Research policy needs bounded rules for both directions"
|
|
6489
|
+
);
|
|
6490
|
+
for (const predicate of predicates) {
|
|
6491
|
+
if (!predicate || typeof predicate.path !== "string" || !/^additionalIndicators\.[a-zA-Z0-9_.]+$/.test(predicate.path) || forbidden.test(predicate.path) || !["<=", ">=", "=="].includes(predicate.op) || (predicate.op === "==" ? !["string", "boolean"].includes(typeof predicate.value) : typeof predicate.value !== "number" || !Number.isFinite(predicate.value)))
|
|
6492
|
+
throw new Error(
|
|
6493
|
+
"Research policy contains an unsupported or non-causal predicate"
|
|
6494
|
+
);
|
|
6495
|
+
}
|
|
6496
|
+
}
|
|
6497
|
+
return policy;
|
|
6498
|
+
};
|
|
6499
|
+
var matchesResearchEntryRules = (payload, predicates) => predicates.every((predicate) => {
|
|
6500
|
+
const value = predicate.path.split(".").reduce(
|
|
6501
|
+
(current, key) => current != null && typeof current === "object" && Object.hasOwn(current, key) ? Reflect.get(current, key) : void 0,
|
|
6502
|
+
payload
|
|
6503
|
+
);
|
|
6504
|
+
if (value == null) return false;
|
|
6505
|
+
if (predicate.op === "==") return value === predicate.value;
|
|
6506
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return false;
|
|
6507
|
+
return predicate.op === "<=" ? value <= predicate.value : value >= predicate.value;
|
|
6508
|
+
});
|
|
6509
|
+
var evaluateResearchEntryPolicy = async (policy, signal, onDecision) => {
|
|
6510
|
+
if (signal.strategy !== policy.strategy)
|
|
6511
|
+
throw new Error("Research policy strategy mismatch");
|
|
6512
|
+
if (policy.directions && !policy.directions.includes(signal.direction) || policy.mode === "rules" && policy.rules[signal.direction] === null) {
|
|
6513
|
+
onDecision?.({
|
|
6514
|
+
mode: policy.mode,
|
|
6515
|
+
allowed: false,
|
|
6516
|
+
reason: "DIRECTION_BLOCKED"
|
|
6517
|
+
});
|
|
6518
|
+
return false;
|
|
6519
|
+
}
|
|
6520
|
+
if (policy.mode === "current-gate") {
|
|
6521
|
+
const analysis = await runAiPromptLocal(signal);
|
|
6522
|
+
const allowed2 = analysis.direction === signal.direction && typeof analysis.quality === "number" && analysis.quality >= policy.minQuality;
|
|
6523
|
+
onDecision?.({
|
|
6524
|
+
mode: policy.mode,
|
|
6525
|
+
allowed: allowed2,
|
|
6526
|
+
quality: analysis.quality ?? null,
|
|
6527
|
+
reason: allowed2 ? "CURRENT_GATE_APPROVED" : "CURRENT_GATE_REJECTED"
|
|
6528
|
+
});
|
|
6529
|
+
return allowed2;
|
|
6530
|
+
}
|
|
6531
|
+
const original = buildAiPayload(signal);
|
|
6532
|
+
const gateContext = getDeterministicAiGateContext(original);
|
|
6533
|
+
if (Array.isArray(gateContext?.structuralHardBlockReasons) && gateContext.structuralHardBlockReasons.length) {
|
|
6534
|
+
onDecision?.({
|
|
6535
|
+
mode: policy.mode,
|
|
6536
|
+
allowed: false,
|
|
6537
|
+
reason: "STRUCTURAL_HARD_BLOCK"
|
|
6538
|
+
});
|
|
6539
|
+
return false;
|
|
6540
|
+
}
|
|
6541
|
+
const rules = policy.rules[signal.direction];
|
|
6542
|
+
const payload = buildResearchEntryPayload(signal, original);
|
|
6543
|
+
const allowed = rules !== null && matchesResearchEntryRules(payload, rules);
|
|
6544
|
+
onDecision?.({
|
|
6545
|
+
mode: policy.mode,
|
|
6546
|
+
allowed,
|
|
6547
|
+
reason: allowed ? "RULES_APPROVED" : "PREDICATE_REJECTED",
|
|
6548
|
+
predicates: rules?.map((rule) => {
|
|
6549
|
+
const value = rule.path.split(".").reduce(
|
|
6550
|
+
(current, key) => current && typeof current === "object" && Object.hasOwn(current, key) ? Reflect.get(current, key) : void 0,
|
|
6551
|
+
payload
|
|
6552
|
+
);
|
|
6553
|
+
return {
|
|
6554
|
+
path: rule.path,
|
|
6555
|
+
actual: typeof value === "number" && Number.isFinite(value) || typeof value === "string" || typeof value === "boolean" ? value : null,
|
|
6556
|
+
passed: matchesResearchEntryRules(payload, [rule])
|
|
6557
|
+
};
|
|
6558
|
+
})
|
|
6559
|
+
});
|
|
6560
|
+
return allowed;
|
|
6561
|
+
};
|
|
6562
|
+
|
|
6457
6563
|
// src/strategy/runtimeDecisionTelemetry.ts
|
|
6458
6564
|
var finitePositive = (value) => {
|
|
6459
6565
|
const parsed = Number(value);
|
|
@@ -6992,6 +7098,12 @@ var createStrategyRuntime = ({
|
|
|
6992
7098
|
const projectConfig = await loadTradejsConfig(projectRoot);
|
|
6993
7099
|
const projectHooks = projectConfig.hooks;
|
|
6994
7100
|
const env = String(config.ENV ?? "BACKTEST");
|
|
7101
|
+
const researchPolicyValue = baseConfig?.RESEARCH_ENTRY_POLICY ?? config.RESEARCH_ENTRY_POLICY;
|
|
7102
|
+
const researchEntryPolicy = researchPolicyValue == null ? void 0 : parseResearchEntryPolicy(researchPolicyValue);
|
|
7103
|
+
if (researchEntryPolicy && (env !== "BACKTEST" || Reflect.get(connector, "__tradejsTestConnector") !== true))
|
|
7104
|
+
throw new Error(
|
|
7105
|
+
"Research entry policies require a BACKTEST simulation connector"
|
|
7106
|
+
);
|
|
6995
7107
|
const jev = (0, import_jev6.parseJevConfig)(config.JEV);
|
|
6996
7108
|
if (jev && env !== "BACKTEST" && jev.source === "provider" && !jev.provider)
|
|
6997
7109
|
throw new Error(
|
|
@@ -7702,7 +7814,8 @@ var createStrategyRuntime = ({
|
|
|
7702
7814
|
await enrichSignalWithMarketContextStages({
|
|
7703
7815
|
signal,
|
|
7704
7816
|
env,
|
|
7705
|
-
includeHyperliquidWhales:
|
|
7817
|
+
includeHyperliquidWhales: Boolean(researchEntryPolicy),
|
|
7818
|
+
...researchEntryPolicy ? { coinMarketCapEnabled: true } : {}
|
|
7706
7819
|
});
|
|
7707
7820
|
if (jev) {
|
|
7708
7821
|
await assessSignalWithJev({
|
|
@@ -7800,6 +7913,22 @@ var createStrategyRuntime = ({
|
|
|
7800
7913
|
}
|
|
7801
7914
|
return signal ?? decision.code;
|
|
7802
7915
|
}
|
|
7916
|
+
if (researchEntryPolicy && (!signal || !await evaluateResearchEntryPolicy(
|
|
7917
|
+
researchEntryPolicy,
|
|
7918
|
+
signal,
|
|
7919
|
+
(decision2) => {
|
|
7920
|
+
signal.additionalIndicators = {
|
|
7921
|
+
...signal.additionalIndicators,
|
|
7922
|
+
researchEntryDecision: decision2
|
|
7923
|
+
};
|
|
7924
|
+
}
|
|
7925
|
+
))) {
|
|
7926
|
+
if (signal) {
|
|
7927
|
+
signal.orderStatus = "skipped";
|
|
7928
|
+
signal.orderSkipReason = "RESEARCH_ENTRY_POLICY_REJECTED";
|
|
7929
|
+
}
|
|
7930
|
+
return signal ?? "RESEARCH_ENTRY_POLICY_REJECTED";
|
|
7931
|
+
}
|
|
7803
7932
|
const entryGate = await invokeGateHooks(
|
|
7804
7933
|
"beforeEntryGate",
|
|
7805
7934
|
decisionManifest?.hooks?.beforeEntryGate,
|
package/dist/strategies.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/node",
|
|
3
|
-
"version": "3.1.29-beta.
|
|
3
|
+
"version": "3.1.29-beta.284",
|
|
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",
|
|
@@ -105,9 +105,9 @@
|
|
|
105
105
|
"dependencies": {
|
|
106
106
|
"@langchain/core": "^1.2.3",
|
|
107
107
|
"@langchain/openai": "^1.5.5",
|
|
108
|
-
"@tradejs/core": "^3.1.29-beta.
|
|
109
|
-
"@tradejs/infra": "^3.1.29-beta.
|
|
110
|
-
"@tradejs/types": "^3.1.29-beta.
|
|
108
|
+
"@tradejs/core": "^3.1.29-beta.284",
|
|
109
|
+
"@tradejs/infra": "^3.1.29-beta.284",
|
|
110
|
+
"@tradejs/types": "^3.1.29-beta.284",
|
|
111
111
|
"@types/node": "^24",
|
|
112
112
|
"chalk": "4.1.2",
|
|
113
113
|
"ioredis": "5.11.1",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"typescript": "^5.9"
|
|
121
121
|
},
|
|
122
122
|
"devDependencies": {
|
|
123
|
-
"@tradejs/indicators": "^3.1.29-beta.
|
|
123
|
+
"@tradejs/indicators": "^3.1.29-beta.284",
|
|
124
124
|
"@tradejs/strategy-adaptive-momentum-ribbon": "3.0.5",
|
|
125
125
|
"@tradejs/strategy-hyperliquid-consensus": "3.0.5",
|
|
126
126
|
"@tradejs/strategy-kit": "3.0.6",
|