7 Commits

Author SHA1 Message Date
Casey Judice bcc02cac49 Fix HYPE Polymarket discovery: read its event container
Polymarket now publishes a HYPE monthly event
(what-price-will-hyperliquid-hit-in-{month}, no year suffix), so the
old strike-probe fallback was both unnecessary and mis-ranged -- its
strikes [24..52] predated HYPE roughly doubling to ~$72, so every
"above" market ($76-92) was invisible and all 8 above rows came back
NO POLY. Point HYPE at its event like every other asset and re-range
the probe fallback to the current band [52..92].

Regenerated June pairs.json: HYPE now 16/16 with a Poly leg (was 8/16),
total 110/126 (every non-ZEC row paired; ZEC stays Kalshi-only). Only
HYPE rows changed; the other 7 assets are byte-identical.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 17:21:18 -04:00
Casey Judice 44eb6327bf Harden month-rollover tool against rate-limit truncation
gj() now retries 5x with exponential backoff (0.5->8s) instead of 3x
flat, so a throttled burst mid-discovery no longer silently truncates a
ladder. build() reports any asset whose Kalshi ladder came back empty,
and main() aborts (exit 2) rather than overwriting pairs.json when that
happens -- a failed fetch must not be mistaken for "no markets listed."

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 12:32:16 -04:00
Casey Judice 4656a23ef4 Add month-rollover tool to regenerate pairs.json from live markets
The monthly scanner is driven by a static curated pairs.json, so new monthly
contracts don't appear until that file is rebuilt. roll_month.py discovers both
legs live for a target month: it anchors on Kalshi's full strike ladder
(series KX{ASSET}MAX/MINMON, target expiry code) and attaches each strike's
nearest same-direction Polymarket market (events forward-parsed; HYPE probed).
Validated against May: re-discovers 100% of curated tickers, all slugs parse,
nearest-match agrees except where the curated file points at now-closed Poly
markets. Safety: backs up the prior file and refuses to overwrite when it finds
fewer than --min-pairs (so running it before the month lists can't wipe it).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 12:04:42 -04:00
Casey Judice 8cb8d4a9e4 Refresh stale Polymarket slugs (BTC dip markets rediscovered)
Polymarket appends random hash suffixes when re-publishing markets
(e.g. will-bitcoin-dip-to-70k-in-may-2026 → ...-2026-438-356-919).
Our static pairs.json had the unsuffixed slugs from the original
spreadsheet snapshot, so every BTC 'below' pair silently fell through
to NO POLY despite both venues having liquid markets. User flagged
this looking at BTC <70k May.

- scripts/refresh_pairs.py: walks each asset's 'what-price-will-X-
  hit-in-may' multi-outcome event on Gamma, rebuilds the
  (asset, direction, strike) → slug map, rewrites data/pairs.json.
  Probes HYPE strikes individually since there's no container event
  for that asset. Has --dry-run.
- data/pairs.json: updated to current live slugs. Two BTC arbs that
  were previously hidden now surface (BTC <65k and <70k both ARB).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 17:12:05 -04:00
Casey Judice dfdfe8414d IBKR daily scanner: correct YES+NO conid schema + discover helper
Earlier ibkr.py assumed each strike = one conid (buy=Yes / sell=No). The
IBKR ForecastEx CP API actually exposes each strike as TWO separate conids
(YES = right=CALL, NO = right=PUT). Local symbol shape is
CFBTC_MMDDYYHH_<strike>_<YES|NO> e.g. CFBTC_05242616_71000_YES means
4pm ET May 24 2026, $71,000 YES side.

- data/ibkr_contracts.example.json: per entry now has yes_conid + no_conid
  + strike + close_iso + label (one row per strike).
- arb/daily.py: snapshots both conids in one batch; yes_ask/no_ask come
  directly from each side's ask (no more 1-bid derivation).
- scripts/discover_ibkr.py: walks /iserver/secdef/strikes + secdef/info to
  print the full YES/NO ladder for a given underlying + month + maturity.
  Filters by maturityDate so it doesn't mix expiries.

End-to-end verified: 3 sample strikes pair cleanly to KXBTCD-26MAY2416
(IBKR $71K -> Kalshi T70999.99 etc.). Live prices still pending the
user's ForecastEx market-data subscription / strikes closer to spot.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:19:26 -04:00
Casey Judice 5e6889ec7b Static dashboard via GitHub Pages (docs/) + GHA snapshot writes
Adds a phone-friendly public dashboard served from docs/ via GitHub Pages:
- docs/index.html, app.js, style.css: monthly + hourly tabs only, no
  positions/settings (positions stay on the local Mac UI). Reads
  ./data/scan.json and ./data/hourly.json instead of /api endpoints.
- gha_alerts.py also writes both snapshots to docs/data/ each cron tick.
- Workflow now commits docs/data/ alongside alerts_state.json.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:13:47 -04:00
Casey Judice 05c0441053 Initial commit: prediction-market arb scanner + GHA alerts
- Monthly + hourly Kalshi/Polymarket arb scanner (stdlib-only Python).
- Live positions tab w/ realized P&L history.
- GitHub Actions cron workflow texts SMS via Apps Script webhook on
  newly-detected arbs. State persisted in alerts_state.json.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 19:48:50 -04:00