← Back
/** Close (sell) specific open copied positions to free slots.
 *  Sells full on-chain holding on CLOB; the running daemon reconcile detects the
 *  on-chain-zero balance and frees the ledger slot itself (no manual ledger write
 *  → no race with the live daemon). DRY=1 → preview only. Run on Malaysia. */
import fs from "node:fs";
import { makeExecutor } from "./copy-exec.mjs";

const TARGETS = ["Detroit Tigers", "Baltimore Orioles", "Pittsburgh Pirates"];
const DRY = process.env.DRY === "1";

const p = JSON.parse(fs.readFileSync("./positions.json", "utf8"));
const entries = Object.entries(p).filter(([k, x]) => x.status === "open" && TARGETS.some((t) => x.title.includes(t)));
console.log(`matched ${entries.length} open positions to close (DRY=${DRY})`);

const ex = DRY ? null : await makeExecutor();

for (const [key, o] of entries) {
  const bid = await fetch(`https://clob.polymarket.com/price?token_id=${o.tokenID}&side=sell`).then((r) => r.json()).catch((e) => ({ err: String(e) }));
  const px = Number(bid.price || 0);
  console.log(`\n- ${o.title} | ${o.outcome} | bestBid=${bid.price} | markPnl=${o.markPnl}`);
  if (!px || px < 0.01) { console.log("  !! no valid bid, skipping"); continue; }
  if (DRY) { console.log(`  would SELL all @ ~${(px * 0.97).toFixed(3)} (bid -3%)`); continue; }
  const resp = await ex.sellAll({ tokenID: o.tokenID, price: px });
  console.log("  SELL resp:", JSON.stringify(resp).slice(0, 400));
}
console.log("\ndone — reconcile will free slot(s) once on-chain balance hits 0");