This is the simplest Polymarket BTC 5-minute market bot. It's keyboard-driven - you press a key to bet, and the bot handles the rest. There are 288 five-minute markets every day (24 hours x 12 per hour), giving you tons of betting opportunities.
The bot doesn't buy at the market price - it places orders at a discount (default 10%) below the current best bid. This is like asking for a deal: "The market says UP costs $0.55, but I'll only pay $0.495."
Why? Because in binary options, every cent of entry price matters. If you can consistently buy cheaper than the "fair" price, even a small edge compounds over hundreds of bets.
Each market lasts exactly 5 minutes. At the end, BTC's price is compared to where it was at the start. If BTC's closing price is higher than the opening price, UP wins. Otherwise, DOWN wins.
The bot tracks your session performance: total wins, losses, net P&L in dollars, and shows motivational messages.
| Key | Action | What Happens |
|---|---|---|
| B | Bet UP | Places a discounted BUY order for the UP (NO) token |
| S | Bet DOWN | Places a discounted BUY order for the DOWN (YES) token |
| X | Close Early | Sells your position at current market price before market ends |
| Ctrl+C | Exit Bot | Cancels all orders and shuts down |
import tty, termios
# Set terminal to raw mode for instant keypress detection
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
What it does: Switches your terminal into "raw" mode so it detects each keypress immediately, without waiting for you to press Enter. This makes the bot feel responsive - press B and it instantly places your bet.
state = {
'order_side': None, # "UP" or "DOWN" if pending order
'order_price': 0,
'order_token_id': None,
'position_side': None, # "UP" or "DOWN" if holding
'position_shares': 0,
'entry_price': 0,
'current_market_ts': None,
'price_to_beat': None, # BTC price at market open
}
What it does: Tracks everything about your current situation: whether you have an open order, whether you hold a position, what price you entered at, and what BTC price needs to be beaten for you to win.
# When a new 5-minute market starts:
if market_ts != state['current_market_ts']:
# 1. Count P&L from previous position
if state['position_side']:
pnl = (final_bid - state['entry_price']) * state['position_shares']
SESSION_PNL += pnl
# 2. Cancel any unfilled orders from previous market
cancel_token_orders(state['order_token_id'])
# 3. Reset state for new market
state = {k: None for k in state}
# 4. Record BTC opening price
state['price_to_beat'] = get_btc_price()
# 5. Find the new market
state['market_info'] = get_market_info(market_ts)
What it does: When the 5-minute timer resets, the bot: calculates if your last bet won or lost, cancels any leftover orders, resets everything, grabs the new BTC price (this is the "price to beat"), and finds the new Polymarket market.
Payout Structure:
The bid discount (10%) helps: instead of buying at $0.54, you might buy at $0.486. This lowers your breakeven to ~48.6%, giving you more room for error.
pip install py-clob-client web3 termcolor python-dotenv
nice_funcs, which is Moon Dev's custom library. You'll need that installed too. The bot only works on Mac/Linux due to the tty module (terminal raw mode).
| Term | Meaning |
|---|---|
| Token ID | A unique identifier for each outcome (UP/DOWN) on Polymarket |
| Best Bid | The highest price someone is currently willing to pay |
| Best Ask | The lowest price someone is currently willing to sell at |
| Limit Order | An order that only executes at your specified price or better |
| Market Order | An order that executes immediately at the best available price |
| P&L | Profit and Loss - your net gain or loss |
| Session Stats | Performance tracking for the current run of the bot |
# --- PYTHON ---
BET_SIZE_USD = 10.0
MARKET_DURATION = 300
BID_DISCOUNT_PCT = 10
SESSION_WINS = 0; SESSION_LOSSES = 0; SESSION_PNL = 0.0; SESSION_TRADES = 0
state = {
'order_side': None, 'order_price': 0, 'order_token_id': None,
'position_side': None, 'position_shares': 0, 'position_token_id': None,
'entry_price': 0, 'current_market_ts': None, 'market_info': None,
'price_to_beat': None,
}
# --- PSEUDO-CODE ---
SET bet size to $10 per bet
SET market duration to 300 seconds (5 minutes)
SET bid discount to 10% below current bid
INITIALIZE session counters: 0 wins, 0 losses, $0 P&L, 0 trades
CREATE a state tracking dictionary:
"order_side": currently null (no pending order)
"order_price": 0 (no price set)
"position_side": currently null (no held position)
"entry_price": 0 (no entry recorded)
"current_market_ts": which 5-minute window we're in
"price_to_beat": the BTC price at market open
# --- PYTHON ---
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
# --- PSEUDO-CODE ---
SAVE the current terminal settings (so we can restore them later)
SWITCH terminal to "cbreak" mode:
This means: detect each keypress IMMEDIATELY without waiting for Enter
The bot can react the instant you press B, S, or X
# --- PYTHON ---
if market_ts != state['current_market_ts']:
if state['position_side'] and state['position_token_id']:
current_book = up_book if state['position_side'] == "UP" else down_book
if current_book and state['entry_price'] > 0:
final_bid = current_book['best_bid']
pnl = (final_bid - state['entry_price']) * state['position_shares']
SESSION_PNL += pnl; SESSION_TRADES += 1
if pnl >= 0: SESSION_WINS += 1
else: SESSION_LOSSES += 1
if state['order_side'] and state['order_token_id'] and not state['position_side']:
cancel_token_orders(state['order_token_id'])
state = {k: None if k != 'current_market_ts' else market_ts for k in state}
state['price_to_beat'] = get_btc_price()
for attempt in range(8):
state['market_info'] = get_market_info(market_ts)
if state['market_info']: break
time.sleep(2)
# --- PSEUDO-CODE ---
WHEN a new 5-minute market window starts:
IF we held a position from the previous market:
GET the final bid price for our token
CALCULATE P&L = (final price - our entry price) x number of shares
ADD to session total P&L
ADD 1 to session trade count
IF profit >= 0: ADD 1 to session wins
ELSE: ADD 1 to session losses
IF we had an unfilled order from the previous market:
CANCEL that order (it's too late now)
RESET all state variables for the new market
GET the current BTC price (this is the "price to beat")
TRY up to 8 times to find the new Polymarket market:
SEARCH for the market with slug "btc-updown-5m-{timestamp}"
IF found: use it
ELSE: wait 2 seconds and try again
# --- PYTHON ---
if char == 'B':
token_id = market_info['up_token_id']
if state['order_token_id']:
cancel_token_orders(state['order_token_id'])
time.sleep(0.5)
book = get_order_book(token_id)
bid_price = round(book['best_bid'] * (1 - BID_DISCOUNT_PCT / 100), 4)
shares = calculate_shares(BET_SIZE_USD, bid_price)
resp = place_limit_order(token_id, "BUY", bid_price, shares)
if resp and resp.get('orderID'):
state['order_side'] = "UP"
state['order_price'] = bid_price
state['order_token_id'] = token_id
# --- PSEUDO-CODE ---
WHEN user presses 'B' (Bet UP):
GET the token ID for the UP outcome
IF we already have a pending order: CANCEL it first
GET the current order book for this token
CALCULATE our bid price = best current bid MINUS 10% discount
(e.g., if best bid is $0.55, we bid $0.495)
CALCULATE how many shares we get for $10 at our bid price
PLACE a BUY limit order on Polymarket at our discounted price
IF the order was accepted:
RECORD that we have a pending UP order
RECORD our bid price
RECORD which token we ordered
# --- PYTHON ---
elif char == 'X':
if not state['position_side'] or not state['position_token_id']:
continue
token_id = state['position_token_id']
shares = state['position_shares']
book = get_order_book(token_id)
sell_price = book['best_bid']
close_pnl = (sell_price - state['entry_price']) * shares
SESSION_PNL += close_pnl; SESSION_TRADES += 1
if close_pnl >= 0: SESSION_WINS += 1
else: SESSION_LOSSES += 1
cancel_token_orders(token_id)
place_limit_order(token_id, "SELL", sell_price, shares)
# --- PSEUDO-CODE ---
WHEN user presses 'X' (Close position early):
IF we don't have a position: do nothing
GET the token ID and number of shares we hold
GET the current order book
SET the sell price to the current best bid (sell immediately)
CALCULATE P&L = (sell price - entry price) x shares
ADD to session P&L and trade count
UPDATE wins or losses counter
CANCEL any remaining orders
PLACE a SELL order at the current bid price (sell into the market)
# --- PYTHON ---
def get_btc_price():
resp = requests.get("https://api.binance.com/api/v3/ticker/price",
params={"symbol": "BTCUSDT"}, timeout=5)
if resp.status_code == 200:
return float(resp.json()['price'])
return None
# --- PSEUDO-CODE ---
FUNCTION get_btc_price():
CALL Binance's public API to get the current BTC/USDT price
WAIT up to 5 seconds for a response
IF successful: RETURN the price as a number
IF failed: RETURN nothing (None)