← back to Ken
kalshi-dash/seed-portfolios.mjs
48 lines
// 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();