Files
poly-maker/docs/scoping/05-config-and-ops.md
T

133 lines
6.5 KiB
Markdown
Raw Normal View History

2026-07-05 17:50:04 -04:00
# 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
```toml
[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)
```toml
[[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.