tradeblocks-mcp 4.2.0 → 4.3.0
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/README.md +40 -1
- package/dist/{chunk-YRD62LDE.js → chunk-35RVWZGT.js} +4 -1
- package/dist/{chunk-4UU7IT2A.js.map → chunk-35RVWZGT.js.map} +1 -1
- package/dist/{chunk-4UU7IT2A.js → chunk-ENXBPJ7Y.js} +148 -6
- package/dist/chunk-ENXBPJ7Y.js.map +1 -0
- package/dist/{chunk-62GCLMQA.js → chunk-TLX7IBCM.js} +3 -6
- package/dist/chunk-TLX7IBCM.js.map +1 -0
- package/dist/{daily-logs-store-PXB53WEK.js → daily-logs-store-FZRIGYUX.js} +2 -2
- package/dist/{daily-logs-store-65YHFJ5F.js → daily-logs-store-MEZ5S3BR.js} +2 -2
- package/dist/market/provenance/index.js +1 -4
- package/dist/market/provenance/index.js.map +1 -1
- package/dist/{sync-JL7OPLCT.js → sync-EW33QZPD.js} +3 -3
- package/dist/test-exports.js +320 -279
- package/dist/test-exports.js.map +1 -1
- package/dist/{trades-store-UGZ62A7N.js → trades-store-3TOLBL2W.js} +2 -2
- package/dist/{trades-store-MOFJHRC2.js → trades-store-PNLPRYRJ.js} +2 -2
- package/package.json +1 -1
- package/server/{chunk-7N6HBOAY.js → chunk-PDSUY2X2.js} +148 -6
- package/server/chunk-PDSUY2X2.js.map +1 -0
- package/server/{chunk-J4GWE6JR.js → chunk-YIWLVX7Z.js} +3 -6
- package/server/chunk-YIWLVX7Z.js.map +1 -0
- package/server/{daily-logs-store-YAXASQN4.js → daily-logs-store-LRVO7COL.js} +2 -2
- package/server/index.js +993 -801
- package/server/index.js.map +1 -1
- package/server/{sync-ZV3QEGMO.js → sync-2POG6KA6.js} +3 -3
- package/server/{trades-store-MF7YYLCH.js → trades-store-MXUZLSF5.js} +2 -2
- package/src/db/dataset-schemas.ts +97 -23
- package/src/tools/market-data.ts +327 -245
- package/src/tools/profile-analysis.ts +18 -4
- package/src/tools/reports/fields.ts +16 -11
- package/src/tools/reports/helpers.ts +6 -2
- package/src/tools/reports/predictive.ts +15 -4
- package/src/tools/shared/field-analysis.ts +57 -14
- package/src/tools/shared/filter-objective.ts +73 -0
- package/src/utils/trade-analysis-fields.ts +19 -4
- package/dist/chunk-62GCLMQA.js.map +0 -1
- package/dist/chunk-YRD62LDE.js.map +0 -1
- package/server/chunk-7N6HBOAY.js.map +0 -1
- package/server/chunk-J4GWE6JR.js.map +0 -1
- /package/dist/{daily-logs-store-65YHFJ5F.js.map → daily-logs-store-FZRIGYUX.js.map} +0 -0
- /package/dist/{daily-logs-store-PXB53WEK.js.map → daily-logs-store-MEZ5S3BR.js.map} +0 -0
- /package/dist/{sync-JL7OPLCT.js.map → sync-EW33QZPD.js.map} +0 -0
- /package/dist/{trades-store-MOFJHRC2.js.map → trades-store-3TOLBL2W.js.map} +0 -0
- /package/dist/{trades-store-UGZ62A7N.js.map → trades-store-PNLPRYRJ.js.map} +0 -0
- /package/server/{daily-logs-store-YAXASQN4.js.map → daily-logs-store-LRVO7COL.js.map} +0 -0
- /package/server/{sync-ZV3QEGMO.js.map → sync-2POG6KA6.js.map} +0 -0
- /package/server/{trades-store-MF7YYLCH.js.map → trades-store-MXUZLSF5.js.map} +0 -0
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
syncAllBlocks,
|
|
10
10
|
syncBlock,
|
|
11
11
|
upsertSyncMetadata
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YIWLVX7Z.js";
|
|
13
13
|
import "./chunk-76OEJGQX.js";
|
|
14
14
|
import "./chunk-NLYLE5C6.js";
|
|
15
15
|
import "./chunk-24O66TM5.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-PDSUY2X2.js";
|
|
17
17
|
import "./chunk-2E3K452Q.js";
|
|
18
18
|
import "./chunk-UT3JLF3M.js";
|
|
19
19
|
export {
|
|
@@ -27,4 +27,4 @@ export {
|
|
|
27
27
|
syncBlock,
|
|
28
28
|
upsertSyncMetadata
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=sync-
|
|
30
|
+
//# sourceMappingURL=sync-2POG6KA6.js.map
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
getTradesPage,
|
|
13
13
|
searchTrades,
|
|
14
14
|
updateTradesForBlock
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-PDSUY2X2.js";
|
|
16
16
|
import "./chunk-2E3K452Q.js";
|
|
17
17
|
import "./chunk-UT3JLF3M.js";
|
|
18
18
|
export {
|
|
@@ -29,4 +29,4 @@ export {
|
|
|
29
29
|
searchTrades,
|
|
30
30
|
updateTradesForBlock
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=trades-store-
|
|
32
|
+
//# sourceMappingURL=trades-store-MXUZLSF5.js.map
|
|
@@ -8,6 +8,16 @@ import {
|
|
|
8
8
|
} from "@tradeblocks/lib";
|
|
9
9
|
import { OPEN_KNOWN_FIELDS, CLOSE_KNOWN_FIELDS, STATIC_FIELDS } from "../utils/field-timing.ts";
|
|
10
10
|
import { resolveTradeTicker } from "../utils/ticker.ts";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
export const maxMissedSessionsSchema = z
|
|
14
|
+
.number()
|
|
15
|
+
.int()
|
|
16
|
+
.nonnegative()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe(
|
|
19
|
+
"Opt-in maximum missed XNYS sessions for dataset values. No limit when omitted. Unsupported calendar ages (outside 2022–2030) are refused when a limit is set.",
|
|
20
|
+
);
|
|
11
21
|
|
|
12
22
|
export async function ensureDatasetsSchema(conn: DuckDBConnection): Promise<void> {
|
|
13
23
|
await conn.run("CREATE SCHEMA IF NOT EXISTS datasets");
|
|
@@ -127,7 +137,7 @@ export function datasetFields(entries: StoredDataset[]): AnalysisField[] {
|
|
|
127
137
|
? "numeric"
|
|
128
138
|
: "categorical",
|
|
129
139
|
timing: dataset.columnTiming![column],
|
|
130
|
-
knownBy: dataset.knownBy ?? null,
|
|
140
|
+
knownBy: dataset.columnTiming![column] === "open" ? (dataset.knownBy ?? null) : null,
|
|
131
141
|
source,
|
|
132
142
|
})),
|
|
133
143
|
);
|
|
@@ -149,31 +159,49 @@ export async function runtimeFieldCatalog(conn: DuckDBConnection): Promise<Analy
|
|
|
149
159
|
];
|
|
150
160
|
}
|
|
151
161
|
|
|
152
|
-
export
|
|
162
|
+
export interface DatasetProvenance {
|
|
163
|
+
sourceTimestamp: string;
|
|
164
|
+
availableAt: string;
|
|
165
|
+
sessionAge: number | "unsupported";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function resolveTradeDatasets(
|
|
169
|
+
entries: StoredDataset[],
|
|
170
|
+
trade: Trade,
|
|
171
|
+
maxMissedSessions?: number,
|
|
172
|
+
) {
|
|
153
173
|
const values: Record<string, number | string> = {};
|
|
154
|
-
const provenance: Record<string,
|
|
174
|
+
const provenance: Record<string, DatasetProvenance> = {};
|
|
175
|
+
const rejected: Record<string, DatasetProvenance> = {};
|
|
155
176
|
const entryTime = combineDateAndTime(trade.dateOpened, trade.timeOpened);
|
|
156
177
|
for (const { dataset, rows, ticker } of entries) {
|
|
157
178
|
if (ticker && ticker !== resolveTradeTicker(trade)) continue;
|
|
158
179
|
for (const column of dataset.columns) {
|
|
159
|
-
const match = resolveDatasetColumnAtTime(dataset, rows, column, entryTime);
|
|
180
|
+
const match = resolveDatasetColumnAtTime(dataset, rows, column, entryTime, maxMissedSessions);
|
|
160
181
|
if (!match) continue;
|
|
161
182
|
const field = `${dataset.name}.${column}`;
|
|
162
|
-
values[field] = match.value;
|
|
163
|
-
provenance[field] = {
|
|
183
|
+
if (match.accepted) values[field] = match.value;
|
|
184
|
+
(match.accepted ? provenance : rejected)[field] = {
|
|
164
185
|
sourceTimestamp: match.row.timestamp.toISOString(),
|
|
165
186
|
availableAt: match.availableAt.toISOString(),
|
|
187
|
+
sessionAge: match.sessionAge,
|
|
166
188
|
};
|
|
167
189
|
}
|
|
168
190
|
}
|
|
169
|
-
return { values, provenance };
|
|
191
|
+
return { values, provenance, rejected };
|
|
170
192
|
}
|
|
171
193
|
|
|
172
194
|
export interface DatasetFieldAge {
|
|
173
195
|
attachments: number;
|
|
174
|
-
medianAgeDays: number;
|
|
175
|
-
maxAgeDays: number;
|
|
196
|
+
medianAgeDays: number | null;
|
|
197
|
+
maxAgeDays: number | null;
|
|
176
198
|
olderThan3Days: number;
|
|
199
|
+
sessionAgeStatus: "supported" | "unsupported";
|
|
200
|
+
medianAgeSessions: number | null;
|
|
201
|
+
maxAgeSessions: number | null;
|
|
202
|
+
staleAttachments: number;
|
|
203
|
+
unsupportedSessionAge: number;
|
|
204
|
+
rejectedAttachments: number;
|
|
177
205
|
}
|
|
178
206
|
|
|
179
207
|
const easternCalendar = new Intl.DateTimeFormat("en-US", {
|
|
@@ -194,34 +222,61 @@ function easternDayNumber(date: Date): number {
|
|
|
194
222
|
);
|
|
195
223
|
}
|
|
196
224
|
|
|
197
|
-
/**
|
|
225
|
+
/** Session ages come only from the shared resolver's selected source provenance. */
|
|
198
226
|
export function summarizeDatasetAge(
|
|
199
227
|
trades: Trade[],
|
|
200
|
-
matches: {
|
|
228
|
+
matches: {
|
|
229
|
+
provenance: Record<string, { sourceTimestamp: string; sessionAge?: number | "unsupported" }>;
|
|
230
|
+
rejected?: Record<string, DatasetProvenance>;
|
|
231
|
+
}[],
|
|
201
232
|
): Record<string, DatasetFieldAge> {
|
|
202
|
-
const ages = new Map<
|
|
233
|
+
const ages = new Map<
|
|
234
|
+
string,
|
|
235
|
+
{ days: number[]; sessions: number[]; unsupported: number; rejected: number }
|
|
236
|
+
>();
|
|
203
237
|
for (let i = 0; i < trades.length; i++) {
|
|
204
238
|
const entryDay = easternDayNumber(
|
|
205
239
|
combineDateAndTime(trades[i].dateOpened, trades[i].timeOpened),
|
|
206
240
|
);
|
|
207
|
-
for (const [field, provenance] of Object.entries(
|
|
208
|
-
|
|
209
|
-
|
|
241
|
+
for (const [field, provenance] of Object.entries({
|
|
242
|
+
...matches[i].provenance,
|
|
243
|
+
...matches[i].rejected,
|
|
244
|
+
})) {
|
|
245
|
+
const samples = ages.get(field) ?? { days: [], sessions: [], unsupported: 0, rejected: 0 };
|
|
246
|
+
if (matches[i].rejected?.[field]) samples.rejected++;
|
|
247
|
+
else samples.days.push(entryDay - easternDayNumber(new Date(provenance.sourceTimestamp)));
|
|
248
|
+
if (typeof provenance.sessionAge === "number") samples.sessions.push(provenance.sessionAge);
|
|
249
|
+
else samples.unsupported++;
|
|
210
250
|
ages.set(field, samples);
|
|
211
251
|
}
|
|
212
252
|
}
|
|
213
253
|
return Object.fromEntries(
|
|
214
254
|
[...ages].map(([field, samples]) => {
|
|
215
|
-
samples.sort((a, b) => a - b);
|
|
216
|
-
const
|
|
255
|
+
const days = samples.days.sort((a, b) => a - b);
|
|
256
|
+
const sessions = samples.sessions.sort((a, b) => a - b);
|
|
257
|
+
const middle = Math.floor(days.length / 2);
|
|
258
|
+
const sessionMiddle = Math.floor(sessions.length / 2);
|
|
217
259
|
return [
|
|
218
260
|
field,
|
|
219
261
|
{
|
|
220
|
-
attachments:
|
|
221
|
-
medianAgeDays:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
262
|
+
attachments: days.length,
|
|
263
|
+
medianAgeDays: !days.length
|
|
264
|
+
? null
|
|
265
|
+
: days.length % 2
|
|
266
|
+
? days[middle]
|
|
267
|
+
: (days[middle - 1] + days[middle]) / 2,
|
|
268
|
+
maxAgeDays: days.length ? days[days.length - 1] : null,
|
|
269
|
+
olderThan3Days: days.filter((age) => age > 3).length,
|
|
270
|
+
sessionAgeStatus: samples.unsupported ? ("unsupported" as const) : ("supported" as const),
|
|
271
|
+
medianAgeSessions: !sessions.length
|
|
272
|
+
? null
|
|
273
|
+
: sessions.length % 2
|
|
274
|
+
? sessions[sessionMiddle]
|
|
275
|
+
: (sessions[sessionMiddle - 1] + sessions[sessionMiddle]) / 2,
|
|
276
|
+
maxAgeSessions: sessions.length ? sessions[sessions.length - 1] : null,
|
|
277
|
+
staleAttachments: sessions.filter((age) => age >= 1).length,
|
|
278
|
+
unsupportedSessionAge: samples.unsupported,
|
|
279
|
+
rejectedAttachments: samples.rejected,
|
|
225
280
|
},
|
|
226
281
|
];
|
|
227
282
|
}),
|
|
@@ -232,5 +287,24 @@ export function datasetAgeOutput(summary: Record<string, DatasetFieldAge>, field
|
|
|
232
287
|
const selected = Object.fromEntries(
|
|
233
288
|
fields.filter((field) => summary[field]).map((field) => [field, summary[field]]),
|
|
234
289
|
);
|
|
235
|
-
|
|
290
|
+
const datasetWarnings = Object.entries(selected).flatMap(([field, age]) => [
|
|
291
|
+
...(age.staleAttachments
|
|
292
|
+
? [
|
|
293
|
+
`${field}: ${age.staleAttachments} candidate attachments missed at least one expected XNYS session.`,
|
|
294
|
+
]
|
|
295
|
+
: []),
|
|
296
|
+
...(age.unsupportedSessionAge
|
|
297
|
+
? [
|
|
298
|
+
`${field}: session age unsupported for ${age.unsupportedSessionAge} candidate attachments outside XNYS calendar 2022–2030.`,
|
|
299
|
+
]
|
|
300
|
+
: []),
|
|
301
|
+
...(age.rejectedAttachments
|
|
302
|
+
? [
|
|
303
|
+
`${field}: ${age.rejectedAttachments} attachments refused by maxMissedSessions; counted as uncovered.`,
|
|
304
|
+
]
|
|
305
|
+
: []),
|
|
306
|
+
]);
|
|
307
|
+
return Object.keys(selected).length
|
|
308
|
+
? { datasetAge: selected, ...(datasetWarnings.length ? { datasetWarnings } : {}) }
|
|
309
|
+
: {};
|
|
236
310
|
}
|