← Back
/** Sell ALL open copied positions for a given leader (full liquidation).
 *  Dust (<1 share) is skipped by sellAll. DRY=1 → preview. Run on Malaysia. */
import fs from "node:fs";
import { makeExecutor } from "./copy-exec.mjs";

const LEADER = (process.env.LEADER || "0x204f72").toLowerCase();
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" && (x.leader || "").toLowerCase().startsWith(LEADER));
console.log(`leader ${LEADER}: ${entries.length} open positions (DRY=${DRY})`);

const ex = DRY ? null : await makeExecutor();
let sold = 0, skipped = 0;
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} | bid=${bid.price} | markPnl=${o.markPnl}`);
  if (!px || px < 0.01) { console.log("  !! no valid bid, skip"); skipped++; continue; }
  if (DRY) { console.log(`  would SELL all @ ~${(px * 0.97).toFixed(3)}`); continue; }
  const resp = await ex.sellAll({ tokenID: o.tokenID, price: px });
  if (resp && resp.skipped) { console.log(`  skipped: ${resp.skipped} (dust)`); skipped++; continue; }
  console.log("  SELL:", JSON.stringify(resp).slice(0, 250));
  sold++;
}
console.log(`\ndone — sold ${sold}, skipped ${skipped}. reconcile frees slots on-chain-zero.`);