Fix: robust active event discovery

This commit is contained in:
2026-03-15 14:40:15 -07:00
parent 8c76087b6a
commit 677050a224

View File

@@ -1,5 +1,7 @@
import { signRequest, KALSHI_API_BASE } from './auth.js'; import { signRequest, KALSHI_API_BASE } from './auth.js';
const OPEN_EVENT_STATUSES = new Set(['open', 'active', 'initialized', 'trading']);
async function kalshiFetch(method, path, body = null) { async function kalshiFetch(method, path, body = null) {
const headers = signRequest(method, path); const headers = signRequest(method, path);
const opts = { method, headers }; const opts = { method, headers };
@@ -13,15 +15,78 @@ async function kalshiFetch(method, path, body = null) {
return res.json(); return res.json();
} }
function getTimeMs(value) {
if (!value) return null;
const ts = new Date(value).getTime();
return Number.isFinite(ts) ? ts : null;
}
function getEventCloseTimeMs(event) {
return (
getTimeMs(event?.close_time) ||
getTimeMs(event?.expiration_time) ||
getTimeMs(event?.settlement_time) ||
getTimeMs(event?.end_date) ||
null
);
}
function pickBestEvent(events = []) {
const now = Date.now();
const ranked = events
.filter(Boolean)
.map((event) => {
const status = String(event.status || '').toLowerCase();
const closeTs = getEventCloseTimeMs(event);
const openLike = OPEN_EVENT_STATUSES.has(status);
const notClearlyExpired = closeTs == null || closeTs > now - 60_000;
return { event, openLike, closeTs, notClearlyExpired };
})
.filter((x) => x.openLike || x.notClearlyExpired);
if (!ranked.length) return events[0] || null;
ranked.sort((a, b) => {
if (a.openLike !== b.openLike) return a.openLike ? -1 : 1;
const aTs = a.closeTs ?? Number.MAX_SAFE_INTEGER;
const bTs = b.closeTs ?? Number.MAX_SAFE_INTEGER;
return aTs - bTs;
});
return ranked[0].event;
}
async function fetchEvents(series, query) {
const path = `/trade-api/v2/events?series_ticker=${encodeURIComponent(series)}&${query}`;
const data = await kalshiFetch('GET', path);
return Array.isArray(data.events) ? data.events : [];
}
/** /**
* Get events for the BTC 15-min series. * Get events for the BTC 15-min series.
* Returns the currently active event + its markets. * Returns the currently active event + its markets.
*/ */
export async function getActiveBTCEvent() { export async function getActiveBTCEvent() {
const data = await kalshiFetch('GET', '/trade-api/v2/events?series_ticker=KXBTC15M&status=open&limit=1'); const configuredSeries = process.env.KALSHI_SERIES_TICKER || 'KXBTC15M';
const event = data.events?.[0]; const seriesCandidates = [...new Set([configuredSeries, configuredSeries.toUpperCase(), configuredSeries.toLowerCase()])];
if (!event) return null; const eventMap = new Map();
return event;
for (const series of seriesCandidates) {
for (const query of ['status=open&limit=5', 'limit=25']) {
try {
const events = await fetchEvents(series, query);
for (const event of events) {
if (event?.event_ticker) eventMap.set(event.event_ticker, event);
}
} catch (e) {
console.error(`[Kalshi] Event fetch failed (${series}, ${query}):`, e.message);
}
}
if (eventMap.size) break;
}
return pickBestEvent([...eventMap.values()]);
} }
/** /**