tradeblocks-mcp 2.2.0-beta.7 → 2.2.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/dist/test-exports.js +144 -1
- package/dist/test-exports.js.map +1 -1
- package/package.json +2 -2
- package/server/index.js +141 -1
- package/server/index.js.map +1 -1
package/dist/test-exports.js
CHANGED
|
@@ -1740,6 +1740,21 @@ var MassiveAggregateResponseSchema = z.object({
|
|
|
1740
1740
|
request_id: z.string(),
|
|
1741
1741
|
next_url: z.string().optional()
|
|
1742
1742
|
});
|
|
1743
|
+
var MassiveQuoteSchema = z.object({
|
|
1744
|
+
bid_price: z.number(),
|
|
1745
|
+
ask_price: z.number(),
|
|
1746
|
+
sip_timestamp: z.number(),
|
|
1747
|
+
// nanoseconds
|
|
1748
|
+
bid_size: z.number(),
|
|
1749
|
+
ask_size: z.number(),
|
|
1750
|
+
sequence_number: z.number()
|
|
1751
|
+
});
|
|
1752
|
+
var MassiveQuotesResponseSchema = z.object({
|
|
1753
|
+
status: z.string(),
|
|
1754
|
+
request_id: z.string(),
|
|
1755
|
+
results: z.array(MassiveQuoteSchema).default([]),
|
|
1756
|
+
next_url: z.string().optional()
|
|
1757
|
+
});
|
|
1743
1758
|
var MassiveSnapshotGreeksSchema = z.object({
|
|
1744
1759
|
delta: z.number(),
|
|
1745
1760
|
gamma: z.number(),
|
|
@@ -1830,6 +1845,12 @@ function massiveTimestampToETTime(unixMs) {
|
|
|
1830
1845
|
hour12: false
|
|
1831
1846
|
});
|
|
1832
1847
|
}
|
|
1848
|
+
function nanosToETMinuteKey(nanosTimestamp) {
|
|
1849
|
+
const ms = Math.floor(nanosTimestamp / 1e6);
|
|
1850
|
+
const date = massiveTimestampToETDate(ms);
|
|
1851
|
+
const time = massiveTimestampToETTime(ms);
|
|
1852
|
+
return `${date} ${time}`;
|
|
1853
|
+
}
|
|
1833
1854
|
function getApiKey() {
|
|
1834
1855
|
const key = process.env.MASSIVE_API_KEY;
|
|
1835
1856
|
if (!key) {
|
|
@@ -2030,8 +2051,86 @@ var MassiveProvider = class {
|
|
|
2030
2051
|
url = null;
|
|
2031
2052
|
}
|
|
2032
2053
|
}
|
|
2054
|
+
const quotesEnabled2 = process.env.MASSIVE_QUOTES_ENABLED === "true" || process.env.MASSIVE_QUOTES_ENABLED === "1";
|
|
2055
|
+
if (quotesEnabled2 && assetClass === "option" && timespan !== "day" && allRows.length > 0) {
|
|
2056
|
+
const quotesMap = await this.fetchQuotesForBars(apiTicker, headers, from, to);
|
|
2057
|
+
if (quotesMap.size > 0) {
|
|
2058
|
+
for (const row of allRows) {
|
|
2059
|
+
if (row.time != null) {
|
|
2060
|
+
const key = `${row.date} ${row.time}`;
|
|
2061
|
+
const quote = quotesMap.get(key);
|
|
2062
|
+
if (quote != null) {
|
|
2063
|
+
row.bid = quote.bid;
|
|
2064
|
+
row.ask = quote.ask;
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2033
2070
|
return allRows;
|
|
2034
2071
|
}
|
|
2072
|
+
/**
|
|
2073
|
+
* Fetches historical quotes (bid/ask) for an option ticker over a date range.
|
|
2074
|
+
* Returns a Map keyed by "YYYY-MM-DD HH:MM" ET minute key.
|
|
2075
|
+
* Any error (network, HTTP error, parse failure) silently returns an empty Map.
|
|
2076
|
+
*/
|
|
2077
|
+
async fetchQuotesForBars(apiTicker, headers, from, to) {
|
|
2078
|
+
const result = /* @__PURE__ */ new Map();
|
|
2079
|
+
try {
|
|
2080
|
+
let url = `${MASSIVE_BASE_URL}/v3/quotes/${encodeURIComponent(apiTicker)}?timestamp.gte=${from}×tamp.lte=${to}&order=asc&limit=${MASSIVE_MAX_LIMIT}`;
|
|
2081
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
2082
|
+
const QUOTES_MAX_PAGES = 100;
|
|
2083
|
+
let pageCount = 0;
|
|
2084
|
+
while (url) {
|
|
2085
|
+
pageCount++;
|
|
2086
|
+
if (pageCount > QUOTES_MAX_PAGES) {
|
|
2087
|
+
break;
|
|
2088
|
+
}
|
|
2089
|
+
let response;
|
|
2090
|
+
try {
|
|
2091
|
+
response = await fetch(url, {
|
|
2092
|
+
headers,
|
|
2093
|
+
signal: AbortSignal.timeout(3e4)
|
|
2094
|
+
});
|
|
2095
|
+
} catch {
|
|
2096
|
+
return result;
|
|
2097
|
+
}
|
|
2098
|
+
if (!response.ok) {
|
|
2099
|
+
return result;
|
|
2100
|
+
}
|
|
2101
|
+
const json = await response.json();
|
|
2102
|
+
const parsed = MassiveQuotesResponseSchema.safeParse(json);
|
|
2103
|
+
if (!parsed.success) {
|
|
2104
|
+
return result;
|
|
2105
|
+
}
|
|
2106
|
+
const data = parsed.data;
|
|
2107
|
+
for (const quote of data.results) {
|
|
2108
|
+
const key = nanosToETMinuteKey(quote.sip_timestamp);
|
|
2109
|
+
result.set(key, { bid: quote.bid_price, ask: quote.ask_price });
|
|
2110
|
+
}
|
|
2111
|
+
if (data.next_url) {
|
|
2112
|
+
const nextUrlObj = new URL(data.next_url);
|
|
2113
|
+
const cursor = nextUrlObj.searchParams.get("cursor") ?? data.next_url;
|
|
2114
|
+
if (seenCursors.has(cursor)) {
|
|
2115
|
+
break;
|
|
2116
|
+
}
|
|
2117
|
+
seenCursors.add(cursor);
|
|
2118
|
+
url = data.next_url;
|
|
2119
|
+
} else {
|
|
2120
|
+
url = null;
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
} catch {
|
|
2124
|
+
return /* @__PURE__ */ new Map();
|
|
2125
|
+
}
|
|
2126
|
+
return result;
|
|
2127
|
+
}
|
|
2128
|
+
async fetchQuotes(ticker, from, to) {
|
|
2129
|
+
const apiKey = getApiKey();
|
|
2130
|
+
const apiTicker = toMassiveTicker(ticker, "option");
|
|
2131
|
+
const headers = { Authorization: `Bearer ${apiKey}` };
|
|
2132
|
+
return this.fetchQuotesForBars(apiTicker, headers, from, to);
|
|
2133
|
+
}
|
|
2035
2134
|
async fetchOptionSnapshot(options) {
|
|
2036
2135
|
const apiKey = getApiKey();
|
|
2037
2136
|
const { underlying } = options;
|
|
@@ -4317,6 +4416,9 @@ function computeReplayMfeMae(pnlPath) {
|
|
|
4317
4416
|
import { z as z5 } from "zod";
|
|
4318
4417
|
|
|
4319
4418
|
// src/utils/bar-cache.ts
|
|
4419
|
+
function quotesEnabled() {
|
|
4420
|
+
return process.env.MASSIVE_QUOTES_ENABLED === "true" || process.env.MASSIVE_QUOTES_ENABLED === "1";
|
|
4421
|
+
}
|
|
4320
4422
|
async function fetchBarsWithCache(opts) {
|
|
4321
4423
|
const { ticker, from, to, timespan, assetClass, baseDir } = opts;
|
|
4322
4424
|
try {
|
|
@@ -4332,7 +4434,7 @@ async function fetchBarsWithCache(opts) {
|
|
|
4332
4434
|
);
|
|
4333
4435
|
const rows = cached.getRows();
|
|
4334
4436
|
if (rows.length > 0) {
|
|
4335
|
-
|
|
4437
|
+
const bars2 = rows.map((row) => ({
|
|
4336
4438
|
open: Number(row[0]),
|
|
4337
4439
|
high: Number(row[1]),
|
|
4338
4440
|
low: Number(row[2]),
|
|
@@ -4345,6 +4447,44 @@ async function fetchBarsWithCache(opts) {
|
|
|
4345
4447
|
volume: 0
|
|
4346
4448
|
// market.intraday has no volume column
|
|
4347
4449
|
}));
|
|
4450
|
+
const missingQuotes = assetClass === "option" && quotesEnabled() && bars2.some((b) => b.bid == null && b.ask == null);
|
|
4451
|
+
if (missingQuotes) {
|
|
4452
|
+
try {
|
|
4453
|
+
const provider = getProvider();
|
|
4454
|
+
if (provider.fetchQuotes) {
|
|
4455
|
+
const quotesMap = await provider.fetchQuotes(ticker, from, to);
|
|
4456
|
+
if (quotesMap.size > 0) {
|
|
4457
|
+
const updates = [];
|
|
4458
|
+
for (const bar of bars2) {
|
|
4459
|
+
if (bar.time != null) {
|
|
4460
|
+
const key = `${bar.date} ${bar.time}`;
|
|
4461
|
+
const quote = quotesMap.get(key);
|
|
4462
|
+
if (quote != null) {
|
|
4463
|
+
bar.bid = quote.bid;
|
|
4464
|
+
bar.ask = quote.ask;
|
|
4465
|
+
updates.push(
|
|
4466
|
+
`('${escaped}', '${bar.date}', '${bar.time}', ${quote.bid}, ${quote.ask})`
|
|
4467
|
+
);
|
|
4468
|
+
}
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
4471
|
+
if (updates.length > 0) {
|
|
4472
|
+
const updateConn = opts.conn ?? await getConnection(baseDir ?? ".");
|
|
4473
|
+
for (let i = 0; i < updates.length; i += 500) {
|
|
4474
|
+
const chunk = updates.slice(i, i + 500);
|
|
4475
|
+
await updateConn.run(
|
|
4476
|
+
`UPDATE market.intraday AS m SET bid = v.bid, ask = v.ask
|
|
4477
|
+
FROM (VALUES ${chunk.join(", ")}) AS v(ticker, date, time, bid, ask)
|
|
4478
|
+
WHERE m.ticker = v.ticker AND m.date = v.date AND m.time = v.time`
|
|
4479
|
+
);
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
} catch {
|
|
4485
|
+
}
|
|
4486
|
+
}
|
|
4487
|
+
return bars2;
|
|
4348
4488
|
}
|
|
4349
4489
|
} catch {
|
|
4350
4490
|
}
|
|
@@ -6266,6 +6406,8 @@ export {
|
|
|
6266
6406
|
MassiveAggregateResponseSchema,
|
|
6267
6407
|
MassiveBarSchema,
|
|
6268
6408
|
MassiveProvider,
|
|
6409
|
+
MassiveQuoteSchema,
|
|
6410
|
+
MassiveQuotesResponseSchema,
|
|
6269
6411
|
MassiveSnapshotContractSchema,
|
|
6270
6412
|
MassiveSnapshotResponseSchema,
|
|
6271
6413
|
OPEN_KNOWN_FIELDS,
|
|
@@ -6365,6 +6507,7 @@ export {
|
|
|
6365
6507
|
markPrice,
|
|
6366
6508
|
massiveTimestampToETDate,
|
|
6367
6509
|
massiveTimestampToETTime,
|
|
6510
|
+
nanosToETMinuteKey,
|
|
6368
6511
|
parseLegsString,
|
|
6369
6512
|
pdf,
|
|
6370
6513
|
performTailRiskAnalysis,
|