Files
poly-maker/docs/scoping/05-config-and-ops.md
T
Daniel Sapkota c7b686116e Getting there
2026-07-05 17:50:04 -04:00

6.5 KiB
Raw Blame History

05 — Local Config, Market Selection, and Operations

Google Sheets currently plays four roles: config store, market database, selection UI, and dashboard. v2 replaces each with a local equivalent. The test: a laptop with the repo, a .env, and a funded wallet is a complete deployment. No Google account, no service-account JSON, no second IP running a scanner.

1. Configuration files (replaces Hyperparameters + Selected Markets sheets)

All TOML, all in config/, all validated by pydantic at load, all hot-reloadable via watchfiles (applied at the next quoter wake; invalid edits are rejected with a logged diff, keeping the last good config — an edit can never crash the bot).

config/config.toml — engine & account

[wallet]
# secrets stay in .env: PK, BROWSER_ADDRESS; this file only references them
signature_type = 2            # revisit after Phase 2 wallet spike (03 §1)

[engine]
debounce_ms          = 200
reconcile_interval_s = 30
heartbeat            = true    # exchange dead-man switch (03 §3)
journal              = true    # raw WS/order journal for the backtester

[risk]                         # global — per-market caps live in markets.toml
max_total_exposure_usdc   = 5000
max_event_group_loss_usdc = 1000     # neg-risk group worst-case
daily_loss_kill_usdc      = 250
ws_stale_halt_s           = 10

config/strategy.toml — named parameter profiles

Schema in 04 §8. Profiles (political-longdated, political-hot, …) replace the Hyperparameters sheet's param_type groups.

config/markets.toml — the trade list (replaces Selected Markets sheet)

[[markets]]
slug     = "will-x-win-the-2028-democratic-nomination"
profile  = "political-longdated"
q_max_usdc = 800               # optional per-market overrides of the profile

[[markets]]
condition_id = "0x37a6de..."   # slug or condition_id both accepted
profile      = "political-hot"
enabled      = false           # keep the entry, stop quoting

The bot resolves slugs → tokens/metadata via the catalog at startup and on reload. Adding a market while running = edit file, save; the engine subscribes, seeds the book, starts quoting. Removing/disabling = cancel that market's orders, unsubscribe. This is the entire "market management UI".

.env keeps only secrets: PK, BROWSER_ADDRESS, optional RPC URL override. SPREADSHEET_URL and credentials.json are deleted.

2. Market catalog & scanner (replaces data_updater + All/Volatility Markets sheets)

state.db (SQLite) holds the market catalog; the scanner is a subcommand, not a second deployment:

  • polymaker scan — Gamma keyset sweep with server-side filters (03 §4): politics tag(s), active, min liquidity/volume, end-date window, rewards present. Enriches the shortlist with batch /books depth and reward-density estimates (the v1 add_formula_params math, kept) plus the maker-rebate estimate (taker-fee volume × rebate share — 03 §3). Writes to SQLite. Seconds per run; scheduled inside the bot process (e.g. every 15 min) — the "run on a different IP" advice dies with the crawl that motivated it.
  • polymaker markets — rank/browse the catalog in the terminal (rich table): polymaker markets --tag politics --min-reward 20 --max-vol-sum 20 --sort score. Score = expected daily income (rewards + rebates) vs. volatility & spread risk — v1's gm_reward_per_100 / volatility_sum composite, recalibrated.
  • polymaker markets add <slug> [--profile P] — appends to markets.toml (file remains the source of truth; the command is a convenience editor).
  • Volatility for ranking: prices-history coarse estimate at scan time; markets we quote get live WS-derived vol which supersedes it.

3. Runtime CLI (replaces update_stats.py + Summary sheet + eyeballing prints)

Single polymaker entrypoint (typer):

Command Purpose
polymaker run [--paper] start the engine (paper mode: full pipeline, no order POSTs)
polymaker status positions, open quotes, inventory, PnL, regime per market (reads SQLite; works while the bot runs)
polymaker pnl [--daily] realized/unrealized PnL, reward + rebate income vs. estimates
polymaker flatten [market] reduce-only mode (maker exits) for one/all markets
polymaker cancel-all panic button (also runs automatically at startup)
polymaker scan / markets catalog (above)
polymaker sim replay ... backtester (04 §9)
polymaker doctor preflight: wallet auth spike checks, pUSD balance/allowances, WS reachability, clock skew

4. Observability

  • structlog JSON logs to logs/ + human-readable console. Every order decision logs its inputs (FV, σ, inventory, regime) — a quote is always explainable after the fact.
  • Journal (journal/*.jsonl): raw WS in / orders out. Feeds the backtester and post-mortems.
  • SQLite is the queryable operational record: fills, orders, PnL marks, reward payouts, risk events. Any dashboard we want later (Grafana, a small web page) reads this — no scoping dependency on it now.
  • Alerting (minimal, phase 4): kill-switch trips, WS-stale halts, reconcile divergence, heartbeat failures → log at CRITICAL + optional webhook URL in config (generic; Discord/Telegram/ntfy all take a POST).
  • KPI set defined in 04 §9 (markouts, two-sided in-band uptime, fill ratio, income vs. estimate).

5. Deployment & runtime ops

  • uv end-to-end (already adopted; finish the job): requires-python = ">=3.12", refreshed lock, uv run polymaker ..., dev group with ruff, mypy, pytest, pytest-asyncio. Delete the 3.9 pin.
  • Placement: any always-on Linux box; latency to the CLOB (AWS us-east region) is the one infra knob that matters for queue position — a small VPS in us-east-1 beats a laptop on wifi. Not required for correctness.
  • Supervision: systemd unit example in the README (Restart=always); startup sequence is cancel-all → snapshot → resume, so a restart is always safe. The exchange heartbeat covers the gap between death and restart.
  • CI (GitHub Actions): ruff + mypy + pytest on PR. No deploy pipeline needed for a single-operator bot.
  • State backup: state.db + config/ are the whole world; journal grows ~MBs/day per market — rotate + optionally compress with age.

6. Security notes

  • PK only ever in .env (gitignored) / environment; never in TOML, logs, or SQLite. Log wallet addresses truncated.
  • The CLI never prints secrets; doctor verifies without echoing.
  • Dependencies pinned via uv.lock; renovate/dependabot optional later.