← Jordi Lluis / Projects

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

Entry price and timing by branch
BranchEntryWhat changed
v1Near expiry, often $0.96–$0.99Little 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 remainingMore upside per winning trade; more time for the market to reverse.
StratBWider window and a larger gap versus the opening referenceBook updates could trigger a decision immediately. Dublin VPS and a warmed execution path. No controlled region comparison.
UC$0.01–$0.20 leftover cheap asksMaker 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

Tools and what they did in this project
SkillWhere it was used
PythonBot loop, patches, ledger analysis and the timing parser.
WebSocketsBook 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 signingA warmed client and coincurve signatures so less work sat on the submit path.
Polymarket CLOB APIPrepared and posted orders. An acknowledgement is not a fill.
JSONL recordingsDaily BBO and later L2 files, rotated and compressed on the VPS.
CSV ledgerThe public anonymized market-resolution table and its tests.

Try it step by step

  1. Read the problem first: leftover cheap asks, not the balance chart.
  2. Follow the branch table: early expensive tickets, StratA at $0.40–$0.72, then UC leftover cheap asks.
  3. Read the execution path: Lightsail, warm connection, metadata cache, defined timing window.
  4. Open the data table: how recordings were named and joined. The VPS copies were deleted; the layout is what can still be shown.
  5. 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

Components, dependencies and responsibility
ComponentDepends onResponsibility
Price referenceChainlink RTDS and, on some paths, BinanceInputs to the historical signal. The archive is not one uniform feed.
Outcome booksPolymarket WebSocket book eventsShowed whether a cheap ask was still resting.
Decision loopBook callback plus a 5 ms gate (was 50 ms)A throttle, not measured end-to-end latency.
Order clientHTTP/2, token metadata cache, coincurveBuilt the signed CLOB request on the VPS.
Lightsail instanceUbuntu in eu-west-1 (Dublin)Ran the bot and later the recorders. Location alone is not a benchmark.
Public case studyStatic site plus market_ledger.csvThe 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.

Recording and research records, as operated on the VPS
RecordDepends onResponsibility
ws_books_YYYYMMDD.jsonlBBO recorder on the Lightsail hostOne file per UTC day: best bid and ask updates. Later gzip-compressed. No order sizes in the early BBO files.
ws_books_l2_YYYYMMDD.jsonlL2 recorder, started laterDepth at the ask, needed to ask whether a cheap ticket was actually fillable.
live.logBot process on the same hostLAT_DETAIL rows for preparation and API-response time. Identifiers stay private; hashes are in EVIDENCE.md.
market / window / sideGamma market id plus the five-minute slotThe join key from a book event to an order attempt and later to a resolution.
market_ledger.csvAnonymized resolution rows in the public repoReproducible market accounting. It is not the wallet cash series.
Later Hyperliquid capturesSeparate after live Polymarket trading stoppedRecorded for analysis that was not finished. Not a second live bot on this page.

Implementation, step by step

  1. 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.
  2. Add the cheap-entry line (UC): leftover last-second asks, first as a maker under the ask, then with a taker leg.
  3. Create a Lightsail instance in Dublin, warm the HTTP client, cache metadata and measure a named window: prepare then POST response.
  4. Record books to dated JSONL files and rotate them so a disk-full host could not silently stop the recorder.
  5. 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.
  6. 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.1

Use 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.

Evidence map · Public ledger · CLOB V2 date