[object Object]

← back to Ken

Ken (Cody gate): raise winner-gate MIN_RESOLVED 20->100 (N=20@60% clearable by ~25% variance → real money followed lucky noise); fix cumulative_pnl_cents to accumulate in ON CONFLICT (was frozen at day's first trade); fix resolver log to count SETTLED not SELECTED trades

d2605dfdf8bc37331b8732765428968402fa3924 · 2026-08-03 09:40:19 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit d2605dfdf8bc37331b8732765428968402fa3924
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Mon Aug 3 09:40:19 2026 -0700

    Ken (Cody gate): raise winner-gate MIN_RESOLVED 20->100 (N=20@60% clearable by ~25% variance → real money followed lucky noise); fix cumulative_pnl_cents to accumulate in ON CONFLICT (was frozen at day's first trade); fix resolver log to count SETTLED not SELECTED trades
---
 kalshi-dash/server.js | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/kalshi-dash/server.js b/kalshi-dash/server.js
index 5afed93..61c439f 100644
--- a/kalshi-dash/server.js
+++ b/kalshi-dash/server.js
@@ -7499,7 +7499,10 @@ async function getTraderState() {
 // currently hold the SAME direction. entry_price is refreshed to the LIVE Kalshi YES
 // price so the trader's yes/no price math is correct (paper stores NO-cost, not YES).
 async function getWinnerConsensusSignals() {
-  const MIN_RESOLVED = 20, WIN_GATE = 0.60, MIN_AGREE = 2, MAX_MARKETS = 8;
+  // MIN_RESOLVED raised 20→100 (2026-08-03, Cody gate): at 60% win gate, N=20 is clearable
+  // by pure variance — P(>=12 wins | n=20, p=0.5) ~= 25%, so ~1-in-4 RANDOM portfolios would
+  // qualify as a "winner" that real money then follows. N=100 pushes the gate above noise.
+  const MIN_RESOLVED = 100, WIN_GATE = 0.60, MIN_AGREE = 2, MAX_MARKETS = 8;
   try {
     const { rows } = await kenQ(`
       WITH winners AS (
@@ -8952,6 +8955,7 @@ async function resolvePortfolioTrades() {
       LIMIT 500
     `);
 
+    let settledCount = 0;
     for (const trade of openTrades) {
       // Get latest price from snapshots
       const { rows: snaps } = await kenQ(`
@@ -9007,6 +9011,7 @@ async function resolvePortfolioTrades() {
         RETURNING id
       `, [status, currentPrice, pnl, trade.id]);
       if (flip.rowCount === 0) continue; // lost the race — already settled elsewhere, do NOT double-credit
+      settledCount++;
 
       // Update portfolio running totals
       const streakVal = status === 'won' ? 1 : status === 'lost' ? -1 : 0;
@@ -9037,7 +9042,8 @@ async function resolvePortfolioTrades() {
           closed_trades = ken_daily_pnl.closed_trades + 1,
           wins = ken_daily_pnl.wins + $3,
           losses = ken_daily_pnl.losses + $4,
-          daily_pnl_cents = ken_daily_pnl.daily_pnl_cents + $5
+          daily_pnl_cents = ken_daily_pnl.daily_pnl_cents + $5,
+          cumulative_pnl_cents = ken_daily_pnl.cumulative_pnl_cents + $5
       `, [trade.portfolio_id, tradeDate, status === 'won' ? 1 : 0, status === 'lost' ? 1 : 0, pnl]);
 
       // Update learning table
@@ -9049,7 +9055,7 @@ async function resolvePortfolioTrades() {
       `, [category, trade.direction, status === 'won' ? 1 : 0, pnl]);
     }
 
-    if (openTrades.length > 0) console.log(`[Ken/Portfolio] Resolved ${openTrades.length} trades across portfolios`);
+    if (settledCount > 0) console.log(`[Ken/Portfolio] Settled ${settledCount}/${openTrades.length} open trades this pass`);
   } catch (e) {
     console.error('[Ken/Portfolio] Resolution error:', e.message);
   } finally {

← d1ce301 Ken: saveTradeConfig read-merges DB enabled gate (root-cause  ·  back to Ken  ·  chore: gitignore runtime data, v1.0.1 (session close) 811d382 →