mirror of
https://github.com/multipleof4/KalBot.git
synced 2026-03-16 21:41:02 +00:00
Fix: Skip empty events and pick tradable market
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { getActiveBTCEvent, getEventMarkets, getOrderbook, getMarket } from '../kalshi/rest.js';
|
||||
import { getActiveBTCEvents, getEventMarkets, getOrderbook, getMarket } from '../kalshi/rest.js';
|
||||
import { KalshiWS } from '../kalshi/websocket.js';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
const OPEN_MARKET_STATUSES = new Set(['open', 'active', 'initialized', 'trading']);
|
||||
const TRADABLE_MARKET_STATUSES = new Set(['open', 'active', 'trading']);
|
||||
|
||||
/**
|
||||
* Tracks the currently active BTC 15-min market.
|
||||
@@ -79,35 +80,95 @@ export class MarketTracker extends EventEmitter {
|
||||
};
|
||||
}
|
||||
|
||||
_toTs(value) {
|
||||
if (!value) return null;
|
||||
const ts = new Date(value).getTime();
|
||||
return Number.isFinite(ts) ? ts : null;
|
||||
}
|
||||
|
||||
_pickBestMarket(markets = []) {
|
||||
const now = Date.now();
|
||||
|
||||
const ranked = markets
|
||||
.filter(Boolean)
|
||||
.map((market) => {
|
||||
const status = String(market?.status || '').toLowerCase();
|
||||
const closeTs =
|
||||
this._toTs(market?.close_time) ||
|
||||
this._toTs(market?.expiration_time) ||
|
||||
this._toTs(market?.settlement_time) ||
|
||||
null;
|
||||
|
||||
const tradable = TRADABLE_MARKET_STATUSES.has(status);
|
||||
const openLike = OPEN_MARKET_STATUSES.has(status);
|
||||
const notClearlyExpired = closeTs == null || closeTs > now - 60_000;
|
||||
|
||||
return { market, tradable, openLike, notClearlyExpired, closeTs };
|
||||
})
|
||||
.filter((x) => x.openLike || x.notClearlyExpired);
|
||||
|
||||
if (!ranked.length) return markets[0] || null;
|
||||
|
||||
ranked.sort((a, b) => {
|
||||
if (a.tradable !== b.tradable) return a.tradable ? -1 : 1;
|
||||
if (a.openLike !== b.openLike) return a.openLike ? -1 : 1;
|
||||
if (a.notClearlyExpired !== b.notClearlyExpired) return a.notClearlyExpired ? -1 : 1;
|
||||
const aTs = a.closeTs ?? Number.MAX_SAFE_INTEGER;
|
||||
const bTs = b.closeTs ?? Number.MAX_SAFE_INTEGER;
|
||||
return aTs - bTs;
|
||||
});
|
||||
|
||||
return ranked[0].market;
|
||||
}
|
||||
|
||||
async _findAndSubscribe() {
|
||||
try {
|
||||
const event = await getActiveBTCEvent();
|
||||
const candidates = await getActiveBTCEvents(12);
|
||||
|
||||
if (!event) {
|
||||
if (!candidates.length) {
|
||||
if (!this.currentTicker) this.emit('update', null);
|
||||
console.log('[Tracker] No active BTC 15m event found. Retrying in 30s...');
|
||||
return;
|
||||
}
|
||||
|
||||
const inlineMarkets = Array.isArray(event.markets) ? event.markets : [];
|
||||
const markets = inlineMarkets.length ? inlineMarkets : await getEventMarkets(event.event_ticker);
|
||||
let selectedEvent = null;
|
||||
let selectedMarket = null;
|
||||
|
||||
const market = markets.find((m) => OPEN_MARKET_STATUSES.has(String(m?.status || '').toLowerCase())) || markets[0];
|
||||
for (const event of candidates) {
|
||||
const eventTicker = event?.event_ticker;
|
||||
if (!eventTicker) continue;
|
||||
|
||||
if (!market) {
|
||||
if (!this.currentTicker) {
|
||||
this.currentEvent = event.event_ticker || null;
|
||||
this.marketData = null;
|
||||
this.orderbook = { yes: [], no: [] };
|
||||
this.emit('update', null);
|
||||
let markets = Array.isArray(event.markets) ? event.markets : [];
|
||||
if (!markets.length) {
|
||||
try {
|
||||
markets = await getEventMarkets(eventTicker);
|
||||
} catch (e) {
|
||||
console.error(`[Tracker] Failed loading markets for ${eventTicker}:`, e.message);
|
||||
continue;
|
||||
}
|
||||
console.log(`[Tracker] Event ${event.event_ticker} has no active market yet. Retrying...`);
|
||||
}
|
||||
|
||||
if (!markets.length) continue;
|
||||
|
||||
const market = this._pickBestMarket(markets);
|
||||
if (!market?.ticker) continue;
|
||||
|
||||
selectedEvent = event;
|
||||
selectedMarket = market;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!selectedEvent || !selectedMarket) {
|
||||
if (!this.currentTicker) this.emit('update', null);
|
||||
console.log('[Tracker] No tradable BTC 15m market found yet. Retrying...');
|
||||
return;
|
||||
}
|
||||
|
||||
const newTicker = market.ticker;
|
||||
const newTicker = selectedMarket.ticker;
|
||||
if (newTicker === this.currentTicker) {
|
||||
this.currentEvent = event.event_ticker;
|
||||
this.currentEvent = selectedEvent.event_ticker || this.currentEvent;
|
||||
this.marketData = { ...(this.marketData || {}), ...selectedMarket };
|
||||
this.emit('update', this.getState());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,8 +181,8 @@ export class MarketTracker extends EventEmitter {
|
||||
}
|
||||
|
||||
this.currentTicker = newTicker;
|
||||
this.currentEvent = event.event_ticker;
|
||||
this.marketData = market;
|
||||
this.currentEvent = selectedEvent.event_ticker;
|
||||
this.marketData = selectedMarket;
|
||||
this.orderbook = { yes: [], no: [] };
|
||||
|
||||
// Fetch fresh orderbook via REST
|
||||
@@ -134,7 +195,7 @@ export class MarketTracker extends EventEmitter {
|
||||
|
||||
// Subscribe via WS
|
||||
this.ws.subscribeTicker(newTicker);
|
||||
console.log(`[Tracker] Now tracking: ${newTicker} (${market.title || market.subtitle})`);
|
||||
console.log(`[Tracker] Now tracking: ${newTicker} (${selectedMarket.title || selectedMarket.subtitle || selectedEvent.event_ticker})`);
|
||||
|
||||
this.emit('update', this.getState());
|
||||
this.emit('market-rotated', { from: oldTicker, to: newTicker });
|
||||
@@ -153,8 +214,11 @@ export class MarketTracker extends EventEmitter {
|
||||
const state = this.getState();
|
||||
this.emit('update', state);
|
||||
|
||||
const status = String(fresh?.status || '').toLowerCase();
|
||||
const settledLike = status === 'closed' || status === 'settled' || status === 'expired' || status === 'finalized';
|
||||
|
||||
// If market closed/settled, find the next one
|
||||
if (fresh.status === 'closed' || fresh.status === 'settled' || fresh.result) {
|
||||
if (settledLike || fresh.result) {
|
||||
console.log(`[Tracker] Market ${this.currentTicker} settled (result: ${fresh.result}). Rotating...`);
|
||||
this.emit('settled', { ticker: this.currentTicker, result: fresh.result });
|
||||
this.currentTicker = null;
|
||||
|
||||
Reference in New Issue
Block a user