/** 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");