@tradejs/node 3.1.29-beta.289 → 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 +2504 -1883
- package/dist/backtest.mjs +3 -2
- package/dist/{chunk-KYGJBMKE.mjs → chunk-HRON2EAI.mjs} +432 -40
- 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 +837 -775
- package/dist/cli.mjs +4 -3
- package/dist/diagnostics.js +2532 -1911
- package/dist/diagnostics.mjs +4 -3
- package/dist/mcp.d.mts +4 -2
- package/dist/mcp.d.ts +4 -2
- package/dist/mcp.js +2614 -1971
- package/dist/mcp.mjs +27 -5
- 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 +2091 -1470
- package/dist/registry.mjs +3 -2
- package/dist/runtimeDashboard.js +2255 -1632
- package/dist/runtimeDashboard.mjs +4 -3
- package/dist/runtimeStrategies.js +2417 -1796
- package/dist/runtimeStrategies.mjs +4 -3
- package/dist/strategies.d.mts +3 -1
- package/dist/strategies.d.ts +3 -1
- package/dist/strategies.js +2106 -1485
- package/dist/strategies.mjs +3 -2
- package/package.json +10 -5
package/dist/mcp.mjs
CHANGED
|
@@ -6,11 +6,12 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
listRuntimeDeployments,
|
|
8
8
|
loadResolvedRuntimeStrategies
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-W6PPAADK.mjs";
|
|
10
|
+
import "./chunk-HRON2EAI.mjs";
|
|
11
|
+
import "./chunk-UUNEWAT4.mjs";
|
|
11
12
|
import {
|
|
12
13
|
ensureIndicatorPluginsLoaded
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-PYJWXAYR.mjs";
|
|
14
15
|
import "./chunk-LZDXRXIU.mjs";
|
|
15
16
|
import "./chunk-YR55Q355.mjs";
|
|
16
17
|
import "./chunk-GHSLOJLE.mjs";
|
|
@@ -37,6 +38,7 @@ import { getRuntimeStorageDayKey } from "@tradejs/core/time";
|
|
|
37
38
|
import { createHash } from "crypto";
|
|
38
39
|
import { readFile } from "fs/promises";
|
|
39
40
|
import path from "path";
|
|
41
|
+
import { stripVTControlCharacters } from "util";
|
|
40
42
|
import { getDataStrict, mcpStorage, redisKeys } from "@tradejs/infra/redis";
|
|
41
43
|
var MCP_JOB_TTL = 7 * 86400;
|
|
42
44
|
var hash = (value) => createHash("sha256").update(value).digest("hex");
|
|
@@ -202,10 +204,29 @@ var readAuthorizedMcpJob = async (principal, id) => {
|
|
|
202
204
|
throw new Error("Insufficient scope");
|
|
203
205
|
return job;
|
|
204
206
|
};
|
|
205
|
-
var
|
|
207
|
+
var redactMcpLogLine = (line) => line.replace(/\u001b\[[0-9;]*m/g, "").replace(/\b(Bearer|Basic)\s+\S+/gi, "$1 [redacted]").replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@]*:[^\s/@]+@/gi, "$1[redacted]@").replace(/((?:authorization|cookie)\s*:\s*)[^\r\n]+/gi, "$1[redacted]").replace(
|
|
206
208
|
/((?:[\w.-]*(?:secret|password|token|api[_-]?key|private[_-]?key|authorization|cookie|credential)[\w.-]*)["']?\s*[:=]\s*)(?:"[^"\r\n]*"|'[^'\r\n]*'|[^\s,;&}]+)/gi,
|
|
207
209
|
"$1[redacted]"
|
|
208
|
-
)
|
|
210
|
+
);
|
|
211
|
+
var MCP_LOG_LINE_LIMIT = 1e3;
|
|
212
|
+
var redactMcpJobLog = (line) => redactMcpLogLine(line).slice(0, MCP_LOG_LINE_LIMIT);
|
|
213
|
+
var formatMcpArtifactLogLine = (line) => {
|
|
214
|
+
const text = redactMcpLogLine(
|
|
215
|
+
stripVTControlCharacters(line).replace(/\r/g, "")
|
|
216
|
+
);
|
|
217
|
+
const fragments = [];
|
|
218
|
+
let start = 0;
|
|
219
|
+
while (start < text.length) {
|
|
220
|
+
let end = Math.min(start + MCP_LOG_LINE_LIMIT, text.length);
|
|
221
|
+
const lastCodeUnit = text.charCodeAt(end - 1);
|
|
222
|
+
if (end < text.length && lastCodeUnit >= 55296 && lastCodeUnit <= 56319) {
|
|
223
|
+
end -= 1;
|
|
224
|
+
}
|
|
225
|
+
fragments.push(redactMcpJobLog(text.slice(start, end)));
|
|
226
|
+
start = end;
|
|
227
|
+
}
|
|
228
|
+
return fragments.join("\n") + "\n";
|
|
229
|
+
};
|
|
209
230
|
var readMcpJobLogs = async (principal, id, offset = 0, limit = 50) => {
|
|
210
231
|
if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
211
232
|
throw new Error("Select a non-negative log offset and a limit of 1\u2013100");
|
|
@@ -667,6 +688,7 @@ export {
|
|
|
667
688
|
McpCursorError,
|
|
668
689
|
cancelMcpJob,
|
|
669
690
|
enqueueMcpJob,
|
|
691
|
+
formatMcpArtifactLogLine,
|
|
670
692
|
isMcpRecord,
|
|
671
693
|
mcpId,
|
|
672
694
|
mcpJobDirectory,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as _tradejs_types from '@tradejs/types';
|
|
2
|
+
import { PortfolioPolicyConfig, PortfolioStateStore, PortfolioCloseIntent, PortfolioReservation, PortfolioObservation, PortfolioPosition } from '@tradejs/types';
|
|
3
|
+
|
|
4
|
+
interface PortfolioExecutionAdapter {
|
|
5
|
+
/** Idempotent bookkeeping, before removing a confirmed close intent from durable state. */
|
|
6
|
+
confirmClosed?(intent: PortfolioCloseIntent, asOf: number): Promise<void>;
|
|
7
|
+
observe(asOf: number, reservations: readonly PortfolioReservation[]): Promise<PortfolioObservation>;
|
|
8
|
+
close(position: PortfolioPosition, intent: PortfolioCloseIntent, asOf: number): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/** Shared by runtime and replay. IO is behind observation, execution and CAS storage. */
|
|
11
|
+
declare function createPortfolioCoordinator({ policy, strategy, store, execution, }: {
|
|
12
|
+
policy: PortfolioPolicyConfig;
|
|
13
|
+
strategy: string;
|
|
14
|
+
store: PortfolioStateStore;
|
|
15
|
+
execution: PortfolioExecutionAdapter;
|
|
16
|
+
}): {
|
|
17
|
+
context(now: number): Promise<_tradejs_types.PortfolioContext>;
|
|
18
|
+
tick: (now: number, force?: boolean) => Promise<_tradejs_types.PortfolioContext>;
|
|
19
|
+
submit<T>(now: number, entry: Omit<PortfolioReservation, "submitted" | "oppositeHandled">, send: (markSubmitted: (qty: number) => Promise<void>, markRejected: () => Promise<void>) => Promise<T>): Promise<{
|
|
20
|
+
reason?: string;
|
|
21
|
+
value?: T;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
type PortfolioCoordinator = ReturnType<typeof createPortfolioCoordinator>;
|
|
25
|
+
/** Isolated per replay session, never a global registry. */
|
|
26
|
+
declare function createMemoryPortfolioStore(): PortfolioStateStore;
|
|
27
|
+
|
|
28
|
+
export { type PortfolioCoordinator, type PortfolioExecutionAdapter, createMemoryPortfolioStore, createPortfolioCoordinator };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as _tradejs_types from '@tradejs/types';
|
|
2
|
+
import { PortfolioPolicyConfig, PortfolioStateStore, PortfolioCloseIntent, PortfolioReservation, PortfolioObservation, PortfolioPosition } from '@tradejs/types';
|
|
3
|
+
|
|
4
|
+
interface PortfolioExecutionAdapter {
|
|
5
|
+
/** Idempotent bookkeeping, before removing a confirmed close intent from durable state. */
|
|
6
|
+
confirmClosed?(intent: PortfolioCloseIntent, asOf: number): Promise<void>;
|
|
7
|
+
observe(asOf: number, reservations: readonly PortfolioReservation[]): Promise<PortfolioObservation>;
|
|
8
|
+
close(position: PortfolioPosition, intent: PortfolioCloseIntent, asOf: number): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/** Shared by runtime and replay. IO is behind observation, execution and CAS storage. */
|
|
11
|
+
declare function createPortfolioCoordinator({ policy, strategy, store, execution, }: {
|
|
12
|
+
policy: PortfolioPolicyConfig;
|
|
13
|
+
strategy: string;
|
|
14
|
+
store: PortfolioStateStore;
|
|
15
|
+
execution: PortfolioExecutionAdapter;
|
|
16
|
+
}): {
|
|
17
|
+
context(now: number): Promise<_tradejs_types.PortfolioContext>;
|
|
18
|
+
tick: (now: number, force?: boolean) => Promise<_tradejs_types.PortfolioContext>;
|
|
19
|
+
submit<T>(now: number, entry: Omit<PortfolioReservation, "submitted" | "oppositeHandled">, send: (markSubmitted: (qty: number) => Promise<void>, markRejected: () => Promise<void>) => Promise<T>): Promise<{
|
|
20
|
+
reason?: string;
|
|
21
|
+
value?: T;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
type PortfolioCoordinator = ReturnType<typeof createPortfolioCoordinator>;
|
|
25
|
+
/** Isolated per replay session, never a global registry. */
|
|
26
|
+
declare function createMemoryPortfolioStore(): PortfolioStateStore;
|
|
27
|
+
|
|
28
|
+
export { type PortfolioCoordinator, type PortfolioExecutionAdapter, createMemoryPortfolioStore, createPortfolioCoordinator };
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/portfolio.ts
|
|
21
|
+
var portfolio_exports = {};
|
|
22
|
+
__export(portfolio_exports, {
|
|
23
|
+
createMemoryPortfolioStore: () => createMemoryPortfolioStore,
|
|
24
|
+
createPortfolioCoordinator: () => createPortfolioCoordinator
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(portfolio_exports);
|
|
27
|
+
var import_portfolio = require("@tradejs/core/portfolio");
|
|
28
|
+
function createPortfolioCoordinator({
|
|
29
|
+
policy,
|
|
30
|
+
strategy,
|
|
31
|
+
store,
|
|
32
|
+
execution
|
|
33
|
+
}) {
|
|
34
|
+
const fingerprint = (0, import_portfolio.portfolioFingerprint)(policy, strategy);
|
|
35
|
+
let cache;
|
|
36
|
+
async function transact(now, change, force = false) {
|
|
37
|
+
for (let attempt = 0; attempt < 16; attempt++) {
|
|
38
|
+
const previous = await store.read();
|
|
39
|
+
if (previous && previous.fingerprint !== fingerprint)
|
|
40
|
+
throw new Error(
|
|
41
|
+
"Portfolio policy changed under existing state; reconcile the persisted scope before changing configuration"
|
|
42
|
+
);
|
|
43
|
+
const base = previous ?? (0, import_portfolio.createPortfolioState)(fingerprint);
|
|
44
|
+
const bucket = Math.floor(now / policy.observationIntervalMs);
|
|
45
|
+
const observation = !force && cache?.revision === base.revision && cache.bucket === bucket ? cache.observation : await execution.observe(now, base.reservations);
|
|
46
|
+
const reconciled = (0, import_portfolio.reconcilePortfolio)(
|
|
47
|
+
policy,
|
|
48
|
+
strategy,
|
|
49
|
+
base,
|
|
50
|
+
observation
|
|
51
|
+
);
|
|
52
|
+
for (const intent of base.closing) {
|
|
53
|
+
if (!observation.positions.some(
|
|
54
|
+
(p) => p.symbol === intent.position.symbol
|
|
55
|
+
))
|
|
56
|
+
await execution.confirmClosed?.(intent, observation.asOf);
|
|
57
|
+
}
|
|
58
|
+
const changed = change(reconciled, observation);
|
|
59
|
+
const next = { ...changed.state, revision: base.revision + 1 };
|
|
60
|
+
if (await store.compare(previous, next)) {
|
|
61
|
+
cache = { revision: next.revision, bucket, observation };
|
|
62
|
+
return { state: next, observation, result: changed.result };
|
|
63
|
+
}
|
|
64
|
+
cache = void 0;
|
|
65
|
+
}
|
|
66
|
+
throw new Error("Portfolio state contention; entry was not submitted");
|
|
67
|
+
}
|
|
68
|
+
async function tick(now, force = false) {
|
|
69
|
+
const claimed = await transact(
|
|
70
|
+
now,
|
|
71
|
+
(state, observation) => {
|
|
72
|
+
const commands = (0, import_portfolio.portfolioCloseCommands)(policy, state, observation);
|
|
73
|
+
return {
|
|
74
|
+
state: {
|
|
75
|
+
...state,
|
|
76
|
+
closing: state.closing.map(
|
|
77
|
+
(c) => commands.some((x) => x.intent.positionId === c.positionId) ? { ...c, lastAttemptAt: observation.asOf } : c
|
|
78
|
+
)
|
|
79
|
+
},
|
|
80
|
+
result: commands
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
force
|
|
84
|
+
);
|
|
85
|
+
for (const command of claimed.result)
|
|
86
|
+
await execution.close(
|
|
87
|
+
command.position,
|
|
88
|
+
command.intent,
|
|
89
|
+
claimed.observation.asOf
|
|
90
|
+
);
|
|
91
|
+
if (claimed.result.length) {
|
|
92
|
+
cache = void 0;
|
|
93
|
+
const refreshed = await transact(
|
|
94
|
+
now,
|
|
95
|
+
(state) => ({ state, result: void 0 }),
|
|
96
|
+
true
|
|
97
|
+
);
|
|
98
|
+
return (0, import_portfolio.buildPortfolioContext)(
|
|
99
|
+
policy,
|
|
100
|
+
strategy,
|
|
101
|
+
refreshed.state,
|
|
102
|
+
refreshed.observation
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return (0, import_portfolio.buildPortfolioContext)(
|
|
106
|
+
policy,
|
|
107
|
+
strategy,
|
|
108
|
+
claimed.state,
|
|
109
|
+
claimed.observation
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
async function updateReservation(now, id, submitted, qty) {
|
|
113
|
+
return transact(
|
|
114
|
+
now,
|
|
115
|
+
(s, o) => {
|
|
116
|
+
const exists = s.reservations.some((r) => r.id === id);
|
|
117
|
+
const blocked = submitted && (!exists || s.closing.length > 0 || o.asOf <= s.blockedThrough);
|
|
118
|
+
return {
|
|
119
|
+
state: {
|
|
120
|
+
...s,
|
|
121
|
+
reservations: s.reservations.flatMap(
|
|
122
|
+
(r) => r.id !== id ? [r] : submitted && !blocked ? [{ ...r, submitted: true, qty: qty ?? r.qty }] : []
|
|
123
|
+
)
|
|
124
|
+
},
|
|
125
|
+
result: !blocked
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
true
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
async context(now) {
|
|
133
|
+
const state = await store.read() ?? (0, import_portfolio.createPortfolioState)(fingerprint);
|
|
134
|
+
if (state.fingerprint !== fingerprint)
|
|
135
|
+
throw new Error("Portfolio policy changed under existing state");
|
|
136
|
+
const observation = await execution.observe(now, state.reservations);
|
|
137
|
+
(0, import_portfolio.validatePortfolioObservation)(observation);
|
|
138
|
+
return (0, import_portfolio.buildPortfolioContext)(policy, strategy, state, observation);
|
|
139
|
+
},
|
|
140
|
+
tick,
|
|
141
|
+
async submit(now, entry, send) {
|
|
142
|
+
await tick(now);
|
|
143
|
+
const admitted = await transact(
|
|
144
|
+
now,
|
|
145
|
+
(s, o) => {
|
|
146
|
+
const r = (0, import_portfolio.reservePortfolioEntry)(policy, strategy, s, o, {
|
|
147
|
+
...entry,
|
|
148
|
+
submitted: false,
|
|
149
|
+
oppositeHandled: false
|
|
150
|
+
});
|
|
151
|
+
return { state: r.state, result: r.reason };
|
|
152
|
+
},
|
|
153
|
+
true
|
|
154
|
+
);
|
|
155
|
+
if (admitted.result) return { reason: admitted.result };
|
|
156
|
+
let submitted = false;
|
|
157
|
+
try {
|
|
158
|
+
const value = await send(
|
|
159
|
+
async (qty) => {
|
|
160
|
+
if (!Number.isFinite(qty) || qty <= 0)
|
|
161
|
+
throw new Error("Invalid submitted portfolio quantity");
|
|
162
|
+
submitted = true;
|
|
163
|
+
const update = await updateReservation(now, entry.id, true, qty);
|
|
164
|
+
if (!update.result)
|
|
165
|
+
throw new Error("PORTFOLIO_SUBMISSION_NO_LONGER_ADMITTED");
|
|
166
|
+
},
|
|
167
|
+
async () => {
|
|
168
|
+
await transact(
|
|
169
|
+
now,
|
|
170
|
+
(s) => ({
|
|
171
|
+
state: {
|
|
172
|
+
...s,
|
|
173
|
+
reservations: s.reservations.filter((r) => r.id !== entry.id),
|
|
174
|
+
completedSignals: {
|
|
175
|
+
...s.completedSignals,
|
|
176
|
+
[entry.signalId]: now
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
result: void 0
|
|
180
|
+
}),
|
|
181
|
+
true
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
if (!submitted) await updateReservation(now, entry.id, false);
|
|
186
|
+
else await tick(now, true);
|
|
187
|
+
return { value };
|
|
188
|
+
} catch (error) {
|
|
189
|
+
if (!submitted) await updateReservation(now, entry.id, false);
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function createMemoryPortfolioStore() {
|
|
196
|
+
let state = null;
|
|
197
|
+
return {
|
|
198
|
+
read: async () => state === null ? null : structuredClone(state),
|
|
199
|
+
compare: async (expected, next) => {
|
|
200
|
+
if ((state?.revision ?? -1) !== (expected?.revision ?? -1)) return false;
|
|
201
|
+
state = structuredClone(next);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
207
|
+
0 && (module.exports = {
|
|
208
|
+
createMemoryPortfolioStore,
|
|
209
|
+
createPortfolioCoordinator
|
|
210
|
+
});
|