mirror of
https://github.com/multipleof4/KalBot.git
synced 2026-03-16 21:41:02 +00:00
Fix: Support Kalshi v2 fixed-point fill fields
This commit is contained in:
@@ -13,7 +13,7 @@ export class LiveEngine {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.enabledStrategies = new Set();
|
this.enabledStrategies = new Set();
|
||||||
this.openOrders = new Map();
|
this.openOrders = new Map();
|
||||||
this.recentFills = [];
|
this.recentFills =[];
|
||||||
this.totalPnL = 0;
|
this.totalPnL = 0;
|
||||||
this.wins = 0;
|
this.wins = 0;
|
||||||
this.losses = 0;
|
this.losses = 0;
|
||||||
@@ -25,7 +25,7 @@ export class LiveEngine {
|
|||||||
this._dailyLossResetTime = Date.now();
|
this._dailyLossResetTime = Date.now();
|
||||||
this._lastBalance = null;
|
this._lastBalance = null;
|
||||||
this._lastPortfolioValue = null;
|
this._lastPortfolioValue = null;
|
||||||
this._positions = [];
|
this._positions =[];
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
@@ -48,7 +48,7 @@ export class LiveEngine {
|
|||||||
const orders = await db.query(
|
const orders = await db.query(
|
||||||
'SELECT * FROM live_orders WHERE status = "pending" OR status = "resting"'
|
'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);
|
this.openOrders.set(o.orderId, o);
|
||||||
}
|
}
|
||||||
if (this.openOrders.size) {
|
if (this.openOrders.size) {
|
||||||
@@ -115,8 +115,8 @@ export class LiveEngine {
|
|||||||
'GET',
|
'GET',
|
||||||
'/trade-api/v2/portfolio/positions?settlement_status=unsettled&limit=200'
|
'/trade-api/v2/portfolio/positions?settlement_status=unsettled&limit=200'
|
||||||
);
|
);
|
||||||
const positions = data?.market_positions || data?.positions || [];
|
const positions = data?.market_positions || data?.positions ||[];
|
||||||
this._positions = Array.isArray(positions) ? positions : [];
|
this._positions = Array.isArray(positions) ? positions :[];
|
||||||
return this._positions;
|
return this._positions;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[Live] Positions fetch error:', e.message);
|
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) {
|
_getBestAskFromOrderbook(side, orderbook) {
|
||||||
if (!orderbook) return null;
|
if (!orderbook) return null;
|
||||||
|
|
||||||
@@ -146,6 +141,20 @@ export class LiveEngine {
|
|||||||
return null;
|
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.
|
* Verify an order's actual fill status by polling Kalshi.
|
||||||
* IOC responses can report 0 fills even when fills happened async.
|
* IOC responses can report 0 fills even when fills happened async.
|
||||||
@@ -158,8 +167,8 @@ export class LiveEngine {
|
|||||||
const order = data?.order;
|
const order = data?.order;
|
||||||
if (!order) continue;
|
if (!order) continue;
|
||||||
|
|
||||||
const fillCount = order.taker_fill_count || order.fill_count || 0;
|
const fillCount = this._getFillCount(order);
|
||||||
const fillCost = order.taker_fill_cost || order.fill_cost || 0;
|
const fillCost = this._getFillCostCents(order);
|
||||||
const status = (order.status || '').toLowerCase();
|
const status = (order.status || '').toLowerCase();
|
||||||
const isFinal = ['canceled', 'cancelled', 'executed', 'filled', 'closed'].includes(status);
|
const isFinal = ['canceled', 'cancelled', 'executed', 'filled', 'closed'].includes(status);
|
||||||
|
|
||||||
@@ -245,7 +254,7 @@ export class LiveEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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 result = await kalshiFetch('POST', '/trade-api/v2/portfolio/orders', orderBody);
|
||||||
const order = result?.order;
|
const order = result?.order;
|
||||||
@@ -255,8 +264,8 @@ export class LiveEngine {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fillCount = order.taker_fill_count || 0;
|
let fillCount = this._getFillCount(order);
|
||||||
let fillCost = order.taker_fill_cost || 0;
|
let fillCost = this._getFillCostCents(order);
|
||||||
let status = (order.status || '').toLowerCase();
|
let status = (order.status || '').toLowerCase();
|
||||||
|
|
||||||
// If immediate response says 0 fills, verify with Kalshi to catch async fills
|
// 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);
|
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}`);
|
console.log(`[Live] ${msg}`);
|
||||||
await notify(msg, `Live: ${signal.strategy}`, 'high', 'money_with_wings');
|
await notify(msg, `Live: ${signal.strategy}`, 'high', 'money_with_wings');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user