diff --git a/lib/live/engine.js b/lib/live/engine.js index e11f5ec..91f8ddd 100644 --- a/lib/live/engine.js +++ b/lib/live/engine.js @@ -13,7 +13,7 @@ export class LiveEngine { constructor() { this.enabledStrategies = new Set(); this.openOrders = new Map(); - this.recentFills = []; + this.recentFills =[]; this.totalPnL = 0; this.wins = 0; this.losses = 0; @@ -25,7 +25,7 @@ export class LiveEngine { this._dailyLossResetTime = Date.now(); this._lastBalance = null; this._lastPortfolioValue = null; - this._positions = []; + this._positions =[]; } async init() { @@ -48,7 +48,7 @@ export class LiveEngine { const orders = await db.query( 'SELECT * FROM live_orders WHERE status = "pending" OR status = "resting"' ); - for (const o of (orders[0] || [])) { + for (const o of (orders[0] ||[])) { this.openOrders.set(o.orderId, o); } if (this.openOrders.size) { @@ -115,8 +115,8 @@ export class LiveEngine { 'GET', '/trade-api/v2/portfolio/positions?settlement_status=unsettled&limit=200' ); - const positions = data?.market_positions || data?.positions || []; - this._positions = Array.isArray(positions) ? positions : []; + const positions = data?.market_positions || data?.positions ||[]; + this._positions = Array.isArray(positions) ? positions :[]; return this._positions; } catch (e) { console.error('[Live] Positions fetch error:', e.message); @@ -124,11 +124,6 @@ export class LiveEngine { } } - /** - * Determine the best executable price from the orderbook. - * For buying yes: best ask = 100 - best_no_bid (or lowest yes offer) - * For buying no: best ask = 100 - best_yes_bid (or lowest no offer) - */ _getBestAskFromOrderbook(side, orderbook) { if (!orderbook) return null; @@ -146,6 +141,20 @@ export class LiveEngine { return null; } + _getFillCount(order) { + if (!order) return 0; + const fp = order.taker_fill_count_fp ?? order.fill_count_fp; + if (fp != null) return Math.round(parseFloat(fp)); + return order.taker_fill_count ?? order.fill_count ?? 0; + } + + _getFillCostCents(order) { + if (!order) return 0; + const dollars = order.taker_fill_cost_dollars ?? order.fill_cost_dollars; + if (dollars != null) return Math.round(parseFloat(dollars) * 100); + return order.taker_fill_cost ?? order.fill_cost ?? 0; + } + /** * Verify an order's actual fill status by polling Kalshi. * IOC responses can report 0 fills even when fills happened async. @@ -158,8 +167,8 @@ export class LiveEngine { const order = data?.order; if (!order) continue; - const fillCount = order.taker_fill_count || order.fill_count || 0; - const fillCost = order.taker_fill_cost || order.fill_cost || 0; + const fillCount = this._getFillCount(order); + const fillCost = this._getFillCostCents(order); const status = (order.status || '').toLowerCase(); const isFinal = ['canceled', 'cancelled', 'executed', 'filled', 'closed'].includes(status); @@ -245,7 +254,7 @@ export class LiveEngine { } try { - console.log(`[Live] Placing IOC order: ${side.toUpperCase()} ${contracts}x @ ${priceCents}¢ ($${sizeDollars}) [ask: ${bestAsk}¢, max: ${maxAcceptable}¢] | ${signal.reason}`); + console.log(`[Live] Placing IOC order: ${side.toUpperCase()} ${contracts}x @ ${priceCents}¢ ($${sizeDollars})[ask: ${bestAsk}¢, max: ${maxAcceptable}¢] | ${signal.reason}`); const result = await kalshiFetch('POST', '/trade-api/v2/portfolio/orders', orderBody); const order = result?.order; @@ -255,8 +264,8 @@ export class LiveEngine { return null; } - let fillCount = order.taker_fill_count || 0; - let fillCost = order.taker_fill_cost || 0; + let fillCount = this._getFillCount(order); + let fillCost = this._getFillCostCents(order); let status = (order.status || '').toLowerCase(); // If immediate response says 0 fills, verify with Kalshi to catch async fills @@ -311,7 +320,7 @@ export class LiveEngine { console.error('[Live] DB write error:', e.message); } - const msg = `💰 LIVE [${signal.strategy}] ${side.toUpperCase()} ${fillCount}x @ ${priceCents}¢ ($${(fillCost/100).toFixed(2)}) [ask:${bestAsk}¢] | ${signal.reason}`; + const msg = `💰 LIVE[${signal.strategy}] ${side.toUpperCase()} ${fillCount}x @ ${priceCents}¢ ($${(fillCost/100).toFixed(2)}) [ask:${bestAsk}¢] | ${signal.reason}`; console.log(`[Live] ${msg}`); await notify(msg, `Live: ${signal.strategy}`, 'high', 'money_with_wings');