← back to Ken
Ken: seed 99 paper-trading portfolios + add portfolio stat columns (local boot)
2fa8032ec6302cbb2cc3e43b01bfe02d8cf24ef1 · 2026-07-10 11:11:08 -0700 · Steve
Files touched
M kalshi-dash/schema.sqlA kalshi-dash/seed-portfolios.mjs
Diff
commit 2fa8032ec6302cbb2cc3e43b01bfe02d8cf24ef1
Author: Steve <steve@designerwallcoverings.com>
Date: Fri Jul 10 11:11:08 2026 -0700
Ken: seed 99 paper-trading portfolios + add portfolio stat columns (local boot)
---
kalshi-dash/schema.sql | 17 ++++++++++++---
kalshi-dash/seed-portfolios.mjs | 47 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/kalshi-dash/schema.sql b/kalshi-dash/schema.sql
index bb98e54..70f855d 100644
--- a/kalshi-dash/schema.sql
+++ b/kalshi-dash/schema.sql
@@ -98,9 +98,20 @@ CREATE TABLE IF NOT EXISTS ken_portfolios (
id BIGINT PRIMARY KEY,
name TEXT, strategy TEXT,
balance_cents BIGINT, daily_budget_cents BIGINT,
- total_invested_cents BIGINT DEFAULT 0, starting_balance_cents BIGINT,
- color TEXT, last_trade_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW()
-);
+ total_invested_cents BIGINT DEFAULT 0, total_returned_cents BIGINT DEFAULT 0,
+ starting_balance_cents BIGINT, color TEXT,
+ trades_won BIGINT DEFAULT 0, trades_lost BIGINT DEFAULT 0, trades_expired BIGINT DEFAULT 0,
+ streak BIGINT DEFAULT 0, best_trade_cents BIGINT DEFAULT 0, worst_trade_cents BIGINT DEFAULT 0,
+ last_trade_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW()
+);
+-- backfill columns on an already-created ken_portfolios (idempotent)
+ALTER TABLE ken_portfolios ADD COLUMN IF NOT EXISTS total_returned_cents BIGINT DEFAULT 0;
+ALTER TABLE ken_portfolios ADD COLUMN IF NOT EXISTS trades_won BIGINT DEFAULT 0;
+ALTER TABLE ken_portfolios ADD COLUMN IF NOT EXISTS trades_lost BIGINT DEFAULT 0;
+ALTER TABLE ken_portfolios ADD COLUMN IF NOT EXISTS trades_expired BIGINT DEFAULT 0;
+ALTER TABLE ken_portfolios ADD COLUMN IF NOT EXISTS streak BIGINT DEFAULT 0;
+ALTER TABLE ken_portfolios ADD COLUMN IF NOT EXISTS best_trade_cents BIGINT DEFAULT 0;
+ALTER TABLE ken_portfolios ADD COLUMN IF NOT EXISTS worst_trade_cents BIGINT DEFAULT 0;
CREATE TABLE IF NOT EXISTS ken_portfolio_trades (
id BIGSERIAL PRIMARY KEY,
diff --git a/kalshi-dash/seed-portfolios.mjs b/kalshi-dash/seed-portfolios.mjs
new file mode 100644
index 0000000..bb43d42
--- /dev/null
+++ b/kalshi-dash/seed-portfolios.mjs
@@ -0,0 +1,47 @@
+// Seed ken_portfolios — one paper-trading portfolio per PORTFOLIO_STRATEGIES key.
+// Keys + names + colors are read straight out of server.js so the seed stays in sync.
+// Model: $100 starting balance, $20/day budget (engine tops up +$100/week).
+// Idempotent: ON CONFLICT (id) DO NOTHING — re-running never disturbs live balances.
+import fs from 'fs';
+import pg from 'pg';
+
+const src = fs.readFileSync(new URL('./server.js', import.meta.url), 'utf8');
+
+const stratBlock = src.match(/const PORTFOLIO_STRATEGIES = \{([\s\S]*?)\n\};/)[1];
+const keys = [...stratBlock.matchAll(/^\s*([a-z_]+):\s*\(sig\)/gm)].map((m) => m[1]);
+
+const grab = (name) => {
+ const m = src.match(new RegExp('const ' + name + ' = (\\{[\\s\\S]*?\\});'));
+ // eslint-disable-next-line no-eval
+ return m ? eval('(' + m[1] + ')') : {};
+};
+const stratNames = grab('stratNames');
+const stratColors = grab('stratColors');
+const titleCase = (k) => k.split('_').map((w) => w[0].toUpperCase() + w.slice(1)).join(' ');
+
+const START_BALANCE = 10000; // $100
+const DAILY_BUDGET = 2000; // $20/day
+
+const url = process.env.KEN_DATABASE_URL || 'postgresql://localhost:5432/ken';
+const pool = new pg.Pool({ connectionString: url });
+
+let seeded = 0;
+for (let i = 0; i < keys.length; i++) {
+ const strat = keys[i];
+ const id = i + 1;
+ const name = stratNames[strat] || titleCase(strat);
+ const color = stratColors[strat] || '#64748b';
+ const r = await pool.query(
+ `INSERT INTO ken_portfolios
+ (id, name, strategy, balance_cents, daily_budget_cents, total_invested_cents,
+ total_returned_cents, starting_balance_cents, color)
+ VALUES ($1,$2,$3,$4,$5,0,0,$4,$6)
+ ON CONFLICT (id) DO NOTHING`,
+ [id, name, strat, START_BALANCE, DAILY_BUDGET, color]
+ );
+ seeded += r.rowCount;
+}
+
+const { rows } = await pool.query('SELECT COUNT(*) c FROM ken_portfolios');
+console.log(`Seeded ${seeded} new portfolios; ken_portfolios now has ${rows[0].c} rows (${keys.length} strategies).`);
+await pool.end();
← a3dd171 Ken: switch AI analyst from paid Gemini to local Ollama (her
·
back to Ken
·
Ken: add captured_at to ken_market_snapshots (momentum query a060e29 →