Skip to content

feat(options-gps): market line shopping — live exchange pricing, z-score edge detection, execution routing#39

Merged
e35ventura merged 6 commits intoentrius:mainfrom
eureka928:feature/issue-32-market-line-shopping
Mar 12, 2026
Merged

feat(options-gps): market line shopping — live exchange pricing, z-score edge detection, execution routing#39
e35ventura merged 6 commits intoentrius:mainfrom
eureka928:feature/issue-32-market-line-shopping

Conversation

@eureka928
Copy link
Contributor

@eureka928 eureka928 commented Mar 12, 2026

Summary

Adds Market Line Shopping to Options GPS — compares Synth's theoretical option prices against live exchange data (Deribit, Aevo) to find mispricing edges using statistical z-score analysis, then routes each strategy leg to the best execution venue. Like a sports bettor shopping lines across books.

Closes #32

What's New

  • exchange.py — new module with:

    • Live API fetchers: _fetch_deribit_live() (single request via get_book_summary_by_currency), _fetch_aevo_live() (parallel orderbook fetches via ThreadPoolExecutor, capped at 40 instruments). Falls back to mock data when no API connectivity.
    • Z-score edge detection: compute_edge() computes population std dev across all pricing sources (Synth + exchanges) with a noise floor at 0.1% of market mean. Labels: STRONG (|z|≥2.0), MODERATE (|z|≥1.0), WEAK (|z|≥0.5), NONE.
    • Action-aware execution routing: best_execution_price() — BUY legs route to lowest ask, SELL legs route to highest bid across venues.
    • ExchangeQuote and EdgeMetrics dataclasses, leg_divergences(), strategy_divergence().
    • Crypto only (BTC, ETH, SOL) — non-crypto assets gracefully skip with no exchange data.
  • Pipeline integrationrank_strategies() accepts divergence_by_strategy mapping id(candidate) → z_score. Applies clamped ±0.15 additive bonus (z * 0.06) after confidence multiplier. No changes to ScoredStrategy dataclass — fully backward compatible.

  • High-signal UI — Market Line Shopping table on Screen 1b with call/put side-by-side per strike:

    • All columns: Synth Fair, Deribit mid, Aevo mid, * Exec (best venue + ask price), Edge (z-score σ)
    • ATM strike marker, per-leg annotations in strategy cards: ★ Buy @ AEVO ask $655 — edge +1.5σ
    • Decision log includes exchange_edge_zscore and exchange_edge_label per strategy
  • Mock data — 6 JSON files (deribit_BTC/ETH/SOL.json, aevo_BTC/ETH/SOL.json) with intentional ±1-5% price variation from Synth fair values for testable divergence scenarios.

Related Issues

Closes #32

Type of Change

  • Bug fix
  • Improvement to existing tool
  • Documentation
  • Other (describe below)

Testing

  • Tested against Synth API
  • Manually tested
  • Tests added/updated

Test command: python -m pytest tools/options-gps/tests/ -v
Result: 119 passed (80 existing + 36 exchange + 3 e2e) in 0.09s

Checklist

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

Files Changed

File Change
mock_data/exchange_options/*.json New — 6 mock exchange response files for BTC/ETH/SOL
tools/options-gps/exchange.py New — Live + mock fetchers, z-score edge detection, action-aware routing (~360 lines)
tools/options-gps/pipeline.py Added divergence_by_strategy param to rank_strategies() (+10 lines)
tools/options-gps/main.py Wired exchange data into pipeline, side-by-side line shopping table, per-leg annotations, decision log (+165 lines)
tools/options-gps/tests/conftest.py New — Shared fixtures for exchange tests
tools/options-gps/tests/test_exchange.py New — 36 tests (fetch, best price, edge detection, divergence, ranking)
tools/options-gps/tests/test_line_shopping_e2e.py New — 3 end-to-end integration tests
tools/options-gps/README.md Added Market Line Shopping section

CLI Output: BTC Bullish (Crypto)


┌── Screen 1: View Setup ────────────────────────────────────────────────┐
│  Symbol: BTC (from --symbol)
│  View: bullish (from --view)
│  Risk: medium (from --risk)
│
│  ════════════════════════════════════════════════════════════
│    ▲ BTC  BULLISH  MEDIUM RISK
│  ════════════════════════════════════════════════════════════
│    Strategy scan : directional long/spread
│    Risk profile  : balanced risk/reward
│    Data sources  : Synth 1h + 24h forecasts, option pricing
└────────────────────────────────────────────────────────────────────────┘

┌── Market Context: BTC ─────────────────────────────────────────────────┐
│    Price:.............. $67,723.50
│    Confidence:......... [███████░░░░░░░░░░░░░░░░░░] 29% LOW
│    Forecast fusion:.... Unclear (1h + 24h)
│    Volatility:......... fwd 62.4% / realized 56.6% (ratio 1.10x) [Normal]
│
│  ═══ MARKET LINE SHOPPING ══════════════════════════════
│      Strike                     CALL                   │                   PUT                  
│                  Synth    DER    AEV     * Exec   Edge │   Synth    DER    AEV     * Exec   Edge
│    ─────────────────────────────────────────────────────────────────────────────────────────────
│      66,500      1,404    ---    ---        ---    --- │      57    ---    ---        ---    ---
│      67,000        987    988    985  AEV 1,010  +0.7σ │     140    141    142  AEV   148  -1.9σ
│      67,500 ◀      638    635    638  AEV   655  +1.5σ │     292    292    292  AEV   305  -2.1σ
│      68,000        373    372    372  AEV   385  +2.1σ │     527    526    526  AEV   542  +0.6σ
│      68,500        197    198    198  AEV   205  -2.0σ │     850    850    850  AEV   870  +0.5σ
│    ─────────────────────────────────────────────────────────────────────────────────────────────
│    * Exec = best execution venue ask price (DER=Deribit, AEV=Aevo)
│
│    1h range  : $    67,084 (-0.9%)  ─  $67,698  ─  $68,338 (+0.9%)
│    24h range : $    64,410 (-4.9%)  ─  $67,898  ─  $72,010 (+6.3%)
│
│    ⚠  GUARDRAIL: Signals unclear — no strong directional conviction from forecasts.
└────────────────────────────────────────────────────────────────────────┘

┌── Screen 2: Top Plays ─────────────────────────────────────────────────┐
│  ⚠  NO TRADE RECOMMENDED
│  Reason: Signals unclear — no strong directional conviction from forecasts.
│  Confidence: [███████░░░░░░░░░░░░░░░░░░] 29% LOW
│
│  The following are tentative alternatives (use with extreme caution):
│
│                                           ~Best                  ~Safer                 ~Upside
│                          ──────────────────────  ──────────────────────  ──────────────────────
│    Strategy                     Long call (ATM)  Bull put credit spread         Long call (OTM)
│    PoP                                      46%                     55%                     40%
│    Expected Value                  $542 (+0.8%)            $-58 (-0.1%)            $498 (+0.7%)
│    Max Loss                                $638                    $349                    $197
│    Net Cost                          $638 debit             $151 credit              $197 debit
│    Risk Type                    premium at risk            defined risk         premium at risk
│
│
│  ~ Tentative Best: Long call (ATM)
│  ═══ CONSTRUCTION ══════════════════════════════════════
│    BUY  1x BTC $67,500 Call  @ $638.43
│      ★ Buy @ AEVO ask $655.00 — edge +1.5σ ◆
│    Net Debit: $638.43  |  Expiry: 2026-02-26 08:00:00Z
│  ═══ METRICS ═══════════════════════════════════════════
│    PoP        : 46%
│    EV         : $542 (+0.80%)
│    Profit     : Unlimited upside if BTC > $68,138 (breakeven)
│    Max Loss   : $638 (premium at risk)
│    Risk Meter : [█░░░░░░░░░] 0.94% of price
│    Tail Risk  : $638 (worst 20% avg loss)
│  ═══ PLAN ══════════════════════════════════════════════
│    Exit       : Close if option value drops below $319 (50% of premium). Stop: price < $65,475.
│    Adjust     : Sell higher-strike call to convert into vertical spread. Or roll to next expiry if thesis holds.
│    Review     : Breakeven: $68,138. Review at 50% time-to-expiry before 2026-02-26 08:00:00Z.
│
│  ~ Tentative Safer: Bull put credit spread
│  ═══ CONSTRUCTION ══════════════════════════════════════
│    SELL 1x BTC $67,500 Put  @ $291.75
│      ★ Sell @ AEVO bid $280.00 — edge -2.1σ ◆
│    BUY  1x BTC $67,000 Put  @ $140.36
│      ★ Buy @ AEVO ask $148.00 — edge -1.9σ ◆
│    Net Credit: $151.39  |  Expiry: 2026-02-26 08:00:00Z
│  ═══ METRICS ═══════════════════════════════════════════
│    PoP        : 55%
│    EV         : $-58 (-0.09%)
│    Max Profit : $151 — $151 credit kept if BTC >= $67,500 at expiry
│    Max Loss   : $349 (defined risk)
│    Risk Meter : [█░░░░░░░░░] 0.51% of price
│    Tail Risk  : $349 (worst 20% avg loss)
│  ═══ PLAN ══════════════════════════════════════════════
│    Exit       : Close if underlying drops below $67,500 (short strike) with momentum. Max loss: $349.
│    Adjust     : Roll short $67,500 put down and out for additional credit. Or close tested side only.
│    Review     : Breakeven: $67,349. Keep full $151 credit if above $67,500 at expiry.
│
│  ~ Tentative Upside: Long call (OTM)
│  ═══ CONSTRUCTION ══════════════════════════════════════
│    BUY  1x BTC $68,500 Call  @ $197.11
│      ★ Buy @ AEVO ask $205.00 — edge -2.0σ ◆
│    Net Debit: $197.11  |  Expiry: 2026-02-26 08:00:00Z
│  ═══ METRICS ═══════════════════════════════════════════
│    PoP        : 40%
│    EV         : $498 (+0.74%)
│    Profit     : Unlimited upside if BTC > $68,697 (breakeven)
│    Max Loss   : $197 (premium at risk)
│    Risk Meter : [░░░░░░░░░░] 0.29% of price
│    Tail Risk  : $197 (worst 20% avg loss)
│  ═══ PLAN ══════════════════════════════════════════════
│    Exit       : Close if option value drops below $99 (50% of premium). Stop: price < $66,445.
│    Adjust     : Sell higher-strike call to convert into vertical spread. Or roll to next expiry if thesis holds.
│    Review     : Breakeven: $68,697. Review at 50% time-to-expiry before 2026-02-26 08:00:00Z.
└────────────────────────────────────────────────────────────────────────┘

┌── Screen 3: Why This Works ────────────────────────────────────────────┐
│  ⚠  Guardrail active: Signals unclear — no strong directional conviction from forecasts.
│     Tentative analysis only — not a trade signal.
│
│  ═══ 24h PRICE DISTRIBUTION ════════════════════════════
│    $    64,410 ( -4.9%)  ▓░░░░░░░░░░░░░░░░░░░   5%
│    $    66,070 ( -2.4%)  ▓▓▓▓░░░░░░░░░░░░░░░░  20%
│    $    67,018 ( -1.0%)  ▓▓▓▓▓▓▓░░░░░░░░░░░░░  35%
│    $    67,898 ( +0.3%)  ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░  50%  ← median
│    $    68,810 ( +1.6%)  ▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░  65%
│    $    69,900 ( +3.2%)  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░  80%
│    $    72,010 ( +6.3%)  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░  95%
│
│  ═══ 1h FORECAST PATH ══════════════════════════════════
│               5th pctl      median   95th pctl
│        0m   $    67,665  $    67,665  $    67,665
│       15m   $    67,371  $    67,673  $    67,989
│       30m   $    67,251  $    67,681  $    68,131
│       45m   $    67,163  $    67,687  $    68,249
│       60m   $    67,084  $    67,698  $    68,338
│
│  ═══ 24h FORECAST PATH ═════════════════════════════════
│               5th pctl      median   95th pctl
│        0h   $    67,638  $    67,638  $    67,638
│        6h   $    66,043  $    67,715  $    69,378
│       12h   $    65,727  $    67,747  $    69,970
│       18h   $    64,807  $    67,846  $    71,086
│       24h   $    64,410  $    67,898  $    72,010
│
│  ═══ PAYOFF: Long call (ATM) ═══════════════════════════
│    $    64,410 ( 5%) ░░               -$638
│    $    66,070 (20%) ░░               -$638
│    $    67,018 (35%) ░░               -$638
│    $    67,898 (50%)                  -$240
│    $    68,810 (65%) ██               +$672
│    $    69,900 (80%) ██████           +$1,762
│    $    72,010 (95%) ███████████████  +$3,871
│
│  ═══ VERDICT ═══════════════════════════════════════════
│    Thesis   : BTC bullish — needs to rise above $68,138 (breakeven)
│    Forecast : Synth 24h median $67,898 (+0.3%, above current)
│    PoP      : 46%
│    Risk     : medium — max loss $638
│
│    ⚠  No trade recommended despite analysis. Signals are insufficient.
└────────────────────────────────────────────────────────────────────────┘

┌── Screen 4: If Wrong ──────────────────────────────────────────────────┐
│  ⚠  Tentative — no active trade recommended
│
│  ═══ POSITION: Long call (ATM) ═════════════════════════
│    BUY 1x BTC $67,500 Call @ $638.43
│    Max Loss   : $638 (premium at risk)
│    Risk Meter : [█░░░░░░░░░] 0.94% of price
│  ═══ SCENARIOS ═════════════════════════════════════════
│    Best case  : BTC @ $72,010  →  P/L +3,871
│    Worst case : BTC @ $64,410  →  P/L -638
│  ═══ EXIT RULES ════════════════════════════════════════
│    Close if option value drops below $319 (50% of premium). Stop: price < $65,475.
│  ═══ ADJUSTMENT PLAYBOOK ═══════════════════════════════
│    Sell higher-strike call to convert into vertical spread. Or roll to next expiry if thesis holds.
│  ═══ KEY LEVELS & REVIEW ═══════════════════════════════
│    Breakeven: $68,138. Review at 50% time-to-expiry before 2026-02-26 08:00:00Z.
│    Expiry : 2026-02-26 08:00:00Z
│    Review : at 50% time-to-expiry and on any >1% BTC move
└────────────────────────────────────────────────────────────────────────┘

┌── Decision Log (JSON) ─────────────────────────────────────────────────┐
│  {
│    "inputs": {
│      "symbol": "BTC",
│      "view": "bullish",
│      "risk": "medium"
│    },
│    "fusion_state": "unclear",
│    "confidence": 0.291,
│    "volatility": {
│      "forecast": 62.39,
│      "realized": 56.63,
│      "elevated": false,
│      "implied_vol": null,
│      "vol_bias": null
│    },
│    "1h_data_available": true,
│    "no_trade": true,
│    "no_trade_reason": "Signals unclear — no strong directional conviction from forecasts.",
│    "candidates_generated": 4,
│    "candidates_after_filters": 4,
│    "exchange_data_available": true,
│    "best_match": {
│      "description": "Long call (ATM)",
│      "type": "long_call",
│      "legs": [
│        {
│          "action": "BUY",
│          "qty": 1,
│          "option_type": "Call",
│          "strike": 67500.0,
│          "premium": 638.43
│        }
│      ],
│      "net_cost": 638.43,
│      "max_loss": 638.43,
│      "expiry": "2026-02-26 08:00:00Z",
│      "max_profit": null,
│      "max_profit_condition": "Unlimited upside if BTC > $68,138 (breakeven)",
│      "pop": 0.461,
│      "ev": 541.61,
│      "tail_risk": 638.43,
│      "loss_profile": "premium at risk",
│      "exchange_edge_zscore": 1.51,
│      "exchange_edge_label": "MODERATE"
│    },
│    "safer_alt": {
│      "description": "Bull put credit spread",
│      "type": "bull_put_credit_spread",
│      "legs": [
│        {
│          "action": "SELL",
│          "qty": 1,
│          "option_type": "Put",
│          "strike": 67500.0,
│          "premium": 291.75
│        },
│        {
│          "action": "BUY",
│          "qty": 1,
│          "option_type": "Put",
│          "strike": 67000.0,
│          "premium": 140.36
│        }
│      ],
│      "net_cost": -151.39,
│      "max_loss": 348.61,
│      "expiry": "2026-02-26 08:00:00Z",
│      "max_profit": 151.39,
│      "max_profit_condition": "$151 credit kept if BTC >= $67,500 at expiry",
│      "pop": 0.547,
│      "ev": -58.39,
│      "tail_risk": 348.61,
│      "loss_profile": "defined risk",
│      "exchange_edge_zscore": -2.02,
│      "exchange_edge_label": "STRONG"
│    },
│    "higher_upside": {
│      "description": "Long call (OTM)",
│      "type": "long_call",
│      "legs": [
│        {
│          "action": "BUY",
│          "qty": 1,
│          "option_type": "Call",
│          "strike": 68500.0,
│          "premium": 197.11
│        }
│      ],
│      "net_cost": 197.11,
│      "max_loss": 197.11,
│      "expiry": "2026-02-26 08:00:00Z",
│      "max_profit": null,
│      "max_profit_condition": "Unlimited upside if BTC > $68,697 (breakeven)",
│      "pop": 0.405,
│      "ev": 498.16,
│      "tail_risk": 197.11,
│      "loss_profile": "premium at risk",
│      "exchange_edge_zscore": -1.99,
│      "exchange_edge_label": "MODERATE"
│    }
│  }
└────────────────────────────────────────────────────────────────────────┘

Test Results

============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/housedev/Documents/_Gittensor/venth/tools/options-gps
plugins: cov-7.0.0, libtmux-0.53.1, anyio-4.9.0, langsmith-0.6.8, asyncio-1.3.0, json-ctrf-0.3.6
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collecting ... collected 119 items

tests/test_exchange.py::TestFetchParse::test_deribit_mock PASSED         [  0%]
tests/test_exchange.py::TestFetchParse::test_aevo_mock PASSED            [  1%]
tests/test_exchange.py::TestFetchParse::test_all_exchanges_mock PASSED   [  2%]
tests/test_exchange.py::TestFetchParse::test_non_crypto_returns_empty PASSED [  3%]
tests/test_exchange.py::TestFetchParse::test_mid_price PASSED            [  4%]
tests/test_exchange.py::TestFetchParse::test_fields_populated PASSED     [  5%]
tests/test_exchange.py::TestFetchParse::test_empty_mock_graceful PASSED  [  5%]
tests/test_exchange.py::TestFetchParse::test_invalid_json_graceful PASSED [  6%]
tests/test_exchange.py::TestBestMarketPrice::test_lowest_ask PASSED      [  7%]
tests/test_exchange.py::TestBestMarketPrice::test_no_match PASSED        [  8%]
tests/test_exchange.py::TestBestMarketPrice::test_single_exchange PASSED [  9%]
tests/test_exchange.py::TestBestMarketPrice::test_prefers_lower_ask PASSED [ 10%]
tests/test_exchange.py::TestBestMarketPrice::test_execution_buy_lowest_ask PASSED [ 10%]
tests/test_exchange.py::TestBestMarketPrice::test_execution_sell_highest_bid PASSED [ 11%]
tests/test_exchange.py::TestEdgeDetection::test_compute_edge_basic PASSED [ 12%]
tests/test_exchange.py::TestEdgeDetection::test_compute_edge_z_score_positive PASSED [ 13%]
tests/test_exchange.py::TestEdgeDetection::test_compute_edge_z_score_negative PASSED [ 14%]
tests/test_exchange.py::TestEdgeDetection::test_compute_edge_no_match PASSED [ 15%]
tests/test_exchange.py::TestEdgeDetection::test_edge_label_strong PASSED [ 15%]
tests/test_exchange.py::TestEdgeDetection::test_edge_label_none_when_close PASSED [ 16%]
tests/test_exchange.py::TestEdgeDetection::test_edge_std_dev_floor PASSED [ 17%]
tests/test_exchange.py::TestDivergence::test_positive PASSED             [ 18%]
tests/test_exchange.py::TestDivergence::test_negative PASSED             [ 19%]
tests/test_exchange.py::TestDivergence::test_zero PASSED                 [ 20%]
tests/test_exchange.py::TestDivergence::test_zero_fair PASSED            [ 21%]
tests/test_exchange.py::TestDivergence::test_leg_divergences_all_legs PASSED [ 21%]
tests/test_exchange.py::TestDivergence::test_leg_divergences_has_z_score PASSED [ 22%]
tests/test_exchange.py::TestDivergence::test_leg_divergences_missing_exchange PASSED [ 23%]
tests/test_exchange.py::TestDivergence::test_strategy_divergence_average_zscore PASSED [ 24%]
tests/test_exchange.py::TestDivergence::test_strategy_divergence_none_when_no_data PASSED [ 25%]
tests/test_exchange.py::TestDivergence::test_leg_divergences_action_aware PASSED [ 26%]
tests/test_exchange.py::TestRankingIntegration::test_positive_divergence_boosts_score PASSED [ 26%]
tests/test_exchange.py::TestRankingIntegration::test_negative_divergence_reduces_score PASSED [ 27%]
tests/test_exchange.py::TestRankingIntegration::test_clamped_at_015 PASSED [ 28%]
tests/test_exchange.py::TestRankingIntegration::test_none_no_effect PASSED [ 29%]
tests/test_exchange.py::TestRankingIntegration::test_empty_dict_no_effect PASSED [ 30%]
tests/test_line_shopping_e2e.py::test_full_line_shopping_pipeline PASSED [ 31%]
tests/test_line_shopping_e2e.py::test_non_crypto_skips_exchange PASSED   [ 31%]
tests/test_line_shopping_e2e.py::test_exchange_failure_graceful PASSED   [ 32%]
tests/test_pipeline.py::test_fusion_aligned_bullish PASSED               [ 33%]
tests/test_pipeline.py::test_fusion_aligned_bearish PASSED               [ 34%]
tests/test_pipeline.py::test_fusion_countermove PASSED                   [ 35%]
tests/test_pipeline.py::test_fusion_unclear PASSED                       [ 36%]
tests/test_pipeline.py::test_fusion_empty_1h_falls_back_to_24h PASSED    [ 36%]
tests/test_pipeline.py::test_fusion_empty_24h_returns_unclear PASSED     [ 37%]
tests/test_pipeline.py::test_fusion_none_1h_falls_back_to_24h_bullish PASSED [ 38%]
tests/test_pipeline.py::test_fusion_none_1h_falls_back_to_24h_bearish PASSED [ 39%]
tests/test_pipeline.py::test_fusion_none_1h_falls_back_to_24h_unclear PASSED [ 40%]
tests/test_pipeline.py::test_generate_strategies_bullish PASSED          [ 41%]
tests/test_pipeline.py::test_generate_strategies_bearish PASSED          [ 42%]
tests/test_pipeline.py::test_generate_strategies_neutral_has_butterfly PASSED [ 42%]
tests/test_pipeline.py::test_compute_payoff_long_call PASSED             [ 43%]
tests/test_pipeline.py::test_iron_condor_max_loss_uses_wider_wing PASSED [ 44%]
tests/test_pipeline.py::test_rank_and_select_three PASSED                [ 45%]
tests/test_pipeline.py::test_should_no_trade_countermove_bullish PASSED  [ 46%]
tests/test_pipeline.py::test_should_no_trade_unclear_neutral PASSED      [ 47%]
tests/test_pipeline.py::test_should_no_trade_volatility_high PASSED      [ 47%]
tests/test_pipeline.py::test_credit_spread_pnl_positive_inside_spread PASSED [ 48%]
tests/test_pipeline.py::test_confidence_narrow_spread PASSED             [ 49%]
tests/test_pipeline.py::test_confidence_wide_spread PASSED               [ 50%]
tests/test_pipeline.py::test_should_no_trade_low_confidence PASSED       [ 51%]
tests/test_pipeline.py::test_should_no_trade_ok_confidence PASSED        [ 52%]
tests/test_pipeline.py::test_is_volatility_elevated_adaptive PASSED      [ 52%]
tests/test_pipeline.py::test_is_volatility_elevated_no_realized PASSED   [ 53%]
tests/test_pipeline.py::test_ev_percentage_in_rationale PASSED           [ 54%]
tests/test_pipeline.py::test_vol_elevated_prefers_defined_risk PASSED    [ 55%]
tests/test_pipeline.py::test_generate_strategies_have_legs PASSED        [ 56%]
tests/test_pipeline.py::test_generate_strategies_spread_has_two_legs PASSED [ 57%]
tests/test_pipeline.py::test_outcome_prices_with_probs PASSED            [ 57%]
tests/test_pipeline.py::test_risk_plan_has_specific_values PASSED        [ 58%]
tests/test_pipeline.py::test_parse_screen_arg PASSED                     [ 59%]
tests/test_pipeline.py::test_card_to_log_serializes_legs PASSED          [ 60%]
tests/test_pipeline.py::test_percentile_weights_sum_to_one PASSED        [ 61%]
tests/test_pipeline.py::test_interpolated_pop_long_call PASSED           [ 62%]
tests/test_pipeline.py::test_interpolated_pop_all_profitable PASSED      [ 63%]
tests/test_pipeline.py::test_interpolated_pop_all_losing PASSED          [ 63%]
tests/test_pipeline.py::test_compute_payoff_with_cdf_differs_from_equal_weight PASSED [ 64%]
tests/test_pipeline.py::test_outcome_prices_and_cdf_returns_matched_pairs PASSED [ 65%]
tests/test_pipeline.py::test_outcome_prices_and_cdf_empty_fallback PASSED [ 66%]
tests/test_pipeline.py::test_rank_strategies_uses_cdf_when_provided PASSED [ 67%]
tests/test_pipeline.py::test_forecast_path_uses_real_time_labels PASSED  [ 68%]
tests/test_pipeline.py::test_estimate_implied_vol_positive PASSED        [ 68%]
tests/test_pipeline.py::test_estimate_implied_vol_scales_with_premium PASSED [ 69%]
tests/test_pipeline.py::test_estimate_implied_vol_empty_data PASSED      [ 70%]
tests/test_pipeline.py::test_compare_volatility_long_vol PASSED          [ 71%]
tests/test_pipeline.py::test_compare_volatility_short_vol PASSED         [ 72%]
tests/test_pipeline.py::test_compare_volatility_neutral PASSED           [ 73%]
tests/test_pipeline.py::test_compare_volatility_edge_cases PASSED        [ 73%]
tests/test_pipeline.py::test_generate_strategies_vol_view_has_straddle PASSED [ 74%]
tests/test_pipeline.py::test_generate_strategies_vol_high_risk_has_short_straddle PASSED [ 75%]
tests/test_pipeline.py::test_generate_strategies_vol_low_risk_no_short_straddle PASSED [ 76%]
tests/test_pipeline.py::test_long_straddle_pnl PASSED                    [ 77%]
tests/test_pipeline.py::test_long_strangle_pnl PASSED                    [ 78%]
tests/test_pipeline.py::test_short_straddle_pnl PASSED                   [ 78%]
tests/test_pipeline.py::test_short_strangle_pnl PASSED                   [ 79%]
tests/test_pipeline.py::test_should_no_trade_vol_neutral_vol PASSED      [ 80%]
tests/test_pipeline.py::test_should_no_trade_vol_long_vol_ok PASSED      [ 81%]
tests/test_pipeline.py::test_should_no_trade_vol_low_confidence_still_trades PASSED [ 82%]
tests/test_pipeline.py::test_should_no_trade_vol_ignores_volatility_high PASSED [ 83%]
tests/test_pipeline.py::test_rank_strategies_vol_long_bias_prefers_long_straddle PASSED [ 84%]
tests/test_pipeline.py::test_rank_strategies_vol_short_bias_prefers_condor PASSED [ 84%]
tests/test_pipeline.py::test_vol_strategies_have_legs PASSED             [ 85%]
tests/test_pipeline.py::test_loss_profile_vol_types PASSED               [ 86%]
tests/test_pipeline.py::test_risk_plan_long_straddle PASSED              [ 87%]
tests/test_pipeline.py::test_risk_plan_short_straddle PASSED             [ 88%]
tests/test_pipeline.py::test_hard_filters_short_straddle_requires_high_risk PASSED [ 89%]
tests/test_pipeline.py::test_hard_filters_short_strangle_requires_medium_plus PASSED [ 89%]
tests/test_pipeline.py::test_risk_plan_long_strangle PASSED              [ 90%]
tests/test_pipeline.py::test_risk_plan_short_strangle PASSED             [ 91%]
tests/test_pipeline.py::test_estimate_implied_vol_uses_expiry_time PASSED [ 92%]
tests/test_pipeline.py::test_estimate_implied_vol_with_future_expiry PASSED [ 93%]
tests/test_pipeline.py::test_vol_rationale_contains_vol_bias PASSED      [ 94%]
tests/test_tool.py::test_client_loads_in_mock_mode PASSED                [ 94%]
tests/test_tool.py::test_prediction_percentiles PASSED                   [ 95%]
tests/test_tool.py::test_volatility PASSED                               [ 96%]
tests/test_tool.py::test_option_pricing PASSED                           [ 97%]
tests/test_vol_scripted.py::test_full_vol_pipeline_long_vol PASSED       [ 98%]
tests/test_vol_scripted.py::test_full_vol_pipeline_short_vol PASSED      [ 99%]
tests/test_vol_scripted.py::test_full_vol_pipeline_no_edge PASSED        [100%]

============================= 119 passed in 0.10s ==============================

Mock JSON responses for BTC, ETH, SOL on both exchanges.
Prices intentionally vary ±1-5% from Synth fair values to
create testable divergence scenarios for line shopping.
…aware routing

Core module for Market Line Shopping:
- ExchangeQuote and EdgeMetrics dataclasses
- fetch_deribit/fetch_aevo with mock_dir fallback for offline dev
- Live API fetchers: Deribit get_book_summary, Aevo parallel orderbook
- compute_edge() with population std dev and z-score (STRONG/MODERATE/WEAK/NONE)
- best_execution_price() routes BUY→lowest ask, SELL→highest bid
- leg_divergences() and strategy_divergence() for per-leg and aggregate scoring
New divergence_by_strategy param accepts {id(candidate): z_score}.
Applies clamped ±0.15 additive bonus (z * 0.06) after confidence
multiplier. No changes to ScoredStrategy dataclass — fully backward
compatible.
…uting

- Market Line Shopping table with ★ Execute @ column and Edge (z-score σ)
- ◆ markers highlight |z|≥1.0 disagreement at a glance
- Per-leg best venue annotation: ★ Buy @ AEVO ask $655 — edge +1.5σ ◆
- Decision log includes exchange_edge_zscore and exchange_edge_label
- Non-crypto assets gracefully skip exchange data
- conftest.py: shared fixtures for exchange quotes, strategies, option data
- test_exchange.py: 8 fetch/parse, 6 best price, 7 edge detection,
  10 divergence, 5 ranking integration tests
- test_line_shopping_e2e.py: full pipeline, non-crypto skip, graceful failure
- README.md: Market Line Shopping section with feature overview
- screenshots: BTC line shopping output, SPY graceful skip, test results
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Options GPS: Market Line Shopping (updated)

2 participants