Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions tools/options-gps/PR_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# PR: Options GPS Autonomous Execution (Issue #26)

## Summary

Adds **autonomous trade execution** to Options GPS. The tool now supports submitting the recommended strategy directly to Deribit or Aevo, with a dry-run mode for simulated execution using mock exchange data. No changes to `pipeline.py` or `exchange.py` — the executor consumes their data classes and functions.

Closes #26

## What's New

- **`executor.py`** — new execution engine with:
- **Data classes**: `OrderRequest` (with strike/option_type for self-contained quote lookup), `OrderResult`, `ExecutionPlan`, `ExecutionReport`
- **Instrument name builders**: `deribit_instrument_name()` → `BTC-26FEB26-67500-C` (ISO 8601 → DDMonYY), `aevo_instrument_name()` → `BTC-67500-C`
- **ABC executor pattern**: `BaseExecutor` with three implementations:
- `DryRunExecutor` — offline simulation using exchange quote data, no network calls
- `DeribitExecutor` — REST API with Bearer token auth (`/public/auth` → `/private/buy|sell`)
- `AevoExecutor` — REST API with per-request HMAC-SHA256 signing (`AEVO-KEY`, `AEVO-TIMESTAMP`, `AEVO-SIGNATURE` headers)
- **Orchestration**: `build_execution_plan()` with auto-routing via `leg_divergences()` from `exchange.py`, `validate_plan()` pre-flight checks, `execute_plan()` with partial-fill warnings, `get_executor()` factory reading credentials from env vars

- **CLI integration** (`main.py`) — 3 new flags:
- `--execute` — submit live orders (requires exchange credentials)
- `--dry-run` — simulate execution with mock exchange data (no API keys needed)
- `--exchange deribit|aevo` — force exchange (default: auto-route each leg to best venue)
- **Screen 5: Execution** — displays order plan, confirmation prompt (live mode), per-leg fill results, net cost summary
- Decision log JSON includes `"execution"` key with mode, fills, net cost

- **Test coverage** — 37 new tests (156 total, all passing):
- `test_executor.py`: class-grouped unit tests — `TestInstrumentNames` (7), `TestBuildPlan` (6), `TestValidatePlan` (5), `TestDryRunExecutor` (6), `TestExecuteFlow` (4), `TestGetExecutor` (5)
- `test_executor_e2e.py`: full pipeline E2E — mock data → rank → build plan → dry-run execute → verify report

## Files Changed

| File | Change |
|------|--------|
| `tools/options-gps/executor.py` | **New** — execution engine (~290 lines) |
| `tools/options-gps/main.py` | Add `--execute`, `--dry-run`, `--exchange` flags + Screen 5 (~105 lines) |
| `tools/options-gps/tests/test_executor.py` | **New** — 33 unit tests in 6 class groups |
| `tools/options-gps/tests/test_executor_e2e.py` | **New** — 3 E2E tests |

**Not modified**: `pipeline.py`, `exchange.py`, `requirements.txt`, `conftest.py`

## Environment Variables

| Variable | Purpose | Required for |
|---|---|---|
| `DERIBIT_CLIENT_ID` | Deribit API key | `--execute --exchange deribit` |
| `DERIBIT_CLIENT_SECRET` | Deribit API secret | same |
| `DERIBIT_TESTNET=1` | Use Deribit testnet | optional |
| `AEVO_API_KEY` | Aevo API key | `--execute --exchange aevo` |
| `AEVO_API_SECRET` | Aevo HMAC secret | same |
| `AEVO_TESTNET=1` | Use Aevo testnet | optional |

None needed for `--dry-run`.

## Test Plan

- [ ] `python3 -m pytest tools/options-gps/tests/ -v` — all 156 tests pass
- [ ] `python3 tools/options-gps/main.py --symbol BTC --view bullish --risk medium --dry-run --no-prompt` — full dry-run flow with Screen 5
- [ ] `python3 tools/options-gps/main.py --symbol BTC --view bullish --risk medium --no-prompt` — analysis-only flow unchanged (no Screen 5)
- [ ] `python3 tools/options-gps/main.py --symbol SPY --view bullish --risk medium --dry-run --no-prompt` — non-crypto graceful skip
- [ ] `python3 tools/options-gps/main.py --symbol BTC --view bullish --risk low --dry-run --exchange deribit --no-prompt` — forced exchange routing
74 changes: 73 additions & 1 deletion tools/options-gps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Turn a trader's view into one clear options decision. Inputs: **symbol**, **mark
- **Screen 2 (Top Plays):** Three ranked cards: Best Match (highest score for view), Safer Alternative (higher win probability), Higher Upside (higher expected payoff). Each shows why it fits, chance of profit, max loss, "Review again at" time.
- **Screen 3 (Why This Works):** Distribution view and plain-English explanation for the best match (Synth 1h + 24h fusion state, required market behavior).
- **Screen 4 (If Wrong):** Exit rule, convert/roll rule, time-based reassessment rule.
- **Screen 5 (Execution):** When `--execute` or `--dry-run` is used, shows order plan, optional confirmation (live only), and per-leg fill results with net cost.

**Guardrails:** No-trade state when confidence is low, signals conflict (e.g. 1h vs 24h countermove), volatility is very high (directional views), or no vol edge exists (vol view with similar Synth/market IV).

Expand All @@ -28,6 +29,60 @@ Turn a trader's view into one clear options decision. Inputs: **symbol**, **mark
7. **Guardrails:** Filters no-trade when fusion is countermove/unclear with directional view, volatility exceeds threshold (directional views), confidence is too low, or vol bias is neutral (vol view — no exploitable divergence between Synth and market IV).
8. **Risk Management:** Each strategy type has a specific risk plan (invalidation trigger, adjustment/reroute rule, review schedule). Short straddle/strangle are labeled "unlimited risk" with hard stops at 2x credit loss; they are risk-gated (high-only for short straddle, medium+ for short strangle).

## Exchange integration architecture

Data flow for crypto assets (BTC, ETH, SOL):

1. **Synth** → forecast percentiles, option pricing, volatility (via `SynthClient`).
2. **Pipeline** → strategy generation, payoff/EV, ranking (with optional exchange divergence bonus).
3. **Exchange (read)** → `exchange.py` fetches live or mock quotes from Deribit and Aevo; `leg_divergences()` computes per-leg best venue and price (lowest ask for BUY, highest bid for SELL).
4. **Execution** → `executor.py` builds an `ExecutionPlan` from the chosen strategy card, resolves instrument names per exchange (Deribit: `BTC-DDMonYY-STRIKE-C|P`; Aevo: `BTC-STRIKE-C|P`), and either simulates (dry-run) or submits orders. Deribit uses REST with Bearer token auth; Aevo uses REST with HMAC-SHA256 signing. When `--exchange` is not set, each leg is auto-routed to its best venue (per `leg_divergences`).

Credentials are read from the environment (no secrets in code). Dry-run requires no credentials.

## Execution

Execution is supported only for **crypto assets** (BTC, ETH, SOL). Use `--execute` to submit live orders or `--dry-run` to simulate without placing orders. Non-crypto symbols exit with an error.

**CLI flags:**

| Flag | Description |
|------|-------------|
| `--execute [best\|safer\|upside]` | Submit live orders for the chosen card (default: `best`). |
| `--dry-run [best\|safer\|upside]` | Simulate execution using exchange quotes; no API keys, no real orders. |
| `--exchange deribit\|aevo` | Force all legs to one exchange. Default: auto-route each leg to best venue. |
| `--force` | Override no-trade guardrail for live execution. |
| `--size N` | Position size multiplier (scales all leg quantities and max loss). |
| `--max-slippage PCT` | Halt execution if any fill exceeds this slippage percentage. |
| `--max-loss USD` | Pre-trade risk check: reject if strategy max loss exceeds this budget. |
| `--timeout SECS` | Order monitoring timeout in seconds (default: 30). |
| `--log-file PATH` | Save full execution report JSON to file (audit trail). |

**Exchange protocols:**

- **Deribit**: JSON-RPC 2.0 over POST with Bearer token auth. Uses `contracts` parameter for unambiguous option sizing. Converts USD prices to BTC via index price lookup (`_get_index_price`), snaps to live order book best bid/ask (`_get_book_price`), and aligns to tick size (0.0005 BTC). Retries on transient errors (429, 502, 503, timeout) with exponential backoff.
- **Aevo**: REST API with per-request HMAC-SHA256 signing (`AEVO-KEY`, `AEVO-TIMESTAMP`, `AEVO-SIGNATURE` headers). Retries on transient errors.

**Auto-routing**: When `--exchange` is not set, each leg is auto-routed to its best venue via `leg_divergences()`. For live execution, a per-exchange executor factory creates and caches separate authenticated sessions.

**Safety features:**
- Guardrail blocks live execution when no-trade reason is active (override with `--force`). Dry-run is always allowed.
- Slippage protection halts multi-leg execution and warns about filled legs needing manual close.
- Max loss budget rejects plans before any orders are sent.
- Partial fill detection warns about filled legs on failure.
- Execution log JSON includes timestamp, per-fill slippage, and complete order/result audit.

**Environment variables (live execution only):**

| Variable | Purpose |
|----------|---------|
| `DERIBIT_CLIENT_ID` / `DERIBIT_CLIENT_SECRET` | Deribit API credentials |
| `DERIBIT_TESTNET=1` | Use Deribit testnet |
| `AEVO_API_KEY` / `AEVO_API_SECRET` | Aevo API credentials |
| `AEVO_TESTNET=1` | Use Aevo testnet |

None needed for `--dry-run`.

## Synth API usage

- **`get_prediction_percentiles(asset, horizon)`** — 1h and 24h probabilistic price forecasts; used for fusion state and for payoff/EV (outcome distribution at expiry).
Expand All @@ -43,6 +98,23 @@ python tools/options-gps/main.py

# Vol view directly from CLI
python tools/options-gps/main.py --symbol BTC --view vol --risk medium --no-prompt

# Simulate execution — best match (default), no API keys needed
python tools/options-gps/main.py --symbol BTC --view bullish --risk medium --dry-run --no-prompt

# Dry-run the safer alternative instead
python tools/options-gps/main.py --symbol BTC --view bullish --risk medium --dry-run safer --no-prompt

# Execute best match on exchange (requires credentials)
python tools/options-gps/main.py --symbol BTC --view bullish --risk medium --execute --no-prompt

# Execute the higher-upside card on Deribit, 3x size, with risk controls
python tools/options-gps/main.py --symbol ETH --view bearish --risk high \
--execute upside --exchange deribit --size 3 --max-slippage 2.0 --max-loss 5000 \
--log-file /tmp/eth_exec.json --no-prompt

# Force execution despite no-trade guardrail
python tools/options-gps/main.py --symbol BTC --view bullish --risk medium --execute --force --no-prompt
```

Prompts: symbol (default BTC), view (bullish/bearish/neutral/vol), risk (low/medium/high). Uses mock data when no `SYNTH_API_KEY` is set.
Expand All @@ -51,4 +123,4 @@ Prompts: symbol (default BTC), view (bullish/bearish/neutral/vol), risk (low/med

From repo root: `python -m pytest tools/options-gps/tests/ -v`. No API key required (mock data).

Test coverage includes: forecast fusion, strategy generation (all views including vol), PnL calculations for all strategy types, CDF-weighted PoP/EV, ranking with vol bias, vol-specific guardrails, IV estimation, vol comparison, risk plans, hard filters, exchange data fetching/parsing, divergence computation, line shopping ranking integration, and end-to-end scripted tests.
Test coverage includes: forecast fusion, strategy generation (all views including vol), PnL calculations for all strategy types, CDF-weighted PoP/EV, ranking with vol bias, vol-specific guardrails, IV estimation, vol comparison, risk plans, hard filters, exchange data fetching/parsing, divergence computation, line shopping ranking integration, execution (instrument names, plan build/validate, dry-run executor, execution flow, auto-routing factory, slippage computation/protection, max loss budget validation, size multiplier, execution log save/load, retry logic for transient errors, per-exchange factory routing), full-pipeline-to-dry-run E2E, and end-to-end scripted tests.
Loading
Loading