Initial commit — BTC 5-minute binary options edge study
Reconstructed strategy engine + execution layer, trained XGBoost models, a manual trading tool, and the research writeup. Paper mode runs keyless over live WebSocket feeds; live trading requires your own wallet. No secrets committed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# Mini-PRD — Quick-Trade: a hotkey execution interface for 5-minute binaries
|
||||
|
||||
> *Written retrospectively: this documents the product decisions behind a tool I built and used during the study. The tool itself belongs to the full (private) system — no live-trading code ships in this repo.*
|
||||
|
||||
## Problem
|
||||
|
||||
A 5-minute binary market prices in new information within seconds; the actionable moment for any late-window signal is the **final 10–40 seconds**. Polymarket's native web UI needs multiple clicks and page-state changes to place one order, gives no feedback on how long an order actually took, and is unusable for building intuition about how the book behaves under time pressure.
|
||||
|
||||
If Pillar 3 of the study asks *"can a human capture the edge at all?"*, the native UI answers "no" for the wrong reason — **tool latency, not market latency**. To make the test fair, execution overhead had to be driven to its floor and *measured*, so that whatever latency remained was attributable to the market, not the mouse.
|
||||
|
||||
## User
|
||||
|
||||
One power user: me. (n = 1 by design — this is a research instrument, not a consumer product. That constraint drives most scope cuts below.)
|
||||
|
||||
## Goals & success metrics
|
||||
|
||||
| Goal | Metric |
|
||||
|---|---|
|
||||
| Minimal click-to-submit path | **One keystroke** = one signed, posted order (no Enter, no confirmation dialog) |
|
||||
| Latency visible, not assumed | Every order prints its **measured sign-and-submit round-trip in ms** (`create_order` + `post_order` → API ack) |
|
||||
| Fill outcome reported, not assumed | After the order: **filled or not, matched size, fill price, and PnL** — read from the order's `size_matched` |
|
||||
| Zero per-click network overhead beyond the order itself | Price display and order parameters require **0 extra HTTP calls** at trade time |
|
||||
| Usable across windows without operator work | New 5-minute market auto-discovered and re-warmed in the background |
|
||||
|
||||
## Non-goals (explicit cuts)
|
||||
|
||||
- **No variable order size** — fixed 10 shares per keystroke. Fewer keys to think about, and it caps fat-finger damage.
|
||||
- **No order management** — no cancel/modify UI. GTD expiry does the cleanup.
|
||||
- **No position dashboard, no charts** — the separate watch screen owns market display; this tool owns the trigger.
|
||||
- **No multi-market support** — current window only.
|
||||
|
||||
## Functional requirements (the entire keyboard surface)
|
||||
|
||||
| Key | Action |
|
||||
|---|---|
|
||||
| `u` / `d` | Buy UP / DOWN, 10 shares, at market (ask + $0.02 buffer, capped at $0.99) |
|
||||
| `Shift`+`1`–`6` | Resting limit "lottery" bids at $0.01 / $0.02 / $0.03 — cheap maker orders (`1`–`3` = UP, `4`–`6` = DOWN) |
|
||||
| `i` / `o` | Sell UP / DOWN at best bid, most expensive lot first |
|
||||
| `b` / `r` / `w` | Balance check · redeem settled tokens · force window refresh |
|
||||
| `q` | Quit (restores terminal state) |
|
||||
|
||||
## Component structure
|
||||
|
||||
```
|
||||
① PRICE FEED — always live in the background. THIS is why a click needs no network:
|
||||
|
||||
Polymarket WebSocket ──► collector ──► snapshots.jsonl ──► tail -F ──► Price panel
|
||||
(chainlink price + (local file, the (live bid/ask,
|
||||
CLOB book, real-time) collector streams it) countdown)
|
||||
|
||||
② HOT PATH — fires on ONE keystroke; it reads the current ask from the Price panel
|
||||
above (a local read), so no network call is needed to price the order:
|
||||
|
||||
keystroke (raw tty, no Enter)
|
||||
│
|
||||
▼
|
||||
Key listener (select() loop)
|
||||
│
|
||||
▼
|
||||
Order router u/d = market · cheap limits · i/o = sell
|
||||
│
|
||||
▼
|
||||
Preflight cache tick_size + neg_risk, warmed once per window
|
||||
│
|
||||
▼
|
||||
Order builder + signer client-side signing; HTTP/1.1 keep-alive
|
||||
│
|
||||
▼
|
||||
REST post_order (GTD) ──► Polymarket CLOB
|
||||
|
||||
③ REPORTING — every order writes one line to a JSONL journal (the study's dataset):
|
||||
|
||||
• on submit: sign → ack latency (ms)
|
||||
• at settle: poll order status (REST) ──► size_matched · fill price · PnL
|
||||
|
||||
Background: a window manager auto-detects each new 5-minute market, resolves its
|
||||
token IDs (one REST call), and re-warms the Preflight cache before the window opens.
|
||||
```
|
||||
|
||||
## Key decisions & tradeoffs
|
||||
|
||||
| Decision | Why | Cost accepted |
|
||||
|---|---|---|
|
||||
| Single keystroke, no confirmation | The confirmation dialog *is* the latency problem | Fat-finger risk — mitigated by fixed small size |
|
||||
| Fixed 10-share size | Removes a decision (and keystrokes) from the hot path | No sizing flexibility |
|
||||
| Prices from a local file tail, not REST | The collector already streams every tick to disk; reading it costs ~0ms and no rate limits | Depends on the collector running |
|
||||
| Warm order params once per window | `tick_size`/`neg_risk` lookups are per-token constants; fetching them per order wastes a round trip inside the hot path | Stale cache on rare market config change |
|
||||
| Market buys pay ask + $0.02 | In the last seconds, a missed fill costs more than 2¢ of price improvement | Slightly worse average entry |
|
||||
| Sell most-expensive-lot-first | Realizes the best exit first when unwinding under time pressure | — |
|
||||
| Terminal UI, not web | tty raw mode delivers a keypress in microseconds; a browser adds an event loop you don't control | No visual polish |
|
||||
|
||||
## The real cost center: the fill lifecycle
|
||||
|
||||
The interface optimizes the *submit* path — but a keystroke doesn't buy anything; it opens an order lifecycle:
|
||||
|
||||
```
|
||||
quote (best ask) → post → { full fill | partial fill | no fill } → retry / cancel
|
||||
```
|
||||
|
||||
This is deliberately **not** managed in the tool (fixed size, GTD auto-expiry does the cleanup — see Non-goals), and that scoping choice is exactly where the honesty lives: **order management is the pain, not a feature I could polish away.** On a thin binary book, partial fills and no-fills are routine. Each retry chases an ask the maker has already moved, so you cross to a worse price (slippage) or miss entirely. The exit runs the same lifecycle as a ladder — post the ask → step to the bid → cross at market — and a latency circuit breaker halts trading when the round trip degrades. The full loop regularly takes longer than the edge exists. **Latency inside this lifecycle plus thin-book slippage consumes essentially the entire margin** — which is why the fast-submit interface, though necessary, was never going to be sufficient.
|
||||
|
||||
## Outcome
|
||||
|
||||
The interface doubled as the study's **measurement instrument**: every order writes one line to a JSONL journal — sign-and-submit latency, whether it filled, matched size, fill price, PnL. That log is the raw dataset behind Pillar 3, turning "execution is slow" from a hunch into distributions you can read. Order latency became a **measured number printed after every trade** instead of a guess, and — together with the fill-lifecycle cost above — that is what makes Pillar 3's conclusion honest: even with the human reduced to a single keystroke and the software path stripped to its floor, the remaining round-trip is orders of magnitude slower than the market makers' millisecond repricing. The bottleneck was never the UI; it's the speed of light plus someone else's colo. **Knowing that changed the product question** — from "how do I trade this faster?" to "what game can retail actually win?" (see the study's conclusion in the [README](../README.md)).
|
||||
Reference in New Issue
Block a user