All posts
May 29, 2026·Apimie

Build a Polymarket Whale-Alert Bot in Python

Whale wallets on Polymarket are public on-chain, but watching them by hand is hopeless — positions shift while you sleep. This tutorial builds a small Python bot that polls for large wallet moves and pings you on Telegram when a new one shows up. It runs on the free tier, and the whole thing is under 60 lines.

We'll use the Apify actor apimie/polymarket-whales-tracker as the data layer, so there's no scraper to maintain and no on-chain indexing to set up.


What you'll need

  • Python 3.10+
  • An Apify token — the actor is the entry point; grab a token from your Apify account.
  • An apimie account — sign up free. Your tier sets the limits (calls per day, lookback, refresh); the free tier is enough to follow along.
  • A Telegram bot — message @BotFather, run /newbot, and save the token it gives you. Send your bot a message, then read your chat_id from https://api.telegram.org/bot<TOKEN>/getUpdates.
pip install requests

Step 1 — Pull the current whale list

The whale_list action returns active whale wallets sorted by volume. One POST to the actor and you get JSON back:

curl -s -X POST \
  "https://api.apify.com/v2/acts/N5u8wVgS1bKzibZdf/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action":"whale_list","limit":100}'

Each record is one wallet:

{
  "proxy_wallet": "0x84cfffc3...",
  "total_volume_usdc": "259659.67",
  "buy_volume_usdc": "259659.67",
  "sell_volume_usdc": "0.00",
  "total_trades": 2170,
  "last_movement_at": "2026-05-29T10:26:10.000Z"
}

A wallet with sell_volume_usdc: 0 has never sold — it's a pure buyer, which is the strongest directional signal in the set.

Here's the same call in Python:

import requests

APIFY_TOKEN = "your_apify_token_here"
ACTOR = "N5u8wVgS1bKzibZdf"

def get_whales(limit=100):
    r = requests.post(
        f"https://api.apify.com/v2/acts/{ACTOR}/run-sync-get-dataset-items",
        params={"token": APIFY_TOKEN},
        json={"action": "whale_list", "limit": limit},
        timeout=120,
    )
    r.raise_for_status()
    return r.json()

Step 2 — Detect what's actually new

Every poll returns the full list, so you need to remember what you've already seen — otherwise you'll alert on the same wallets forever. Key each move by wallet and its last-movement timestamp: when a wallet trades again, the timestamp changes and it counts as new.

def move_id(w):
    return (w["proxy_wallet"], w["last_movement_at"])

Keep the seen IDs in a set. On the first run, mark everything as seen without alerting, so you don't get blasted with the entire current list on startup.


Step 3 — Send the alert

Plain Telegram Bot API, no SDK:

TG_TOKEN = "your_telegram_bot_token"
TG_CHAT_ID = "your_chat_id"

def alert(text):
    requests.post(
        f"https://api.telegram.org/bot{TG_TOKEN}/sendMessage",
        json={"chat_id": TG_CHAT_ID, "text": text, "parse_mode": "Markdown"},
        timeout=30,
    )

Step 4 — Poll on a sane interval

Don't poll faster than the data refreshes — you'd just burn calls re-reading the same snapshot. Snapshots refresh as often as every 15 minutes on the top tier; the free tier's quota is small and shared with chat, so a longer interval is the right call while you test. Match your loop to your tier.

import time

POLL_SECONDS = 900  # top tier refreshes every 15 min; raise this on free
MIN_VOLUME = 10_000  # only alert on wallets above $10k

def run():
    seen = set()
    first_pass = True
    while True:
        try:
            for w in get_whales():
                mid = move_id(w)
                if mid in seen:
                    continue
                seen.add(mid)
                vol = float(w["total_volume_usdc"])
                if first_pass or vol < MIN_VOLUME:
                    continue
                side = "pure buyer" if float(w["sell_volume_usdc"]) == 0 else "mixed"
                alert(
                    f"🐋 *Whale move*\n"
                    f"`{w['proxy_wallet']}`\n"
                    f"Volume: ${vol:,.0f} · {w['total_trades']} trades · {side}"
                )
            first_pass = False
        except requests.RequestException as e:
            print(f"poll failed: {e}")
        time.sleep(POLL_SECONDS)

if __name__ == "__main__":
    run()

That's the whole bot. Run it with python bot.py and leave it on a small VPS, a Raspberry Pi, or a free-tier container — anything that stays awake.


Where to take it next

  • Per-market alerts — swap whale_list for market_whales to watch whales on one specific market instead of the whole board.
  • Pure-buyer filter — only alert when sell_volume_usdc is 0 and total_volume_usdc clears a higher bar. Fewer pings, stronger signal.
  • Per-market PnL — call market_whales to see each whale's outcome_name, net_size_usdc, avg_entry_price vs current_price, and unrealized_pnl. Follow the wallets that are actually in profit.
  • Persist state — write seen to a file or Redis so a restart doesn't replay the current list.

A whale move isn't a trade signal on its own — a large position can be a hedge, and any wallet can be wrong. Treat it as one input among several, not a green light.

If you want the data layer without standing up your own scraper, that's what apimie is — see the API. The free tier is enough to get this bot running today.

Try the Whale AI — free

5 questions/day, no card required.

Ask the AI →