vike
GuidesPolymarket

Follow the profitable cohort

See where the wallets with a record of realized profit put money in the last day, which of those markets they also bought below the mid, and whether the top market is still open.

/smart_money reports what a cohort of historically profitable wallets is doing, in two modes: flows ranks markets by the cohort's net inflow, and mispricings lists markets where the cohort bought meaningfully below the current mid. The recipe calls both for the last 24 hours, joins them on condition_id, and checks the top market's lifecycle with /markets/{condition_id}.

Run
export VIKE_API_KEY=...
python pm-smart-money.py             # real run: needs the key
python pm-smart-money.py --dry-run   # prints the requests it would make, calls nothing
pm-smart-money.py
"""Where the profitable Polymarket cohort put money in the last day, and which of those markets it also bought below the mid.

Run:  VIKE_API_KEY=... python pm-smart-money.py    (--dry-run lists the requests and makes none)
"""
import os
import sys
from datetime import datetime, timezone
from urllib.parse import urlencode

NAME = "pm-smart-money"
BASE = "https://data.vike.io"
DRY = "--dry-run" in sys.argv


def fail(why):
    sys.exit(f"{NAME}: {why}")


def call(path, method="GET", **params):
    url = BASE + path + ("?" + urlencode(params) if params else "")
    if DRY:
        print(method, url)
        return None
    key = os.environ.get("VIKE_API_KEY") or fail("set VIKE_API_KEY")
    import requests

    r = requests.request(method, url, headers={"X-API-Key": key}, timeout=60)
    if r.status_code != 200:
        fail(f"{method} {path} answered HTTP {r.status_code}: {r.text[:200]}")
    return r.json()


def main():
    # Dollars, not shares: net_inflow is cohort buys minus cohort sells in the window. Rows come back best first.
    flows = call("/v1/polymarket/smart_money", mode="flows", hours=24, limit=5)
    # Only clear cases appear here: at least $500 of cohort buying and a 0.03 gap to the mid. [] is a normal answer.
    cheap = call("/v1/polymarket/smart_money", mode="mispricings", hours=24, limit=20)
    cid = "0xe0b5bd8eef80fe8976e2c287e0b76a5cda138ddc437acf95f9ba91112dbc983d"  # --dry-run has no response to read
    if not DRY:
        if not flows:
            fail("no cohort flow in the last 24 hours")
        by_market = {m["condition_id"]: m for m in cheap}
        for f in flows:
            line = f"{f['title']}: net ${f['net_inflow']:,.0f} from {f['smart_wallets']} wallets, yes_mid {f['yes_mid']}"
            m = by_market.get(f["condition_id"])
            if m:
                line += f"  | also bought below the mid: {m['side']} at {m['avg_buy_price']}, now {m['current_mid']}"
            print(line)
        cid = flows[0]["condition_id"]

    # The top market's lifecycle: closed is derived, so a settled market reads closed=1 here.
    detail = call(f"/v1/polymarket/markets/{cid}")
    if DRY:
        return
    if not detail:
        fail(f"{cid} is not in the directory")
    d = detail[0]
    end = datetime.fromtimestamp(d["end_date"] / 1000, timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
    print(f"top market {d['slug']}: closed={d['closed']}, ends {end}")


if __name__ == "__main__":
    try:
        main()
    except Exception as e:  # a shape the recipe does not expect fails by name, not by traceback
        fail(f"{type(e).__name__}: {e}")

Read it this way

  • The cohort is defined on the endpoint page: at least $1,000 of realized P&L, five resolved markets and $5,000 of volume. These rows aggregate that cohort; they carry no wallet addresses.
  • net_inflow is dollars, cohort buys minus cohort sells in the window, and rows come back best first. A yes_mid of null means the market has no recorded mid yet, not zero.
  • An empty mispricings list is a normal answer. A market appears only with at least $500 of cohort buying and a mid at least 0.03 away from the cohort's average entry in its favour. The script prints flows alone then.
  • delta records where the cohort was early. It is not a forecast: a large value means the market has already moved toward the cohort.

There is no as-of parameter

Both modes answer for now. A research series is a stored one: keep each response with its own timestamp, for example hourly, rather than expecting to ask for last Tuesday later.

On this page