Polymarket 15 Min Crypto Trading Bot
Automated trading bot for Polymarket's 15-minute crypto up/down markets. Features built-in stop loss for risk management, time delay restrictions for smarter entry timing, and wallet response time handling to account for on-chain confirmation delays. Designed to monitor price action, place trades at high-probability trigger points, and manage positions across sessions.
Screen Map

HUD Code
Script =
(%
(()=>{const t=document.getElementById("POLY_HUD");t&&t.remove(),window.__POLY_HUD_STATE__||(window.__POLY_HUD_STATE__={});const n=window.__POLY_HUD_STATE__;try{(n.observers||[]).forEach(t=>t.disconnect())}catch{}if(n.observers=[],n.abortController)try{n.abortController.abort()}catch{}n.abortController=new AbortController;const e=n.abortController.signal,o="#00ff66",i="__POLY_DOLLARS__",l="__POLY_HUD_POS__",r="__POLY_HUD_ZOOM__";let c=parseInt(localStorage.getItem(r),10)||16;let s=null,a=0;const u=(...t)=>t.forEach(t=>{try{t()}catch{}}),d=()=>{if(s)return;const t=Date.now()-a;t>=300?(a=Date.now(),u(_,k)):s=setTimeout(()=>{s=null,a=Date.now(),u(_,k)},300-t)},f=document.createElement("div");f.id="POLY_HUD",f.style.cssText=``\n position: fixed;\n top: 90px;\n left: 90px;\n z-index: 2147483647;\n background: black;\n border: 2px solid ${o};\n border-radius: 12px;\n padding: 12px;\n font-family: monospace;\n color: ${o};\n user-select: none;\n min-width: 391px;\n ``;try{const t=JSON.parse(localStorage.getItem(l)||"null");t&&Number.isFinite(t.left)&&Number.isFinite(t.top)&&(f.style.left=``${t.left}px``,f.style.top=``${t.top}px``)}catch{}const p=localStorage.getItem(i)||"";f.innerHTML=``\n <div id="hudHeader" style="display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;cursor:move">\n <div style="opacity:.9;font-weight:700">POLY HUD</div>\n <div style="display:flex;gap:10px">\n <button id="dec">−</button>\n <button id="inc">+</button>\n <button id="copyPrice">COPY</button>\n <button id="liveSession">LIVE SESSION</button>\n </div>\n </div>\n\n <table id="tbl" style="border-collapse:collapse;font-size:${c}px;width:100%;text-align:center">\n <tr>\n <td style="border:1px solid ${o};padding:18px" id="aLabel">UP</td>\n <td style="border:1px solid ${o};padding:18px" id="aPrice">--</td>\n </tr>\n <tr>\n <td style="border:1px solid ${o};padding:18px" id="bLabel">DOWN</td>\n <td style="border:1px solid ${o};padding:18px" id="bPrice">--</td>\n </tr>\n </table>\n\n <div style="display:flex;gap:12px;margin-top:14px">\n <button id="buyA" class="bigBuy">BUY UP</button>\n <button id="buyB" class="bigBuy">BUY DOWN</button>\n </div>\n\n <div style="display:flex;gap:12px;margin-top:14px">\n <button id="redeemBtn" class="bigBuy">REDEEM</button>\n </div>\n\n <div style="display:flex;gap:12px;margin-top:14px;align-items:center">\n <input id="dollarsBox" placeholder="DOLLARS" value="${p.replace(/"/g,""")}"\n style="\n flex:1;\n background:black;\n color:${o};\n border:1px solid ${o};\n padding:12px 14px;\n font-family:monospace;\n outline:none;\n font-size:16px;\n "/>\n <button id="fillDollars" class="fillBtn">FILL DOLLARS</button>\n </div>\n\n <div style="display:flex;gap:12px;margin-top:14px;align-items:center">\n <div style="min-width:98px;opacity:0.9;font-weight:800">POSITION</div>\n <div id="posBox" style="\n flex:1;\n border:2px solid ${o};\n padding:18px 22px;\n text-align:center;\n letter-spacing:2px;\n font-weight:900;\n font-size: 20px;\n ">0</div>\n </div>\n\n <div id="dbg" style="margin-top:12px;font-size:12px;opacity:0.85;text-align:left"></div>\n ``,f.querySelectorAll("button").forEach(t=>{t.style.cssText=``\n background:black;\n color:${o};\n border:1px solid ${o};\n cursor:pointer;\n font-family:monospace;\n white-space:nowrap;\n ``}),f.querySelector("#dec").style.padding="10px 14px",f.querySelector("#inc").style.padding="10px 14px",f.querySelector("#copyPrice").style.padding="10px 16px",f.querySelector("#liveSession").style.padding="10px 16px",f.querySelectorAll(".bigBuy").forEach(t=>{t.style.flex="1",t.style.padding="22px 18px",t.style.fontSize="20px",t.style.fontWeight="900",t.style.letterSpacing="1px"});const b=f.querySelector("#fillDollars");b.style.padding="12px 16px",b.style.fontSize="16px",b.style.fontWeight="800",document.body.appendChild(f);const y=f.querySelector("#dbg"),x=f.querySelector("#posBox"),m=f.querySelector("#tbl"),g=f.querySelector("#hudHeader"),S=f.querySelector("#aLabel"),E=f.querySelector("#bLabel"),L=f.querySelector("#aPrice"),w=f.querySelector("#bPrice"),v=t=>y.textContent=t;n.noBalanceUntil=n.noBalanceUntil||0;let h=!1,C=0,D=0;const O=()=>{try{localStorage.setItem(l,JSON.stringify({left:f.offsetLeft,top:f.offsetTop}))}catch{}};g.addEventListener("mousedown",t=>{t.target.closest("button")||t.target.closest("input")||(h=!0,C=t.clientX-f.offsetLeft,D=t.clientY-f.offsetTop,t.preventDefault())}),document.addEventListener("mousemove",t=>{h&&(f.style.left=t.clientX-C+"px",f.style.top=t.clientY-D+"px")},{signal:e}),document.addEventListener("mouseup",()=>{h&&(h=!1,O())},{signal:e}),window.addEventListener("blur",()=>{h&&(h=!1,O())},{signal:e}),f.querySelector("#inc").onclick=()=>{c+=2,m.style.fontSize=c+"px",localStorage.setItem(r,c)},f.querySelector("#dec").onclick=()=>{c=Math.max(10,c-2),m.style.fontSize=c+"px",localStorage.setItem(r,c)};const q=t=>new Promise(n=>setTimeout(n,t)),$=t=>(t||"").replace(/\s+/g," ").trim().toLowerCase();function P(t){if(!t)return!1;try{t.scrollIntoView({block:"center",inline:"center"})}catch{}const n=t.getBoundingClientRect(),e=Math.floor(n.left+n.width/2),o=Math.floor(n.top+n.height/2),i={bubbles:!0,cancelable:!0,composed:!0,view:window,clientX:e,clientY:o,screenX:e,screenY:o,button:0,buttons:1};try{return t.focus?.(),t.dispatchEvent(new PointerEvent("pointerdown",{...i,pointerId:1,pointerType:"mouse",isPrimary:!0})),t.dispatchEvent(new MouseEvent("mousedown",i)),t.dispatchEvent(new PointerEvent("pointerup",{...i,pointerId:1,pointerType:"mouse",isPrimary:!0})),t.dispatchEvent(new MouseEvent("mouseup",i)),t.dispatchEvent(new MouseEvent("click",i)),!0}catch{try{return t.click?.(),!0}catch{}return!1}}function B(){const t=[...document.querySelectorAll("button.trading-button")];let n=null,e=null;for(const o of t){if(f.contains(o))continue;if("blue"===o.dataset.color)continue;const t=$(o.textContent);!n&&/\bup/.test(t)&&(n=o),!e&&/\bdown/.test(t)&&(e=o)}return{aLabel:"UP",bLabel:"DOWN",aEl:n,bEl:e}}function U(t){if(!t)return null;const n=(t.textContent||"").match(/([\d.]+)\s*¢/);return n?String(Math.floor(parseFloat(n[1]))):null}function _(){const{aLabel:t,bLabel:e,aEl:o,bEl:i}=B();if(S.textContent=t,E.textContent=e,n.aEl=o,n.bEl=i,Date.now()<n.noBalanceUntil)return L.textContent="NB",w.textContent="NB",void v("Prices: NB (no balance)");L.textContent=U(o)??"--",w.textContent=U(i)??"--",v(``Prices: Up=${L.textContent} Down=${w.textContent}``)}let I=null;const Y=f.querySelector("#buyA"),N=f.querySelector("#buyB");function k(){let t=function(){const t=document.querySelectorAll("h3");for(const n of t){if(f.contains(n))continue;if("Positions"!==(n.textContent||"").trim())continue;const t=n.closest("div");if(!t)continue;const e=t.querySelectorAll("div.whitespace-nowrap.text-sm");for(let t=0;t<e.length;t++){const n=(e[t].textContent||"").trim();if(/^up$/i.test(n)&&t+1<e.length){const n=(e[t+1].textContent||"").trim(),o=parseInt(n,10);if(!isNaN(o)&&o>0)return{qty:o,side:"up"}}if(/^down$/i.test(n)&&t+1<e.length){const n=(e[t+1].textContent||"").trim(),o=parseInt(n,10);if(!isNaN(o)&&o>0)return{qty:o,side:"down"}}}}return{qty:0,side:null}}();0===t.qty&&(t=function(){const t=document.querySelectorAll("span");for(const n of t){if(f.contains(n))continue;const t=(n.textContent||"").trim().match(/([\d.]+)\s+shares?/i);if(t){const e=Math.floor(parseFloat(t[1]));if(e<=0)continue;let o=null,i=n.parentElement;for(;i;){if(i.classList.contains("flex-1")){const t=i.parentElement;if(t){const n=[...t.children].filter(t=>t.classList.contains("flex-1"));2===n.length&&(o=0===n.indexOf(i)?"up":"down")}break}i=i.parentElement}return{qty:e,side:o}}}return{qty:0,side:null}}()),x.textContent=t.qty,I=t.side,"up"===t.side?(Y.textContent="SELL UP",N.textContent="BUY DOWN"):"down"===t.side?(Y.textContent="BUY UP",N.textContent="SELL DOWN"):(Y.textContent="BUY UP",N.textContent="BUY DOWN")}const A=f.querySelector("#dollarsBox");function M(t,n){const e=document.querySelector("#market-order-amount-input")||null;if(!e)return v(``${n}: amount input not found``);e.focus(),P(e),function(t,n){const e=Object.getPrototypeOf(t),o=Object.getOwnPropertyDescriptor(e,"value");o&&o.set?o.set.call(t,n):t.value=n}(e,t),e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),e.blur(),v(``${n}: ${t}``)}function T(){const t=(A.value||"").trim();if(!t)return v("FILL DOLLARS: empty");const n=t.replace(/[^\d.]/g,"");if(!n)return v("FILL DOLLARS: invalid");M(n,"FILL DOLLARS")}function R(){const t=document.querySelectorAll('button[role="radio"]');for(const n of t)if(!f.contains(n)&&("SELL"===n.value||"sell"===$(n.textContent)))return n;return null}function H(){const t=document.querySelectorAll("button.trading-button");for(const n of t)if(!f.contains(n)&&"blue"===n.dataset.color)return n;return null}async function W(t,n=6e4){const e=Date.now();let o=100;for(;Date.now()-e<n;){const n=t();if(n)return n;await q(o),o=Math.min(1.5*o,1e3)}return null}async function z(t){const{aEl:e,bEl:o}=B(),i="UP"===t?e:o;if(!i)return v(``BUY ${t}: pill not found``);const l=function(){const t=document.querySelectorAll('button[role="radio"]');for(const n of t)if(!f.contains(n)&&("BUY"===n.value||"buy"===$(n.textContent)))return n;return null}();l&&"checked"!==l.dataset.state&&(v(``BUY ${t}: switching to Buy tab``),P(l),await q(300)),v(``BUY ${t}: select``),P(i),await q(200),v(``BUY ${t}: fill dollars``),T(),await q(300),v(``BUY ${t}: waiting for action button``);const r=await W(H);if(!r)return v(``BUY ${t}: action button not found``);if(function(t){const n=$(t);return n.includes("deposit")||n.includes("deposite")}(r.textContent||""))return function(t=5e3){n.noBalanceUntil=Date.now()+t,L.textContent="NB",w.textContent="NB"}(5e3),v(``BUY ${t}: insufficient balance (NB 5s)``);v(``BUY ${t}: click action``),P(r),await q(500);const c=R();c&&P(c),v(``BUY ${t}: DONE``)}async function F(t){const{aEl:n,bEl:e}=B(),o="UP"===t?n:e;if(!o)return v(``SELL ${t}: pill not found``);const i=R();if(!i)return v(``SELL ${t}: Sell tab not found``);v(``SELL ${t}: switching to Sell tab``),P(i),await q(300),v(``SELL ${t}: select pill``),P(o),await q(300),v(``SELL ${t}: clicking Max``);const l=await W(()=>{const t=document.querySelectorAll("button");for(const n of t)if(!f.contains(n)&&/^max$/i.test((n.textContent||"").trim()))return n;return null},5e3);if(!l)return v(``SELL ${t}: Max button not found``);P(l),await q(300),v(``SELL ${t}: waiting for action button``);const r=await W(H);if(!r)return v(``SELL ${t}: action button not found``);v(``SELL ${t}: click action``),P(r),v(``SELL ${t}: DONE``)}function V(){const t=document.querySelectorAll("button");for(const n of t){if(f.contains(n))continue;const t=(n.textContent||"").trim();if(/\bcash\b/i.test(t))return n}return null}function X(){const t=document.querySelectorAll("button");for(const n of t){if(f.contains(n))continue;if(n.closest('[role="dialog"]'))continue;const t=(n.textContent||"").trim();if(/^claim$/i.test(t))return n}return null}function j(){const t=document.querySelector('[role="dialog"]');if(!t)return null;const n=t.querySelectorAll("button");for(const t of n)if(/\bclaim\b/i.test(t.textContent))return t;return null}function J(){const t=function(){const t=document.querySelector('button[aria-label="Go to live market"]');return t&&!f.contains(t)?t:null}();if(!t)return v("LIVE SESSION: no live session found");v("LIVE SESSION: clicking "+(t.textContent||"").trim()),P(t)}function G(){const t=document.querySelectorAll("button");for(const n of t)if(!f.contains(n)&&"done"===$(n.textContent))return v("AUTO-DISMISS: clicking Done"),void P(n)}A.addEventListener("input",()=>localStorage.setItem(i,A.value)),f.querySelector("#fillDollars").onclick=()=>T(),Y.onclick=()=>"up"===I?F("UP"):z("UP"),N.onclick=()=>"down"===I?F("DOWN"):z("DOWN"),f.querySelector("#redeemBtn").onclick=()=>async function(){v("REDEEM: clicking Cash button");const t=await W(V,5e3);if(!t)return v("REDEEM: Cash button not found");P(t),await q(500),v("REDEEM: waiting for Claim button");const n=await W(X,1e4);if(!n)return v("REDEEM: no claimable position found");P(n),await q(500),v("REDEEM: waiting for Claim dialog");const e=await W(j,1e4);if(!e)return v("REDEEM: Claim dialog not found");P(e),v("REDEEM: DONE")}(),f.querySelector("#copyPrice").onclick=()=>{let t=null;if("up"===I){const n=L.textContent.trim();"--"!==n&&(t=n)}else if("down"===I){const n=w.textContent.trim();"--"!==n&&(t=n)}if(null===t)return v("COPY: no position to copy");navigator.clipboard.writeText(t).then(()=>v(``COPIED: ${t}``),()=>v("COPY: clipboard failed"))},f.querySelector("#liveSession").onclick=()=>J();const Z=new MutationObserver(t=>{for(const n of t)if(!f.contains(n.target))return void d()});Z.observe(document.body,{childList:!0,subtree:!0,characterData:!0}),n.observers.push(Z),n.timerInterval&&clearInterval(n.timerInterval),n.timerInterval=setInterval(()=>{u(k,G)},1e3),d(),v("Poly HUD: ON")})();
)
LoadIndicator() {
global Script
Clipboard :=
Clipboard := Script
ClipWait, 1
SendInput, ^+j
Sleep 1200
SendInput, ^v
Sleep 1200
SendInput, allow pasting
Sleep 4000
SendInput, {Enter}
Sleep 2000
SendInput, ^v
SendInput, {Enter}
sleep 2000
SendInput, ^+j
}
click(point.a)
LoadIndicator()
Nightshark TradingBot Code
;=== THIS IS FOR POLYMARKET 15-MINUTE CRYPTO MARKET ONLY ====
triggerPoint := 75 ; BUY Price Point
exitPoint := 40 ; Stop Loss price point
triggerMinute := 8 ; remaining minutes
walletDelay := 3500 ; 3.5 seconds, you can adjust this based on your wallet response time
Log("Application Started !!")
loop {
click(point.c)
sleep 2000
exitCode := ""
if (Mod(A_Index, 2) = 0) {
Log("===REDEEMING REWARDS===")
redeem()
}
Log("Waiting for trade window last " . triggerMinute . " Minutes")
loop {
if (isXMinRemaining(triggerMinute))
break
sleep 500
}
Log("Monitoring UP & Down to hit Trigger Price > " . triggerPoint )
loop{
read_areas()
sleep 50 ; Adding a small sleep to prevent excessive CPU usage
} until (toNumber(area[1]) > triggerPoint || toNumber(area[2]) > triggerPoint || is5SecBeforeQuarter() )
if (toNumber(area[1]) > triggerPoint && toNumber(area[3]) = 0) {
Log("UP triggered !! Placing Up Order")
loop, 4{
click(point.a)
sleep 500
read_area(1)
if(area[1]~="NB"){
Log(" ====NOT ENOUGH BALANCE==")
Log("Skipping to Next Session")
exitCode = "NB"
break
}
sleep walletDelay
click(point.f) ; Wallet signature
sleep 4000
read_areas()
if (toNumber(area[3]) > 0) {
Log("UP position confirmed")
break
}
else {
Log("Position not confirmed ! Retrying ...")
sleep 1000
}
}
if(toNumber(area[3]) > 0) {
Log("Monitoring StopLoss @" . exitPoint . " or Resolution")
loop {
read_areas()
if (toNumber(area[1]) < exitPoint) {
if(DoubleExitCheck() < exitPoint) {
break
}
}
sleep 50 ; Adding a small sleep to prevent excessive CPU usage
} until (is5SecBeforeQuarter())
if (toNumber(area[1]) < exitPoint && DoubleExitCheck() < exitPoint && toNumber(area[1]) > 2) {
Log("Stop Loss Triggered !! Closing UP Position")
loop, 4 {
click(point.a)
sleep walletDelay
click(point.f)
sleep 4000
read_areas()
if (toNumber(area[3]) = 0) {
Log("UP Position closed ")
break
}
else {
Log("Position not confirmed ! Retrying ...")
sleep 1000
}
}
}
}
else if (exitCode != "NB") {
Log("Position did not filled on 4 retries ! Skipping to next session")
}
}
else if (toNumber(area[2]) > triggerPoint && toNumber(area[3]) = 0) {
Log("Down triggered !! Placing Down Order")
loop, 4 {
click(point.b)
sleep 500
read_area(1)
if(area[1]~="NB"){
Log(" ====NOT ENOUGH BALANCE==")
Log("Skipping to Next Session")
exitCode := "NB"
break
}
sleep walletDelay
click(point.f)
sleep 4000
read_areas()
if (toNumber(area[3]) > 0) {
Log("Down position confirmed")
break
}
else {
Log("Position not confirmed ! Retrying ...")
sleep 1000
}
}
if(toNumber(area[3]) > 0) {
Log("Monitoring StopLoss @" . exitPoint . " or Resolution")
loop {
read_areas()
if (toNumber(area[2]) < exitPoint) {
if(DoubleExitCheck() < exitPoint) {
break
}
}
sleep 50 ; Adding a small sleep to prevent excessive CPU usage
} until (is5SecBeforeQuarter())
if (toNumber(area[2]) < exitPoint && DoubleExitCheck() < exitPoint && toNumber(area[2]) > 2) {
Log("Stop Loss Triggered !! Closing Down Position")
loop, 4 {
click(point.b)
sleep walletDelay
click(point.f)
sleep 4000
read_areas()
if (toNumber(area[3]) = 0) {
Log("Down Position closed ")
break
}
else {
Log("Position not confirmed ! Retrying ...")
sleep 1000
}
}
}
}
else if (exitCode != "NB") {
Log("Position did not filled on 4 retries ! Skipping to next session")
}
}
else if (toNumber(area[3]) > 0) {
Log("Position already exists , skipping this session")
}
Log("Waiting for end of Session")
loop {
sleep 100
} until (is5SecBeforeQuarter())
sleep 6000
click(point.c)
sleep 1000
if (Mod(A_Index, 5) = 0) {
resetHUD()
}
}
isXMinRemaining(x) {
currentMinute := A_Min + 0
remaining := 15 - Mod(currentMinute, 15)
if (remaining <= x)
return true
else
return false
}
is5SecBeforeQuarter() {
minute := A_Min + 0
second := A_Sec + 0
if (Mod(minute, 15) = 14 && second >= 55) {
Log("Last 5 second. launching for new session")
return true
}
else {
return false
}
}
DoubleExitCheck() {
click(point.d)
sleep 1000
value := Clipboard
return value
}
redeem() {
click(point.e)
sleep 500
click(point.e)
sleep 8000
click(point.f)
Send, !{Left}
sleep 2000
click(point.c)
}
resetHUD() {
Log("Refreshing the Page, 20 seconds delay")
SendInput, {F5}
sleep 20000
Log("Resetting HUD")
SendInput, ^+j
sleep 2500
SendInput,{Up}
sleep 2500
SendInput, {Enter}
sleep 2500
SendInput, ^+j
}