@tradejs/node 3.1.29-beta.290 → 3.1.29-beta.291
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/ai.js +109 -48
- package/dist/ai.mjs +1 -1
- package/dist/backtest.js +2491 -1871
- package/dist/backtest.mjs +3 -2
- package/dist/{chunk-PB2KHBGH.mjs → chunk-HRON2EAI.mjs} +413 -22
- package/dist/{chunk-UL5Z46JL.mjs → chunk-PYJWXAYR.mjs} +97 -30
- package/dist/chunk-UUNEWAT4.mjs +193 -0
- package/dist/{chunk-BO42QWAB.mjs → chunk-W6PPAADK.mjs} +1 -1
- package/dist/cli.js +834 -773
- package/dist/cli.mjs +1 -1
- package/dist/diagnostics.js +2511 -1891
- package/dist/diagnostics.mjs +4 -3
- package/dist/mcp.d.mts +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +2537 -1917
- package/dist/mcp.mjs +4 -3
- package/dist/portfolio.d.mts +28 -0
- package/dist/portfolio.d.ts +28 -0
- package/dist/portfolio.js +210 -0
- package/dist/portfolio.mjs +9 -0
- package/dist/registry.js +2429 -1809
- package/dist/registry.mjs +3 -2
- package/dist/runtimeDashboard.js +2236 -1614
- package/dist/runtimeDashboard.mjs +4 -3
- package/dist/runtimeStrategies.js +2052 -1432
- package/dist/runtimeStrategies.mjs +4 -3
- package/dist/strategies.d.mts +3 -1
- package/dist/strategies.d.ts +3 -1
- package/dist/strategies.js +2085 -1465
- package/dist/strategies.mjs +3 -2
- package/package.json +10 -5
|
@@ -12,6 +12,16 @@ import {
|
|
|
12
12
|
} from "@tradejs/core/aiLanguages";
|
|
13
13
|
import { setData, redisKeys } from "@tradejs/infra/redis";
|
|
14
14
|
|
|
15
|
+
// src/strategyAdapters/ai.ts
|
|
16
|
+
import { getRegisteredIndicatorEntries } from "@tradejs/core/indicators";
|
|
17
|
+
import {
|
|
18
|
+
projectAiFeatures,
|
|
19
|
+
TICKER_PROFILE_AI_FEATURES,
|
|
20
|
+
PORTFOLIO_AI_FEATURES,
|
|
21
|
+
validateAiFeatureDefinitions,
|
|
22
|
+
validateAiFeatureSnapshot
|
|
23
|
+
} from "@tradejs/core/aiFeatures";
|
|
24
|
+
|
|
15
25
|
// src/aiShared.ts
|
|
16
26
|
var MAX_AI_SERIES_POINTS = 5;
|
|
17
27
|
var COMPACT_INDICATORS_SNAPSHOT_SYMBOL = /* @__PURE__ */ Symbol.for(
|
|
@@ -235,37 +245,44 @@ var buildMarketBreadthsContextFromSignal = (signal) => {
|
|
|
235
245
|
top100: build("top100")
|
|
236
246
|
};
|
|
237
247
|
};
|
|
248
|
+
var buildTargetVsReference = (signal, asset) => {
|
|
249
|
+
const base = toRecord(signal.additionalIndicators?.baseContext);
|
|
250
|
+
const relative = toRecord(base?.relative);
|
|
251
|
+
const target = toRecord(relative?.[`targetVs${asset}`]);
|
|
252
|
+
return {
|
|
253
|
+
source: target ? String(target.source ?? "") : null,
|
|
254
|
+
available: Boolean(target),
|
|
255
|
+
ratioReturn1h: toFiniteNumber(target?.ratioReturn1h),
|
|
256
|
+
ratioReturn4h: toFiniteNumber(target?.ratioReturn4h),
|
|
257
|
+
ratioReturn24h: toFiniteNumber(target?.ratioReturn24h),
|
|
258
|
+
alpha1h: toFiniteNumber(target?.[`alphaVs${asset}1h`]),
|
|
259
|
+
alpha4h: toFiniteNumber(target?.[`alphaVs${asset}4h`]),
|
|
260
|
+
alpha24h: toFiniteNumber(target?.[`alphaVs${asset}24h`]),
|
|
261
|
+
beta: toFiniteNumber(target?.[`betaTo${asset}20`]),
|
|
262
|
+
correlation: toFiniteNumber(target?.[`correlationTo${asset}20`]),
|
|
263
|
+
ratioTrend: typeof target?.ratioTrend === "string" ? target.ratioTrend : null
|
|
264
|
+
};
|
|
265
|
+
};
|
|
238
266
|
var buildTargetVsBtcContextFromSignal = (signal) => {
|
|
239
|
-
const
|
|
240
|
-
const relative = toRecord(baseContext?.relative);
|
|
241
|
-
const targetVsBtc = toRecord(relative?.targetVsBtc);
|
|
242
|
-
if (!targetVsBtc) {
|
|
243
|
-
return {
|
|
244
|
-
source: null,
|
|
245
|
-
available: false,
|
|
246
|
-
ratioReturn1h: null,
|
|
247
|
-
ratioReturn4h: null,
|
|
248
|
-
ratioReturn24h: null,
|
|
249
|
-
alphaVsBtc1h: null,
|
|
250
|
-
alphaVsBtc4h: null,
|
|
251
|
-
alphaVsBtc24h: null,
|
|
252
|
-
betaToBtc20: null,
|
|
253
|
-
correlationToBtc20: null,
|
|
254
|
-
ratioTrend: null
|
|
255
|
-
};
|
|
256
|
-
}
|
|
267
|
+
const { alpha1h, alpha4h, alpha24h, beta, correlation, ...shared } = buildTargetVsReference(signal, "Btc");
|
|
257
268
|
return {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
+
...shared,
|
|
270
|
+
alphaVsBtc1h: alpha1h,
|
|
271
|
+
alphaVsBtc4h: alpha4h,
|
|
272
|
+
alphaVsBtc24h: alpha24h,
|
|
273
|
+
betaToBtc20: beta,
|
|
274
|
+
correlationToBtc20: correlation
|
|
275
|
+
};
|
|
276
|
+
};
|
|
277
|
+
var buildTargetVsEthContextFromSignal = (signal) => {
|
|
278
|
+
const { alpha1h, alpha4h, alpha24h, beta, correlation, ...shared } = buildTargetVsReference(signal, "Eth");
|
|
279
|
+
return {
|
|
280
|
+
...shared,
|
|
281
|
+
alphaVsEth1h: alpha1h,
|
|
282
|
+
alphaVsEth4h: alpha4h,
|
|
283
|
+
alphaVsEth24h: alpha24h,
|
|
284
|
+
betaToEth20: beta,
|
|
285
|
+
correlationToEth20: correlation
|
|
269
286
|
};
|
|
270
287
|
};
|
|
271
288
|
var buildBtcAltRegimeContextFromSignal = (signal) => {
|
|
@@ -574,6 +591,7 @@ var buildAiMarketContext = (signal) => ({
|
|
|
574
591
|
marketBreadth: buildMarketBreadthContextFromSignal(signal),
|
|
575
592
|
marketBreadths: buildMarketBreadthsContextFromSignal(signal),
|
|
576
593
|
targetVsBtc: buildTargetVsBtcContextFromSignal(signal),
|
|
594
|
+
targetVsEth: buildTargetVsEthContextFromSignal(signal),
|
|
577
595
|
btcAltRegime: buildBtcAltRegimeContextFromSignal(signal),
|
|
578
596
|
cmcGlobal: buildCmcGlobalContextFromSignal(signal),
|
|
579
597
|
cmcReferenceAssets: buildCmcReferenceAssetsContextFromSignal(signal),
|
|
@@ -1061,12 +1079,61 @@ var buildBaseAiPayload = (signal) => {
|
|
|
1061
1079
|
};
|
|
1062
1080
|
};
|
|
1063
1081
|
var defaultAiAdapter = {};
|
|
1082
|
+
var tickerProfileFeatureIds = new Set(
|
|
1083
|
+
TICKER_PROFILE_AI_FEATURES.map(({ id }) => id)
|
|
1084
|
+
);
|
|
1064
1085
|
var getStrategyAiAdapter = (strategy, profileId) => getStrategyProfileAiAdapter(getStrategyManifest(strategy), profileId) ?? defaultAiAdapter;
|
|
1065
1086
|
var getSignalAiAdapter = (signal) => getStrategyAiAdapter(signal.strategy, signal.policyProfileId);
|
|
1066
1087
|
var buildAiPayloadByStrategy = (signal) => {
|
|
1067
1088
|
const basePayload = buildBaseAiPayload(signal);
|
|
1068
1089
|
const adapter = getSignalAiAdapter(signal);
|
|
1069
|
-
|
|
1090
|
+
const payload = adapter.buildPayload?.({ signal, basePayload }) ?? basePayload;
|
|
1091
|
+
const custom = getStrategyManifest(signal.strategy)?.aiFeatures ?? [];
|
|
1092
|
+
const frozen = signal.aiFeatureReplay?.snapshot;
|
|
1093
|
+
if (frozen) validateAiFeatureSnapshot(frozen);
|
|
1094
|
+
const tickerProfile = signal.additionalIndicators?.tickerProfile ?? signal.additionalIndicators?.baseContext?.tickerProfile;
|
|
1095
|
+
const hasProfile = Boolean(
|
|
1096
|
+
tickerProfile || frozen?.definitions.some(({ id }) => tickerProfileFeatureIds.has(id))
|
|
1097
|
+
);
|
|
1098
|
+
const indicatorFeatures = getRegisteredIndicatorEntries(
|
|
1099
|
+
getTradejsProjectCwd()
|
|
1100
|
+
).flatMap((entry) => entry.indicator.enabled ? entry.aiFeatures ?? [] : []);
|
|
1101
|
+
const hasPortfolio = Boolean(
|
|
1102
|
+
signal.additionalIndicators?.portfolioContext || frozen?.definitions.some(
|
|
1103
|
+
({ id }) => PORTFOLIO_AI_FEATURES.some((d) => d.id === id)
|
|
1104
|
+
)
|
|
1105
|
+
);
|
|
1106
|
+
const definitions = [
|
|
1107
|
+
...hasPortfolio ? PORTFOLIO_AI_FEATURES : [],
|
|
1108
|
+
...hasProfile ? TICKER_PROFILE_AI_FEATURES : [],
|
|
1109
|
+
...indicatorFeatures,
|
|
1110
|
+
...custom
|
|
1111
|
+
];
|
|
1112
|
+
if (!definitions.length && !signal.aiFeatureReplay?.snapshot) return payload;
|
|
1113
|
+
validateAiFeatureDefinitions(definitions);
|
|
1114
|
+
if (signal.aiFeatureReplay && !frozen) {
|
|
1115
|
+
throw new Error(
|
|
1116
|
+
"Dataset has no frozen AI features; regenerate the decision-time export"
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
if (frozen && JSON.stringify(frozen.definitions) !== JSON.stringify(definitions)) {
|
|
1120
|
+
throw new Error(
|
|
1121
|
+
"AI feature definition changed; regenerate the decision-time export"
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
return {
|
|
1125
|
+
...payload,
|
|
1126
|
+
featureSnapshot: frozen ?? projectAiFeatures(definitions, {
|
|
1127
|
+
signal: tickerProfile ? {
|
|
1128
|
+
...signal,
|
|
1129
|
+
additionalIndicators: {
|
|
1130
|
+
...signal.additionalIndicators,
|
|
1131
|
+
tickerProfile
|
|
1132
|
+
}
|
|
1133
|
+
} : signal,
|
|
1134
|
+
payload
|
|
1135
|
+
})
|
|
1136
|
+
};
|
|
1070
1137
|
};
|
|
1071
1138
|
var buildAiSystemPromptAddonByStrategy = (signal) => getSignalAiAdapter(signal).buildSystemPromptAddon?.({ signal }) ?? "";
|
|
1072
1139
|
var buildAiHumanPromptAddonByStrategy = (signal, payload) => getSignalAiAdapter(signal).buildHumanPromptAddon?.({
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// src/portfolio.ts
|
|
2
|
+
import {
|
|
3
|
+
buildPortfolioContext,
|
|
4
|
+
createPortfolioState,
|
|
5
|
+
portfolioFingerprint,
|
|
6
|
+
reconcilePortfolio,
|
|
7
|
+
reservePortfolioEntry,
|
|
8
|
+
portfolioCloseCommands,
|
|
9
|
+
validatePortfolioObservation
|
|
10
|
+
} from "@tradejs/core/portfolio";
|
|
11
|
+
function createPortfolioCoordinator({
|
|
12
|
+
policy,
|
|
13
|
+
strategy,
|
|
14
|
+
store,
|
|
15
|
+
execution
|
|
16
|
+
}) {
|
|
17
|
+
const fingerprint = portfolioFingerprint(policy, strategy);
|
|
18
|
+
let cache;
|
|
19
|
+
async function transact(now, change, force = false) {
|
|
20
|
+
for (let attempt = 0; attempt < 16; attempt++) {
|
|
21
|
+
const previous = await store.read();
|
|
22
|
+
if (previous && previous.fingerprint !== fingerprint)
|
|
23
|
+
throw new Error(
|
|
24
|
+
"Portfolio policy changed under existing state; reconcile the persisted scope before changing configuration"
|
|
25
|
+
);
|
|
26
|
+
const base = previous ?? createPortfolioState(fingerprint);
|
|
27
|
+
const bucket = Math.floor(now / policy.observationIntervalMs);
|
|
28
|
+
const observation = !force && cache?.revision === base.revision && cache.bucket === bucket ? cache.observation : await execution.observe(now, base.reservations);
|
|
29
|
+
const reconciled = reconcilePortfolio(
|
|
30
|
+
policy,
|
|
31
|
+
strategy,
|
|
32
|
+
base,
|
|
33
|
+
observation
|
|
34
|
+
);
|
|
35
|
+
for (const intent of base.closing) {
|
|
36
|
+
if (!observation.positions.some(
|
|
37
|
+
(p) => p.symbol === intent.position.symbol
|
|
38
|
+
))
|
|
39
|
+
await execution.confirmClosed?.(intent, observation.asOf);
|
|
40
|
+
}
|
|
41
|
+
const changed = change(reconciled, observation);
|
|
42
|
+
const next = { ...changed.state, revision: base.revision + 1 };
|
|
43
|
+
if (await store.compare(previous, next)) {
|
|
44
|
+
cache = { revision: next.revision, bucket, observation };
|
|
45
|
+
return { state: next, observation, result: changed.result };
|
|
46
|
+
}
|
|
47
|
+
cache = void 0;
|
|
48
|
+
}
|
|
49
|
+
throw new Error("Portfolio state contention; entry was not submitted");
|
|
50
|
+
}
|
|
51
|
+
async function tick(now, force = false) {
|
|
52
|
+
const claimed = await transact(
|
|
53
|
+
now,
|
|
54
|
+
(state, observation) => {
|
|
55
|
+
const commands = portfolioCloseCommands(policy, state, observation);
|
|
56
|
+
return {
|
|
57
|
+
state: {
|
|
58
|
+
...state,
|
|
59
|
+
closing: state.closing.map(
|
|
60
|
+
(c) => commands.some((x) => x.intent.positionId === c.positionId) ? { ...c, lastAttemptAt: observation.asOf } : c
|
|
61
|
+
)
|
|
62
|
+
},
|
|
63
|
+
result: commands
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
force
|
|
67
|
+
);
|
|
68
|
+
for (const command of claimed.result)
|
|
69
|
+
await execution.close(
|
|
70
|
+
command.position,
|
|
71
|
+
command.intent,
|
|
72
|
+
claimed.observation.asOf
|
|
73
|
+
);
|
|
74
|
+
if (claimed.result.length) {
|
|
75
|
+
cache = void 0;
|
|
76
|
+
const refreshed = await transact(
|
|
77
|
+
now,
|
|
78
|
+
(state) => ({ state, result: void 0 }),
|
|
79
|
+
true
|
|
80
|
+
);
|
|
81
|
+
return buildPortfolioContext(
|
|
82
|
+
policy,
|
|
83
|
+
strategy,
|
|
84
|
+
refreshed.state,
|
|
85
|
+
refreshed.observation
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return buildPortfolioContext(
|
|
89
|
+
policy,
|
|
90
|
+
strategy,
|
|
91
|
+
claimed.state,
|
|
92
|
+
claimed.observation
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
async function updateReservation(now, id, submitted, qty) {
|
|
96
|
+
return transact(
|
|
97
|
+
now,
|
|
98
|
+
(s, o) => {
|
|
99
|
+
const exists = s.reservations.some((r) => r.id === id);
|
|
100
|
+
const blocked = submitted && (!exists || s.closing.length > 0 || o.asOf <= s.blockedThrough);
|
|
101
|
+
return {
|
|
102
|
+
state: {
|
|
103
|
+
...s,
|
|
104
|
+
reservations: s.reservations.flatMap(
|
|
105
|
+
(r) => r.id !== id ? [r] : submitted && !blocked ? [{ ...r, submitted: true, qty: qty ?? r.qty }] : []
|
|
106
|
+
)
|
|
107
|
+
},
|
|
108
|
+
result: !blocked
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
true
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
async context(now) {
|
|
116
|
+
const state = await store.read() ?? createPortfolioState(fingerprint);
|
|
117
|
+
if (state.fingerprint !== fingerprint)
|
|
118
|
+
throw new Error("Portfolio policy changed under existing state");
|
|
119
|
+
const observation = await execution.observe(now, state.reservations);
|
|
120
|
+
validatePortfolioObservation(observation);
|
|
121
|
+
return buildPortfolioContext(policy, strategy, state, observation);
|
|
122
|
+
},
|
|
123
|
+
tick,
|
|
124
|
+
async submit(now, entry, send) {
|
|
125
|
+
await tick(now);
|
|
126
|
+
const admitted = await transact(
|
|
127
|
+
now,
|
|
128
|
+
(s, o) => {
|
|
129
|
+
const r = reservePortfolioEntry(policy, strategy, s, o, {
|
|
130
|
+
...entry,
|
|
131
|
+
submitted: false,
|
|
132
|
+
oppositeHandled: false
|
|
133
|
+
});
|
|
134
|
+
return { state: r.state, result: r.reason };
|
|
135
|
+
},
|
|
136
|
+
true
|
|
137
|
+
);
|
|
138
|
+
if (admitted.result) return { reason: admitted.result };
|
|
139
|
+
let submitted = false;
|
|
140
|
+
try {
|
|
141
|
+
const value = await send(
|
|
142
|
+
async (qty) => {
|
|
143
|
+
if (!Number.isFinite(qty) || qty <= 0)
|
|
144
|
+
throw new Error("Invalid submitted portfolio quantity");
|
|
145
|
+
submitted = true;
|
|
146
|
+
const update = await updateReservation(now, entry.id, true, qty);
|
|
147
|
+
if (!update.result)
|
|
148
|
+
throw new Error("PORTFOLIO_SUBMISSION_NO_LONGER_ADMITTED");
|
|
149
|
+
},
|
|
150
|
+
async () => {
|
|
151
|
+
await transact(
|
|
152
|
+
now,
|
|
153
|
+
(s) => ({
|
|
154
|
+
state: {
|
|
155
|
+
...s,
|
|
156
|
+
reservations: s.reservations.filter((r) => r.id !== entry.id),
|
|
157
|
+
completedSignals: {
|
|
158
|
+
...s.completedSignals,
|
|
159
|
+
[entry.signalId]: now
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
result: void 0
|
|
163
|
+
}),
|
|
164
|
+
true
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
if (!submitted) await updateReservation(now, entry.id, false);
|
|
169
|
+
else await tick(now, true);
|
|
170
|
+
return { value };
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (!submitted) await updateReservation(now, entry.id, false);
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function createMemoryPortfolioStore() {
|
|
179
|
+
let state = null;
|
|
180
|
+
return {
|
|
181
|
+
read: async () => state === null ? null : structuredClone(state),
|
|
182
|
+
compare: async (expected, next) => {
|
|
183
|
+
if ((state?.revision ?? -1) !== (expected?.revision ?? -1)) return false;
|
|
184
|
+
state = structuredClone(next);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export {
|
|
191
|
+
createPortfolioCoordinator,
|
|
192
|
+
createMemoryPortfolioStore
|
|
193
|
+
};
|