Skip to content
Merged
133 changes: 133 additions & 0 deletions PR_DESCRIPTION_ISSUE_26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
## Summary

Options GPS can now **autonomously trade options** on Deribit and Aevo directly from the CLI. This adds a full execution engine with order placement, order lifecycle management (place → monitor → cancel), slippage protection, position sizing, and safety guardrails — transforming the tool from analysis-only to end-to-end autonomous execution.

**Before:** CLI showed recommended venue/price per leg but could not place orders. No `--execute` or Screen 5.

**After:** `--dry-run` simulates execution (no credentials needed); `--execute best` (or `safer`/`upside`) submits live orders to Deribit/Aevo. Each leg is auto-routed to its best venue. Orders are monitored with configurable timeout, protected by slippage limits, and partially-filled multi-leg strategies are automatically unwound on failure.

## Related Issues

Closes #26

## Type of Change

- [ ] Bug fix
- [x] Improvement to existing tool
- [ ] Documentation
- [ ] Other (describe below)

## What Changed

### `executor.py` — New execution engine (719 lines)

**Data model:**
- `OrderRequest` / `OrderResult` / `ExecutionPlan` / `ExecutionReport` dataclasses
- `OrderResult` tracks `timestamp` (ISO 8601), `slippage_pct`, and `latency_ms` per fill
- `ExecutionPlan` supports `max_slippage_pct`, `timeout_seconds`, `quantity_override`
- `ExecutionReport` includes `started_at`, `finished_at`, `cancelled_orders`

**Executors (abstract `BaseExecutor` with full order lifecycle):**
- `DryRunExecutor` — simulates fills from quote data; tracks orders for status/cancel
- `DeribitExecutor` — POST + JSON-RPC 2.0 with OAuth token caching, USD↔BTC price conversion, live order book pricing, tick-size alignment
- `AevoExecutor` — REST with EIP-712 L2 order signing (Ethereum private key), instrument ID resolution via `/markets`, 6-decimal price/amount scaling

**Order lifecycle:** `place_order()` → `get_order_status()` → `cancel_order()` on all executors

**Execution engine:**
- `build_execution_plan()` — auto-routes per leg via `leg_divergences`, builds exchange-specific instrument names (Deribit: `BTC-27MAR26-71000-C`, Aevo: `BTC-71000-C`), applies quantity override
- `validate_plan()` — pre-flight checks (instruments, prices, quantities, actions)
- `execute_plan()` — sequential execution with:
- **Order monitoring:** polls `get_order_status()` until filled or timeout, then cancels
- **Slippage protection:** rejects fills exceeding `--max-slippage` threshold
- **Auto-cancel on partial failure:** cancels already-filled legs when a later leg fails
- `get_executor()` factory — reads credentials from env vars, supports testnet

### `main.py` — CLI integration

**New flags:**
| Flag | Purpose |
|------|---------|
| `--execute best\|safer\|upside` | Which strategy card to trade |
| `--dry-run` | Simulate without placing real orders |
| `--force` | Override no-trade guardrail for live execution |
| `--exchange deribit\|aevo` | Force all legs to one venue (default: auto-route) |
| `--max-slippage N` | Max allowed slippage % per fill (0=off) |
| `--quantity N` | Override contract quantity for all legs (0=default) |
| `--timeout N` | Seconds to wait for order fill before cancel (0=fire-and-forget) |
| `--screen none` | Skip analysis screens 1-4, show only execution (Screen 5) |

**Screen 5 (Execution):** order plan display, live confirmation prompt, per-leg results with slippage/latency metrics, auto-cancelled orders, execution timestamps.

**Decision log:** `execution` block now includes `started_at`, `finished_at`, per-fill `slippage_pct`/`latency_ms`/`timestamp`, `cancelled_orders`, `max_slippage_pct`, `timeout_seconds`, `quantity_override`.

### `README.md` — Updated documentation

- Exchange integration architecture (Synth → pipeline → quotes → routing → execution → lifecycle → safety)
- All CLI flags and env vars documented
- Test coverage description updated

## Testing

- [x] Tested against Synth API
- [x] Manually tested
- [x] Tests added/updated

### Test breakdown

**`test_executor.py`** — 54 tests:
- `TestInstrumentNames` (7) — Deribit/Aevo name builders, roundtrip parsing, edge cases
- `TestBuildPlan` (6) — single/multi-leg, exchange override, aevo names, auto-route, estimated cost
- `TestValidatePlan` (5) — valid plan, empty orders, zero price, zero quantity, empty instrument
- `TestDryRunExecutor` (12) — authenticate, buy/sell fills, missing strike, no-match fallback, **get_order_status, status not found, cancel_order, cancel not found, timestamp on result, slippage tracked**
- `TestExecuteFlow` (7) — single/multi-leg, net cost, auto-routing factory, **summary message, report timestamps**
- `TestGetExecutor` (5) — dry-run, dry-run ignores exchange, missing creds (Deribit/Aevo), unknown exchange
- `TestSlippage` (8) — buy worse/better, sell worse/better, zero expected, **slippage protection rejects, slippage protection allows**
- `TestQuantityOverride` (3) — **default quantity, override applied (single-leg), override applied (multi-leg)**

**`test_executor_e2e.py`** — 8 tests:
- Full pipeline → dry-run execution
- Guardrail: refuse live when no-trade, allow with force, allow dry-run, allow when no guardrail
- **Multi-leg execution pipeline** (spread → rank → build → dry-run → verify all legs + timestamps)
- **Non-crypto symbol skips execution** (SPY returns no exchange quotes)
- **Slippage protection E2E** (full pipeline with slippage guard → all pass)

**Verify:** `python3 -m pytest tools/options-gps/tests/ -v` → **178 passed** (119 existing + 59 new).

## Edge Cases Handled

| # | Scenario | Behavior |
|---|----------|----------|
| E1 | No API credentials | `get_executor` raises with clear env var message |
| E2 | Non-crypto symbol + execute | Exit 1: "Execution only supported for crypto assets" |
| E3 | No exchange quotes available | Exit 1: "exchange data not available" |
| E4 | Multi-leg partial failure | Auto-cancel filled legs; report which were cancelled |
| E5 | Instrument names per exchange | Deribit: `BTC-27MAR26-71000-C`; Aevo: `BTC-71000-C` |
| E6 | No-trade guardrail active | Refuse live execution unless `--force`; dry-run always allowed |
| E7 | Dry-run mode | No HTTP calls to exchange; simulates from quote data |
| E8 | Default CLI (no execute flags) | Unchanged — analysis screens only |
| E9 | Slippage exceeds threshold | Order rejected + cancelled; partial fills unwound |
| E10 | Order timeout | Polls status; cancels if still open after deadline |
| E11 | Negative sleep on monitor deadline | Clamped to 0 — no `ValueError` crash |
| E12 | Quantity override = 0 | Uses strategy default leg quantities |

## Environment Variables (live execution)

| Variable | Purpose |
|----------|---------|
| `DERIBIT_CLIENT_ID` / `DERIBIT_CLIENT_SECRET` | Deribit API credentials |
| `DERIBIT_TESTNET=1` | Use Deribit testnet |
| `AEVO_API_KEY` / `AEVO_API_SECRET` | Aevo REST API credentials |
| `AEVO_SIGNING_KEY` | Ethereum private key for EIP-712 order signing |
| `AEVO_WALLET_ADDRESS` | Maker wallet address (Ethereum) |
| `AEVO_TESTNET=1` | Use Aevo testnet |

## Checklist

- [x] Code follows project style guidelines
- [x] Self-review completed
- [x] Changes are documented (if applicable)

## Demo Video

https://screenrec.com/share/xM8Ibk2COs
53 changes: 33 additions & 20 deletions mock_data/exchange_options/aevo_BTC.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,40 @@
{"instrument_name": "BTC-69000-C", "strike": 69000, "option_type": "call"},
{"instrument_name": "BTC-69000-P", "strike": 69000, "option_type": "put"},
{"instrument_name": "BTC-70000-C", "strike": 70000, "option_type": "call"},
{"instrument_name": "BTC-70000-P", "strike": 70000, "option_type": "put"}
{"instrument_name": "BTC-70000-P", "strike": 70000, "option_type": "put"},
{"instrument_name": "BTC-71000-C", "strike": 71000, "option_type": "call"},
{"instrument_name": "BTC-71000-P", "strike": 71000, "option_type": "put"},
{"instrument_name": "BTC-72000-C", "strike": 72000, "option_type": "call"},
{"instrument_name": "BTC-72000-P", "strike": 72000, "option_type": "put"},
{"instrument_name": "BTC-73000-C", "strike": 73000, "option_type": "call"},
{"instrument_name": "BTC-73000-P", "strike": 73000, "option_type": "put"},
{"instrument_name": "BTC-74000-C", "strike": 74000, "option_type": "call"},
{"instrument_name": "BTC-74000-P", "strike": 74000, "option_type": "put"}
],
"order_books": {
"BTC-65000-C": {"bids": [[2800.0, 1.5, 52.5]], "asks": [[2900.0, 1.2, 54.0]]},
"BTC-65000-P": {"bids": [[0.85, 2.0, 51.5]], "asks": [[1.15, 1.8, 54.2]]},
"BTC-66000-C": {"bids": [[1830.0, 1.0, 51.8]], "asks": [[1900.0, 0.8, 53.2]]},
"BTC-66000-P": {"bids": [[16.00, 1.5, 51.0]], "asks": [[19.80, 1.2, 53.0]]},
"BTC-67000-C": {"bids": [[960.0, 2.0, 51.0]], "asks": [[1010.0, 1.5, 52.5]]},
"BTC-67000-P": {"bids": [[135.0, 1.0, 50.8]], "asks": [[148.0, 0.8, 52.2]]},
"BTC-67500-C": {"bids": [[620.0, 1.5, 50.5]], "asks": [[655.0, 1.0, 52.0]]},
"BTC-67500-P": {"bids": [[280.0, 1.2, 50.2]], "asks": [[305.0, 1.0, 51.8]]},
"BTC-68000-C": {"bids": [[360.0, 1.0, 50.0]], "asks": [[385.0, 0.8, 51.5]]},
"BTC-68000-P": {"bids": [[510.0, 1.5, 49.8]], "asks": [[542.0, 1.2, 51.2]]},
"BTC-68500-C": {"bids": [[190.0, 0.8, 49.5]], "asks": [[205.0, 0.5, 51.0]]},
"BTC-68500-P": {"bids": [[830.0, 1.0, 49.2]], "asks": [[870.0, 0.8, 50.8]]},
"BTC-69000-C": {"bids": [[88.0, 1.0, 49.0]], "asks": [[98.0, 0.8, 50.5]]},
"BTC-69000-P": {"bids": [[1210.0, 0.8, 48.8]], "asks": [[1280.0, 0.5, 50.2]]},
"BTC-70000-C": {"bids": [[14.0, 0.5, 48.2]], "asks": [[16.80, 0.3, 49.8]]},
"BTC-70000-P": {"bids": [[2120.0, 0.8, 48.0]], "asks": [[2220.0, 0.5, 49.5]]},

"BTC-65500-C": {"bids": [[2300.0, 1.0, 52.0]], "asks": [[2410.0, 0.8, 53.5]]},
"BTC-65500-P": {"bids": [[3.80, 1.5, 51.5]], "asks": [[5.00, 1.0, 53.5]]}
"BTC-65000-C": {"bids": [[5820.0, 1.5, 56.2]], "asks": [[5960.0, 1.2, 58.2]]},
"BTC-65000-P": {"bids": [[0.45, 2.0, 55.8]], "asks": [[1.60, 1.8, 57.8]]},
"BTC-66000-C": {"bids": [[4920.0, 1.0, 55.8]], "asks": [[5060.0, 0.8, 57.8]]},
"BTC-66000-P": {"bids": [[9.0, 1.5, 55.2]], "asks": [[26.0, 1.2, 57.2]]},
"BTC-67000-C": {"bids": [[4070.0, 2.0, 55.0]], "asks": [[4220.0, 1.5, 57.0]]},
"BTC-67000-P": {"bids": [[125.0, 1.0, 55.0]], "asks": [[155.0, 0.8, 56.8]]},
"BTC-67500-C": {"bids": [[3670.0, 1.5, 54.8]], "asks": [[3820.0, 1.0, 56.8]]},
"BTC-67500-P": {"bids": [[270.0, 1.2, 54.5]], "asks": [[315.0, 1.0, 56.2]]},
"BTC-68000-C": {"bids": [[4820.0, 1.5, 55.0]], "asks": [[4920.0, 1.2, 57.0]]},
"BTC-68000-P": {"bids": [[1610.0, 1.0, 55.2]], "asks": [[1680.0, 0.8, 56.8]]},
"BTC-68500-C": {"bids": [[4420.0, 0.8, 54.8]], "asks": [[4570.0, 0.5, 56.8]]},
"BTC-68500-P": {"bids": [[800.0, 1.0, 54.5]], "asks": [[910.0, 0.8, 56.2]]},
"BTC-69000-C": {"bids": [[4180.0, 2.0, 54.5]], "asks": [[4250.0, 1.5, 55.9]]},
"BTC-69000-P": {"bids": [[1935.0, 1.2, 54.1]], "asks": [[2005.0, 1.0, 55.5]]},
"BTC-70000-C": {"bids": [[3540.0, 1.5, 53.2]], "asks": [[3610.0, 1.0, 54.6]]},
"BTC-70000-P": {"bids": [[2325.0, 1.0, 53.5]], "asks": [[2360.0, 0.8, 54.2]]},
"BTC-71000-C": {"bids": [[2970.0, 2.0, 52.3]], "asks": [[3040.0, 1.5, 53.6]]},
"BTC-71000-P": {"bids": [[2750.0, 1.5, 52.5]], "asks": [[2790.0, 1.0, 53.2]]},
"BTC-72000-C": {"bids": [[2470.0, 1.0, 51.7]], "asks": [[2540.0, 0.8, 53.0]]},
"BTC-72000-P": {"bids": [[3215.0, 1.2, 51.8]], "asks": [[3290.0, 1.0, 52.5]]},
"BTC-73000-C": {"bids": [[2040.0, 1.5, 51.4]], "asks": [[2080.0, 1.0, 52.0]]},
"BTC-73000-P": {"bids": [[3785.0, 1.0, 50.8]], "asks": [[3860.0, 0.8, 52.1]]},
"BTC-74000-C": {"bids": [[1645.0, 0.8, 50.7]], "asks": [[1685.0, 0.5, 51.4]]},
"BTC-74000-P": {"bids": [[4360.0, 1.0, 49.3]], "asks": [[4530.0, 0.8, 52.8]]}
}
}
80 changes: 48 additions & 32 deletions mock_data/exchange_options/deribit_BTC.json
Original file line number Diff line number Diff line change
@@ -1,38 +1,54 @@
{
"instruments": [
{"instrument_name": "BTC-26FEB26-65000-C", "strike": 65000, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-65000-P", "strike": 65000, "option_type": "put"},
{"instrument_name": "BTC-26FEB26-66000-C", "strike": 66000, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-66000-P", "strike": 66000, "option_type": "put"},
{"instrument_name": "BTC-26FEB26-67000-C", "strike": 67000, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-67000-P", "strike": 67000, "option_type": "put"},
{"instrument_name": "BTC-26FEB26-67500-C", "strike": 67500, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-67500-P", "strike": 67500, "option_type": "put"},
{"instrument_name": "BTC-26FEB26-68000-C", "strike": 68000, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-68000-P", "strike": 68000, "option_type": "put"},
{"instrument_name": "BTC-26FEB26-68500-C", "strike": 68500, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-68500-P", "strike": 68500, "option_type": "put"},
{"instrument_name": "BTC-26FEB26-69000-C", "strike": 69000, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-69000-P", "strike": 69000, "option_type": "put"},
{"instrument_name": "BTC-26FEB26-70000-C", "strike": 70000, "option_type": "call"},
{"instrument_name": "BTC-26FEB26-70000-P", "strike": 70000, "option_type": "put"}
{"instrument_name": "BTC-27MAR26-65000-C", "strike": 65000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-65000-P", "strike": 65000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-66000-C", "strike": 66000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-66000-P", "strike": 66000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-67000-C", "strike": 67000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-67000-P", "strike": 67000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-67500-C", "strike": 67500, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-67500-P", "strike": 67500, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-68000-C", "strike": 68000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-68000-P", "strike": 68000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-68500-C", "strike": 68500, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-68500-P", "strike": 68500, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-69000-C", "strike": 69000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-69000-P", "strike": 69000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-70000-C", "strike": 70000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-70000-P", "strike": 70000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-71000-C", "strike": 71000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-71000-P", "strike": 71000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-72000-C", "strike": 72000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-72000-P", "strike": 72000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-73000-C", "strike": 73000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-73000-P", "strike": 73000, "option_type": "put"},
{"instrument_name": "BTC-27MAR26-74000-C", "strike": 74000, "option_type": "call"},
{"instrument_name": "BTC-27MAR26-74000-P", "strike": 74000, "option_type": "put"}
],
"order_books": {
"BTC-26FEB26-65000-C": {"bid": 2780.0, "ask": 2920.0, "mark_price": 2847.68, "bid_iv": 52.1, "ask_iv": 54.3},
"BTC-26FEB26-65000-P": {"bid": 0.90, "ask": 1.10, "mark_price": 0.99, "bid_iv": 51.8, "ask_iv": 53.9},
"BTC-26FEB26-66000-C": {"bid": 1810.0, "ask": 1920.0, "mark_price": 1864.60, "bid_iv": 51.5, "ask_iv": 53.5},
"BTC-26FEB26-66000-P": {"bid": 15.50, "ask": 20.30, "mark_price": 17.91, "bid_iv": 51.2, "ask_iv": 53.2},
"BTC-26FEB26-67000-C": {"bid": 950.0, "ask": 1025.0, "mark_price": 987.04, "bid_iv": 50.8, "ask_iv": 52.8},
"BTC-26FEB26-67000-P": {"bid": 130.0, "ask": 152.0, "mark_price": 140.36, "bid_iv": 50.5, "ask_iv": 52.5},
"BTC-26FEB26-67500-C": {"bid": 610.0, "ask": 660.0, "mark_price": 638.43, "bid_iv": 50.2, "ask_iv": 52.2},
"BTC-26FEB26-67500-P": {"bid": 275.0, "ask": 310.0, "mark_price": 291.75, "bid_iv": 50.0, "ask_iv": 52.0},
"BTC-26FEB26-68000-C": {"bid": 355.0, "ask": 390.0, "mark_price": 373.27, "bid_iv": 49.8, "ask_iv": 51.8},
"BTC-26FEB26-68000-P": {"bid": 505.0, "ask": 548.0, "mark_price": 526.59, "bid_iv": 49.5, "ask_iv": 51.5},
"BTC-26FEB26-68500-C": {"bid": 185.0, "ask": 210.0, "mark_price": 197.11, "bid_iv": 49.2, "ask_iv": 51.2},
"BTC-26FEB26-68500-P": {"bid": 820.0, "ask": 880.0, "mark_price": 850.42, "bid_iv": 49.0, "ask_iv": 51.0},
"BTC-26FEB26-69000-C": {"bid": 85.0, "ask": 102.0, "mark_price": 93.43, "bid_iv": 48.8, "ask_iv": 50.8},
"BTC-26FEB26-69000-P": {"bid": 1200.0, "ask": 1295.0, "mark_price": 1246.74, "bid_iv": 48.5, "ask_iv": 50.5},
"BTC-26FEB26-70000-C": {"bid": 13.0, "ask": 17.50, "mark_price": 15.13, "bid_iv": 48.0, "ask_iv": 50.0},
"BTC-26FEB26-70000-P": {"bid": 2100.0, "ask": 2240.0, "mark_price": 2168.44, "bid_iv": 47.8, "ask_iv": 49.8}
"BTC-27MAR26-65000-C": {"bid": 5800.0, "ask": 5950.0, "mark_price": 5870.0, "bid_iv": 56.0, "ask_iv": 58.0},
"BTC-27MAR26-65000-P": {"bid": 0.50, "ask": 1.50, "mark_price": 0.99, "bid_iv": 55.5, "ask_iv": 57.5},
"BTC-27MAR26-66000-C": {"bid": 4900.0, "ask": 5050.0, "mark_price": 4970.0, "bid_iv": 55.5, "ask_iv": 57.5},
"BTC-27MAR26-66000-P": {"bid": 10.0, "ask": 25.0, "mark_price": 17.91, "bid_iv": 55.0, "ask_iv": 57.0},
"BTC-27MAR26-67000-C": {"bid": 4050.0, "ask": 4200.0, "mark_price": 4120.0, "bid_iv": 54.8, "ask_iv": 56.8},
"BTC-27MAR26-67000-P": {"bid": 120.0, "ask": 160.0, "mark_price": 140.36, "bid_iv": 54.5, "ask_iv": 56.5},
"BTC-27MAR26-67500-C": {"bid": 3650.0, "ask": 3800.0, "mark_price": 3720.0, "bid_iv": 54.5, "ask_iv": 56.5},
"BTC-27MAR26-67500-P": {"bid": 260.0, "ask": 320.0, "mark_price": 291.75, "bid_iv": 54.2, "ask_iv": 56.2},
"BTC-27MAR26-68000-C": {"bid": 4805.0, "ask": 4910.0, "mark_price": 4890.0, "bid_iv": 54.7, "ask_iv": 56.9},
"BTC-27MAR26-68000-P": {"bid": 1602.0, "ask": 1673.0, "mark_price": 1673.0, "bid_iv": 55.0, "ask_iv": 56.5},
"BTC-27MAR26-68500-C": {"bid": 4400.0, "ask": 4550.0, "mark_price": 4480.0, "bid_iv": 54.5, "ask_iv": 56.5},
"BTC-27MAR26-68500-P": {"bid": 780.0, "ask": 920.0, "mark_price": 850.42, "bid_iv": 54.2, "ask_iv": 56.2},
"BTC-27MAR26-69000-C": {"bid": 4165.0, "ask": 4235.0, "mark_price": 4214.0, "bid_iv": 54.3, "ask_iv": 55.7},
"BTC-27MAR26-69000-P": {"bid": 1922.0, "ask": 1993.0, "mark_price": 1993.0, "bid_iv": 53.9, "ask_iv": 55.3},
"BTC-27MAR26-70000-C": {"bid": 3523.0, "ask": 3594.0, "mark_price": 3573.0, "bid_iv": 53.0, "ask_iv": 54.4},
"BTC-27MAR26-70000-P": {"bid": 2314.0, "ask": 2349.0, "mark_price": 2349.0, "bid_iv": 53.3, "ask_iv": 54.0},
"BTC-27MAR26-71000-C": {"bid": 2954.0, "ask": 3025.0, "mark_price": 2982.0, "bid_iv": 52.1, "ask_iv": 53.4},
"BTC-27MAR26-71000-P": {"bid": 2741.0, "ask": 2776.0, "mark_price": 2762.0, "bid_iv": 52.3, "ask_iv": 53.0},
"BTC-27MAR26-72000-C": {"bid": 2455.0, "ask": 2527.0, "mark_price": 2498.0, "bid_iv": 51.5, "ask_iv": 52.8},
"BTC-27MAR26-72000-P": {"bid": 3202.0, "ask": 3274.0, "mark_price": 3274.0, "bid_iv": 51.6, "ask_iv": 52.3},
"BTC-27MAR26-73000-C": {"bid": 2029.0, "ask": 2064.0, "mark_price": 2064.0, "bid_iv": 51.2, "ask_iv": 51.8},
"BTC-27MAR26-73000-P": {"bid": 3772.0, "ask": 3844.0, "mark_price": 3837.0, "bid_iv": 50.6, "ask_iv": 51.9},
"BTC-27MAR26-74000-C": {"bid": 1637.0, "ask": 1673.0, "mark_price": 1673.0, "bid_iv": 50.5, "ask_iv": 51.2},
"BTC-27MAR26-74000-P": {"bid": 4342.0, "ask": 4520.0, "mark_price": 4449.0, "bid_iv": 49.1, "ask_iv": 52.6}
}
}
Loading
Loading