Python trading bot
A 2026 Polymarket experiment: later versions looked for leftover cheap asks, ran from a Dublin VPS, then kept investigating after live trading stopped.
Python · WebSockets · AWS Lightsail · CLOB APIs · JSONL recordings
The problem
The first version bought expensive contracts near expiry, often around $0.96–$0.99, so correct direction left little upside. Later branches changed the entry price and the timing window. They overlapped; they were not four isolated trials.
The later useful problem was a leftover cheap ask still sitting on the about-to-win side. That is a book condition, not a security hole. UC is the public name for that cheap-entry line.
Versions
| Branch | Entry | What changed |
|---|---|---|
| v1 | Near expiry, often $0.96–$0.99 | Little upside when the direction was right. Oracle updates were too coarse for a five-minute market. |
| StratA | $0.40–$0.72 with 11–15 seconds remaining | More upside per winning trade; more time for the market to reverse. |
| StratB | Wider window and a larger gap versus the opening reference | Book updates could trigger a decision immediately. Dublin VPS and a warmed execution path. No controlled region comparison. |
| UC | $0.01–$0.20 leftover cheap asks | Maker orders under the ask, later a taker leg. Live trading later stopped. |
My contribution
I built and operated the live path: WebSocket books, order preparation, a new AWS Lightsail instance in Dublin, and a recording layout on the VPS. I then treated the live run as evidence to investigate, not as a finished proof.
After live trading stopped, recordings continued. The public repository has the case study, the ledger script and the timing parser. The private bot and raw VPS files are not on this site.
Skills this work used
| Skill | Where it was used |
|---|---|
| Python | Bot loop, patches, ledger analysis and the timing parser. |
| WebSockets | Book updates triggered evaluation instead of waiting for the next poll. |
| AWS Lightsail (Dublin) | A new VPS instance for execution and later daily recordings. No controlled region comparison was run. |
| HTTP/2 and signing | A warmed client and coincurve signatures so less work sat on the submit path. |
| Polymarket CLOB API | Prepared and posted orders. An acknowledgement is not a fill. |
| JSONL recordings | Daily BBO and later L2 files, rotated and compressed on the VPS. |
| CSV ledger | The public anonymized market-resolution table and its tests. |
Try it step by step
- Read the problem first: leftover cheap asks, not the balance chart.
- Follow the branch table: early expensive tickets, StratA at $0.40–$0.72, then UC leftover cheap asks.
- Read the execution path: Lightsail, warm connection, metadata cache, defined timing window.
- Open the data table: how recordings were named and joined. The VPS copies were deleted; the layout is what can still be shown.
- Use analyze.py on the public CSV if you want the ledger math. Wallet cash and raw logs stay in the private archive.
What depends on what
| Component | Depends on | Responsibility |
|---|---|---|
| Price reference | Chainlink RTDS and, on some paths, Binance | Inputs to the historical signal. The archive is not one uniform feed. |
| Outcome books | Polymarket WebSocket book events | Showed whether a cheap ask was still resting. |
| Decision loop | Book callback plus a 5 ms gate (was 50 ms) | A throttle, not measured end-to-end latency. |
| Order client | HTTP/2, token metadata cache, coincurve | Built the signed CLOB request on the VPS. |
| Lightsail instance | Ubuntu in eu-west-1 (Dublin) | Ran the bot and later the recorders. Location alone is not a benchmark. |
| Public case study | Static site plus market_ledger.csv | The walkthrough a recruiter can open without the private bot. |
How the data was organised
The live store was files on the VPS, keyed by market, time and file day. I deleted those copies. This table is the layout, not a download.
| Record | Depends on | Responsibility |
|---|---|---|
| ws_books_YYYYMMDD.jsonl | BBO recorder on the Lightsail host | One file per UTC day: best bid and ask updates. Later gzip-compressed. No order sizes in the early BBO files. |
| ws_books_l2_YYYYMMDD.jsonl | L2 recorder, started later | Depth at the ask, needed to ask whether a cheap ticket was actually fillable. |
| live.log | Bot process on the same host | LAT_DETAIL rows for preparation and API-response time. Identifiers stay private; hashes are in EVIDENCE.md. |
| market / window / side | Gamma market id plus the five-minute slot | The join key from a book event to an order attempt and later to a resolution. |
| market_ledger.csv | Anonymized resolution rows in the public repo | Reproducible market accounting. It is not the wallet cash series. |
| Later Hyperliquid captures | Separate after live Polymarket trading stopped | Recorded for analysis that was not finished. Not a second live bot on this page. |
Implementation, step by step
- Write the early expensive late-entry version (often $0.96–$0.99), then StratA at $0.40–$0.72 with 11–15 seconds remaining, then StratB’s wider window.
- Add the cheap-entry line (UC): leftover last-second asks, first as a maker under the ask, then with a taker leg.
- Create a Lightsail instance in Dublin, warm the HTTP client, cache metadata and measure a named window: prepare then POST response.
- Record books to dated JSONL files and rotate them so a disk-full host could not silently stop the recorder.
- After the 28 April CLOB V2 venue change and the 2 May internal guard removal, keep recording and ask whether leftover cheap asks still existed. Later scans of June–July books did not find a durable stale-ask condition; order sizes were missing and August files were gone.
- Publish the ledger and timing parser. Label the deleted VPS files and the unfinished later analysis instead of pretending the case is closed.
Run the public code locally
python analyze.py
python -m unittest discover -s tests
node --test tests/ledger-ui.test.cjs
python -m http.server 8084 --bind 127.0.0.1Use the repository README for environment setup and supported versions.
Limits and unfinished work
This was a live experiment, not a finished proof of an edge. Later book scans no longer showed durable leftover cheap asks; that later-market observation does not establish which change caused the result.
Dublin was not compared with another region under the same clock. An API acknowledgement is not a fill. The public CSV is market-resolution accounting, not wallet cash.
Raw recordings, private bot code and later Hyperliquid analysis are not in the public repository. The VPS files were deleted, so this page can show the schema, not replay those days.