Repository navigation
4. Feature Roadmap
This roadmap outlines the prioritized engineering milestones for the Kalshi Algorithmic Market Maker Bot following the operational philosophy: Measure
| Priority | Feature / Capability | Category | Impact | Status |
|---|---|---|---|---|
| Phase 1 (Critical) | Real-Time Realized PnL & Trade Attribution | Observability & Economics | Visibility into true strategy profitability and fill quality | Completed |
| Phase 2 (High) | Adverse Selection & Toxic Flow Protection | Risk & Capital Defense | Safeguards resting capital against rapid information jumps | Completed |
| Phase 3 (Medium-High) | Dynamic Volatility & Adaptive Spread Modeling | Quantitative Alpha | Optimizes spread width according to real-time market regimes | Planned |
| Phase 4 (Medium) | In-Place Order Amendment Optimization | Execution & Latency | Minimizes unquoted windows and cuts REST API roundtrips | Planned |
| Phase 5 (Low / Scale) | Multi-Market Portfolio Quoting Engine | Horizontal Scalability | Maximizes capital efficiency across concurrent games/leagues | Future |
graph LR
P1["Phase 1<br/><b>Measure</b><br/>Realized PnL & Attribution"] --> P2["Phase 2<br/><b>Protect</b><br/>Toxic Flow Circuit Breaker"]
P2 --> P3["Phase 3<br/><b>Optimize</b><br/>Dynamic Volatility & Spreads"]
P3 --> P4["Phase 4<br/><b>Refine</b><br/>In-Place Order Amend"]
P4 --> P5["Phase 5<br/><b>Scale</b><br/>Multi-Market Portfolio Engine"]
style P1 fill:#1c3b2b,stroke:#2e7d32,stroke-width:2px;
style P2 fill:#1c3b2b,stroke:#2e7d32,stroke-width:2px;
style P3 fill:#1c2d3b,stroke:#1976d2,stroke-width:2px;
style P4 fill:#2a1c3b,stroke:#7b1fa2,stroke-width:2px;
style P5 fill:#263238,stroke:#607d8b,stroke-width:2px;
The bot persists order lifecycle records in PostgreSQL and manages inventory exposure (
-
Trade Matching & Fill Ledger:
- Track fills using FIFO/weighted-average cost accounting on executed contracts.
- Separate Realized PnL (locked-in gain/loss upon offsetting a position) from Unrealized PnL (mark-to-market against live orderbook mid).
- Account for exchange taker/maker fees where applicable.
-
Database Persistence:
-
Add a
tradesorpnl_snapshotstable in PostgreSQL capturing per-market execution history:CREATE TABLE pnl_attribution ( id SERIAL PRIMARY KEY, ticker VARCHAR(64) NOT NULL, timestamp TIMESTAMPTZ DEFAULT NOW(), realized_pnl_cents NUMERIC(12, 4) NOT NULL, unrealized_pnl_cents NUMERIC(12, 4) NOT NULL, total_fees_cents NUMERIC(12, 4) DEFAULT 0, inventory_at_snapshot INT NOT NULL, rotation_session_id UUID NOT NULL );
-
-
Grafana Cloud Telemetry:
- Expose Prometheus metrics via
utils/metrics.py:-
kalshi_realized_pnl_cents(gauge by market ticker; net realized profit after fees) -
kalshi_unrealized_pnl_cents(gauge by market ticker; live mark-to-market against mid) -
kalshi_total_fees_cents(gauge by market ticker) -
kalshi_round_trips_total(counter by market ticker and outcome: profit, loss, scratch)
-
- Add dedicated panels to the Grafana Cloud dashboard for instantaneous balance and PnL monitoring.
- Expose Prometheus metrics via
- Every partial and complete fill computes incremental realized PnL against existing inventory.
- PnL metrics automatically reset or re-tag when auto-rotation transitions to a new contract.
- Zero blocking calls on the asyncio event loop during database writes.
Sports contracts exhibit sudden probability jumps caused by live events (e.g., touchdowns, turnovers, instant replay rulings). When an informed counterparty sweeps the book, standard Avellaneda-Stoikov inventory skewing cannot react fast enough during the 1-second quoting cycle, leaving resting orders vulnerable to rapid sequential fills at stale prices.
-
Price Velocity & Fast Market Detector:
- Tracks orderbook midpoint displacements across a rolling observation window (
PRICE_VELOCITY_WINDOW_SECONDS = 20.0s). - If price displacement exceeds threshold (
PRICE_VELOCITY_THRESHOLD_CENTS = 6.0¢), trips the Fast Market circuit breaker.
- Tracks orderbook midpoint displacements across a rolling observation window (
-
Circuit Breaker Actions:
- Immediate Quote Pull: Cancels resting bids and asks on both sides to prevent adverse fills.
-
Quiesce Cooldown: Enters a fixed 30-second quoting pause (
PRICE_VELOCITY_QUIESCE_SECONDS = 30.0s) before normal quote evaluation resumes. -
Extreme Price Collars: Halts quoting when mid-price breaches
MIN_MID_PRICE = 10¢orMAX_MID_PRICE = 90¢to eliminate binary boundary risk. -
Post-Fill Pause: Pauses quoting for 3.0 seconds post-fill (
POST_FILL_PAUSE_SECONDS) to let the orderbook stabilize. - Session Stop-Loss: Enforces session loss limits (300¢) and fee caps (250¢) with auto-liquidation and market rotation.
-
Alerting & Telemetry:
- Emits structured warnings and logs on circuit breaker trips.
- Webhook notifications on safety quiesce events.
- Rapid mid-price moves trigger immediate quote cancellations.
- Quoting automatically quiesces for a fixed 30s cooldown before normal quote evaluation resumes.
- Extreme price collars (10¢–90¢) prevent adverse inventory accumulation at binary boundaries.
- Post-fill execution pause allows liquidity recovery after partial or complete fills.
- Comprehensive unit tests assert circuit breaker activations, quiesce timers, and state resets on market rotation.
The strategy currently uses a fixed static spread (MIN_SPREAD = 4¢). During periods of low volatility, 4¢ is unnecessarily wide, forfeiting passive fill volume. During high volatility, 4¢ is too narrow, resulting in adverse selection.
-
Real-Time Volatility Estimator:
- Calculate rolling exponentially weighted moving standard deviation (
$\sigma$ ) of the orderbook mid-price over configurable windows (e.g., 30s, 60s, 300s).
- Calculate rolling exponentially weighted moving standard deviation (
-
Avellaneda-Stoikov Adaptive Formulation:
- Replace static spread with the continuous equation:
$$\delta^a + \delta^b = \gamma \sigma^2 + \frac{2}{\gamma} \ln\left(1 + \frac{\gamma}{\kappa}\right)$$ - Bound by safety limits:
$\text{Spread} = \text{clamp}(\delta, ; \text{MIN_SPREAD}, ; \text{MAX_SPREAD})$ .
- Replace static spread with the continuous equation:
-
Orderbook Imbalance Integration:
- Adjust micro-price reservation based on top-of-book volume imbalance:
$$I = \frac{V_{\text{bid}} - V_{\text{ask}}}{V_{\text{bid}} + V_{\text{ask}}}$$
- Adjust micro-price reservation based on top-of-book volume imbalance:
- Mid-price volatility computed incrementally in
$O(1)$ time with zero performance degradation. - Spreads dynamically expand during fast market movements and compress during tight consolidations.
- Defensive fallbacks enforce
MIN_SPREADif orderbook data is sparse.
When reservation prices update, the bot currently performs a sequential cancel_order place_order REST sequence. This introduces two network round-trips (~150–300ms) and creates a brief window where the bot maintains no resting presence in the market.
-
Amend API Integration:
- Integrate Kalshi’s order amend endpoint (
PUT /trade-api/v2/portfolio/orders/{order_id}/amend) to update resting prices or quantities in a single atomic request.
- Integrate Kalshi’s order amend endpoint (
-
State Management:
- Update
OrderManagerto prefer atomic amendments over full cancellation whenever the contract and side remain unchanged. - Maintain client-side order IDs across successful amend operations.
- Update
-
Graceful Fallbacks:
- Automatically fall back to standard
cancel_order+place_orderif the resting order has already filled, expired, or if the exchange rejects the amendment.
- Automatically fall back to standard
- Order adjustments complete in a single REST roundtrip.
- Queue priority preserved on volume reductions where supported by Kalshi matching engine rules.
- Fallback paths verified with deterministic unit tests.
The bot is currently constrained to a single market (self.ticker) at any given time. During schedule lulls or off-peak hours, capital remains idle. When multiple high-volume games occur concurrently (e.g., NFL Sunday 1:00 PM slate), the bot cannot capture spread across the wider board.
-
Portfolio Orchestrator:
- Manage
$N$ concurrentAvellanedaStoikovBotinstances (e.g., 2–4 markets). - Coordinate global risk limits (maximum portfolio gross contract exposure and maximum portfolio margin).
- Manage
-
Shared Connection Pooling:
- Route multi-market WebSocket subscriptions over a unified connection multiplexer.
- Share the existing token-bucket REST rate limiter across all active market workers.
-
Dynamic Capital Allocation:
- Allocate quote sizing dynamically based on market liquidity rank and volatility.
- Multiple markets quote concurrently without WebSocket socket starvation or race conditions.
- Global portfolio kill switch cancels all active quotes across all markets simultaneously.
- Unified database logging with clear market segregation.