Back to Strategies
Polymarket BTC Late-Window Sniper
Code Strategy by 0x7s0lt1·2026-09-04
// Polymarket BTC "Late-Window Sniper"
//
// This strategy looks for strong BTC price moves near the end of a
// 15-minute Up/Down market.
//
// The idea:
// 1. Track BTC's price when the market Window starts.
// 2. Wait until the market is Close to expiration.
// 3. Measure how large the BTC move is relative to the volatility
// expected during the remaining time.
// 4. If the move is statistically significant, determine whether
// "Up" or "Down" is strongly favored.
// 5. Check Polymarket's current price for that outcome.
// 6. Only trade if the outcome still appears underpriced.
//
// This is a directional strategy, NOT a guaranteed arbitrage.
// The strategy assumes Polymarket's price can temporarily lag
// a fast move in the underlying BTC market.
//
// IMPORTANT:
// - The default parameters are not optimized.
// - Test the strategy and monitor zScore/buyPrice before using
// meaningful capital.
// - Fees, slippage, liquidity, and execution latency can materially
// affect the result.
let state = (await $.Storage.get()) || {};
const now = Math.floor(Date.now() / 1000);
const windowSeconds = Number($.Env.WINDOW_SECONDS || 900);
const slugPrefix = $.Env.SLUG_PREFIX || "btc-updown-15m-";
// Window metadata is static for the life of the Window — only
// refresh when nothing is cached or the cached Window has expired.
const needsRefresh = !state.activeWindow || state.activeWindow.endTime <= now;
if (needsRefresh) {
const boundary = Math.floor(now / windowSeconds) * windowSeconds;
const candidateSlug = slugPrefix + boundary;
const res = await $.Http.get("https://gamma-api.polymarket.com/events/slug/" + candidateSlug);
if (res.status !== 200) {
return;
}
const event = JSON.parse(res.text);
const market = event.markets && event.markets[0];
if (!market) {
return;
}
const outcomes = JSON.parse(market.outcomes);
const tokenIds = JSON.parse(market.clobTokenIds);
const endTime = Math.floor(new Date(market.endDate).getTime() / 1000);
if (endTime <= now) {
return;
}
const openPrice = await $.getExchangeRate($.Exchange.BINANCE, "btcusdt");
if (!openPrice) {
return;
}
await $.Storage.set({
activeWindow: {
slug: candidateSlug,
outcomes: outcomes,
tokenIds: tokenIds,
endTime: endTime,
openPrice: openPrice,
acted: false
}
});
return;
}
const w = state.activeWindow;
if (!w || w.acted || now >= w.endTime) {
return;
}
const timeRemaining = w.endTime - now;
const snipeWindow = Number($.Env.SNIPE_WINDOW_SECONDS || 60);
// Not Close enough to expiry yet — nothing to do this run.
if (timeRemaining > snipeWindow) {
return;
}
const price = await $.getExchangeRate($.Exchange.BINANCE, "btcusdt");
if (!price) {
return;
}
const priceMove = (price - w.openPrice) / w.openPrice;
// Tunable, not fitted — calibrate against realized data before
// trusting it.
const annualVol = Number($.Env.BTC_ANNUAL_VOL || 0.55);
const secondsPerYear = 365 * 24 * 3600;
const sigmaRemaining = annualVol * Math.sqrt(timeRemaining / secondsPerYear);
if (sigmaRemaining <= 0) {
return;
}
const zScore = priceMove / sigmaRemaining;
const zThreshold = Number($.Env.Z_THRESHOLD || 1.5);
let outcomeName = null;
if (zScore > zThreshold) {
outcomeName = "Up";
} else if (zScore < -zThreshold) {
outcomeName = "Down";
} else {
return;
}
const idx = w.outcomes.indexOf(outcomeName);
if (idx === -1) {
return;
}
const priceRes = await $.Http.get("https://clob.polymarket.com/price", {
token_id: w.tokenIds[idx],
side: "BUY"
});
if (priceRes.status !== 200) {
return;
}
const buyPrice = Number(JSON.parse(priceRes.text).price);
if (!(buyPrice > 0 && buyPrice < 1)) {
return;
}
// Confirm the real fee for this market's category before trusting
// this default.
const takerFee = Number($.Env.TAKER_FEE || 0.018);
const margin = Number($.Env.EDGE_MARGIN || 0.02);
const maxAllowedPrice = 1 - takerFee - margin;
// Market hasn't caught up to the "sure thing" yet — that gap is the
// entire edge this strategy is trying to capture.
if (buyPrice >= maxAllowedPrice) {
return;
}
const size = Number($.Env.TRADE_SIZE_USDC || 50);
const postRes = await $.Http.post($.Env.PREDICTION_BOT_WEBHOOK_URL, {
key: $.Env.PREDICTION_BOT_KEY,
slug: w.slug,
outcome: outcomeName,
side: "BUY",
size: size,
debug: "late-sniper"
});
if (postRes.status >= 200 && postRes.status < 300) {
w.acted = true;
w.actedOutcome = outcomeName;
w.actedPrice = buyPrice;
w.actedZScore = zScore;
await $.Storage.set(state);
}