[object Object]

← back to Ken

fix: migrate Kalshi exit orders + manual create_order to v2 /portfolio/events/orders API

9969827b63a7da56ed5f5d5509813a00edd5f82b · 2026-08-04 04:03:21 -0700 · steve@designerwallcoverings.com

Take-profit and stop-loss sell paths were still calling retired POST /portfolio/orders (v1, 410).
Manual create_order was also on v1. All three now use POST /portfolio/events/orders with
bid/ask semantics, IOC time_in_force for market-like behavior, and yes-price dollar values.

Refs: TK-10174

Files touched

Diff

commit 9969827b63a7da56ed5f5d5509813a00edd5f82b
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Tue Aug 4 04:03:21 2026 -0700

    fix: migrate Kalshi exit orders + manual create_order to v2 /portfolio/events/orders API
    
    Take-profit and stop-loss sell paths were still calling retired POST /portfolio/orders (v1, 410).
    Manual create_order was also on v1. All three now use POST /portfolio/events/orders with
    bid/ask semantics, IOC time_in_force for market-like behavior, and yes-price dollar values.
    
    Refs: TK-10174
---
 kalshi-dash/server.js | 55 ++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 43 insertions(+), 12 deletions(-)

diff --git a/kalshi-dash/server.js b/kalshi-dash/server.js
index 40cfefe..c6f833b 100644
--- a/kalshi-dash/server.js
+++ b/kalshi-dash/server.js
@@ -977,20 +977,29 @@ const routes = {
           if (!body.ticker || !body.side || !body.action || !body.type || !body.count) {
             return json(res, { error: 'ticker, side, action, type, and count are required' }, 400);
           }
+          // v2 create-order: convert v1 yes/no+action semantics to v2 bid/ask single-price model.
+          // buy YES → bid; sell YES → ask; buy NO → ask (sell YES at low price); sell NO → bid.
+          let v2Side, v2Price;
+          if (body.side === 'yes') {
+            v2Side = body.action === 'buy' ? 'bid' : 'ask';
+            v2Price = (body.yes_price / 100).toFixed(2);
+          } else {
+            v2Side = body.action === 'buy' ? 'ask' : 'bid';
+            v2Price = ((100 - (body.no_price || 0)) / 100).toFixed(2);
+          }
+          const v2Tif = body.time_in_force || (body.type === 'market' ? 'immediate_or_cancel' : 'good_till_canceled');
           const orderPayload = {
             ticker: body.ticker,
-            side: body.side,       // 'yes' or 'no'
-            action: body.action,   // 'buy' or 'sell'
-            type: body.type,       // 'limit' or 'market'
-            count: body.count,
+            side: v2Side,
+            count: String(body.count),
+            price: v2Price,
+            time_in_force: v2Tif,
+            self_trade_prevention_type: 'taker_at_cross',
           };
-          if (body.yes_price !== undefined) orderPayload.yes_price = body.yes_price;
-          if (body.no_price !== undefined) orderPayload.no_price = body.no_price;
           if (body.client_order_id) orderPayload.client_order_id = body.client_order_id;
-          if (body.time_in_force) orderPayload.time_in_force = body.time_in_force;
           if (body.expiration_ts) orderPayload.expiration_ts = body.expiration_ts;
 
-          const data = await kalshiFetch('POST', '/portfolio/orders', orderPayload);
+          const data = await kalshiFetch('POST', '/portfolio/events/orders', orderPayload);
           json(res, { success: true, order: data });
           break;
         }
@@ -7712,8 +7721,19 @@ async function autoTrader(signals) {
         // Take profit check
         if (currentPrice >= TRADE_CONFIG.take_profit_pct) {
           try {
-            const sellOrder = await kalshiFetch('POST', '/portfolio/orders', {
-              ticker: trade.ticker, side: trade.side, action: 'sell', type: 'market', count: trade.count,
+            // v2 exit: YES position → ask (sell YES); NO position → bid (buy YES back to close).
+            const exitV2Side = trade.side === 'yes' ? 'ask' : 'bid';
+            const exitYesCents = trade.side === 'yes'
+              ? (mkt.yes_bid || mkt.last_price || currentPrice)
+              : (mkt.yes_ask || mkt.last_price || (100 - currentPrice));
+            const sellOrder = await kalshiFetch('POST', '/portfolio/events/orders', {
+              ticker: trade.ticker,
+              side: exitV2Side,
+              count: String(trade.count),
+              price: (exitYesCents / 100).toFixed(2),
+              time_in_force: 'immediate_or_cancel',
+              self_trade_prevention_type: 'taker_at_cross',
+              client_order_id: crypto.randomUUID(),
             });
             const sellPrice = currentPrice;
             const pnl = Math.round((sellPrice - trade.price_cents) * trade.count * (1 - TRADE_CONFIG.fee_rate));
@@ -7730,8 +7750,19 @@ async function autoTrader(signals) {
         const unrealizedLoss = (trade.price_cents - currentPrice) * trade.count;
         if (unrealizedLoss > trade.cost_cents * (TRADE_CONFIG.stop_loss_pct / 100)) {
           try {
-            const sellOrder = await kalshiFetch('POST', '/portfolio/orders', {
-              ticker: trade.ticker, side: trade.side, action: 'sell', type: 'market', count: trade.count,
+            // v2 exit: same bid/ask conversion as take-profit.
+            const slExitV2Side = trade.side === 'yes' ? 'ask' : 'bid';
+            const slExitYesCents = trade.side === 'yes'
+              ? (mkt.yes_bid || mkt.last_price || currentPrice)
+              : (mkt.yes_ask || mkt.last_price || (100 - currentPrice));
+            const sellOrder = await kalshiFetch('POST', '/portfolio/events/orders', {
+              ticker: trade.ticker,
+              side: slExitV2Side,
+              count: String(trade.count),
+              price: (slExitYesCents / 100).toFixed(2),
+              time_in_force: 'immediate_or_cancel',
+              self_trade_prevention_type: 'taker_at_cross',
+              client_order_id: crypto.randomUUID(),
             });
             const sellPrice = currentPrice;
             const pnl = (sellPrice - trade.price_cents) * trade.count;

← 982c1f4 auto-save: 2026-08-03T13:24:27 (1 files) — kalshi-dash/ken-r  ·  back to Ken  ·  auto-save: 2026-08-04T09:32:01 (1 files) — kalshi-dash/place 2bec9fc →