core.test_portfolio
Tests for Hedge Portfolio Display Functions
Tests the pure functions in f.domains.hedge.core.portfolio that build displayable portfolio entries for the frontend hedge analysis UI.
MATHEMATICAL BACKGROUND
The hedge portfolio display shows option positions scaled relative to the LP position size, with allocation percentages for risk management.
KEY FORMULAS
Quantity per ETH (Hedge Ratio):
quantity_per_eth = total_quantity / lp_sizeWhere: total_quantity = Number of put contracts held lp_size = Size of LP position in ETH
Interpretation: "For each 1 ETH of LP exposure, we hold X puts"
Example: total_quantity = 11, lp_size = 32.787 quantity_per_eth = 11 / 32.787 = 0.3355
Meaning: ~0.34 puts per ETH of LP positionAllocation Percentage:
allocation_pct = (position_premium / total_cost) × 100Where: position_premium = Premium paid for this strike position total_cost = Total premium across all positions
Example: position_premium = 1133.49, total_cost = 8889 allocation_pct = (1133.49 / 8889) × 100 = 12.75%
Scaled Quantity: The raw quantity from the optimizer, preserved for display. This is what gets sent to the exchange for order execution.
Premium Calculation:
premium = quantity × put_price × spot_priceWhere: put_price = Black-Scholes price as fraction of spot
EXCEL VERIFICATION GUIDE
For a mathematician to verify these metrics in Excel:
- Hedge Ratio:
=Quantity / LP_Size_ETH - Allocation %:
=Premium / Total_Premium - Zero Quantity Pricing: Use Black-Scholes Put formula (see
test_black_scholes.py).
PORTFOLIO ENTRY STRUCTURE
Each HedgePortfolioEntry contains:
| Field | Type | Description |
|---|---|---|
| strike | Decimal | Strike price (e.g., 2200) |
| instrument_name | str | Deribit format (ETH-28MAR26-2200-P) |
| quantity_per_eth | Decimal | Contracts per unit of LP size |
| scaled_quantity | Decimal | Total contracts to purchase |
| put_price | Decimal | Option price as ratio of spot |
| premium | Decimal | Total cost for this position |
| allocation_pct | Decimal | Percentage of total hedge cost |
ZERO QUANTITY ENTRIES
The portfolio display includes "zero quantity" entries for strikes that are available but not selected by the optimizer. These entries:
- Show theoretical put prices (for user reference)
- Have quantity_per_eth = 0, scaled_quantity = 0, premium = 0
- Allow users to see what protection would cost at unused strikes
This is computed using Black-Scholes with the current market parameters (spot, volatility, time to expiry).
DISPLAY ORDERING
Entries are sorted by strike price descending (highest strike first). This matches the convention of showing ATM options at the top.
Example: [Strike 2800, Strike 2600, Strike 2400, Strike 2200]
FUNCTIONS TESTED
build_hedge_portfolio_entry()
- Builds entry from HedgePosition with scaling calculations
- Calculates quantity_per_eth and allocation_pct
build_zero_quantity_entry()
- Builds entry for unused strike with theoretical price
- Uses Black-Scholes for put_price calculation
build_hedge_portfolio_display()
- Combines positions with selected strikes
- Fills gaps with zero-quantity entries
- Returns sorted list
Sample hedge position for testing.
Multiple hedge positions for testing.
Sample expiry date.
Test: Build portfolio entry from standard position.
NUMERICAL EXAMPLE
Input: position: Put 2200, amount=11, price=0.0338, premium=1133.49 size = 32.787 p0 = 3050 total_cost = 8889
Calculation: quantity_per_eth = 11 / 32.787 = 0.3355 allocation_pct = (1133.49 / 8889) × 100 = 12.75%
Expected: Valid HedgePortfolioEntry with calculated values
EXCEL REPRODUCTION
1. Inputs (Cells A1:B4)
| Cell | Parameter | Value |
|---|---|---|
| B1 | Quantity | 11 |
| B2 | Premium | 1133.49 |
| B3 | LP_Size | 32.787 |
| B4 | TotalCost | 8889 |
2. Calculation (Cells B5:B6)
| Cell | Name | Formula | Expectation |
|---|---|---|---|
| B5 | Qty/ETH | =B1/B3 |
0.3355 |
| B6 | Alloc% | =B2/B4 |
12.75% |
Test portfolio entry with large quantity.
Test portfolio entry with small quantity.
Test: Build zero quantity entry for OTM strike.
NUMERICAL EXAMPLE
Input: strike = 2200 (OTM, below current price) p0 = 3050 volatility = 0.70 time_to_expiry = 0.29 years
Expected: Entry with quantity=0 but valid put price > 0
Test zero quantity entry for ATM strike.
Test zero quantity entry for ITM strike.
Test: Build portfolio display with selected strikes.
NUMERICAL EXAMPLE
Input: positions: [Put 2600 × 5, Put 2200 × 10] selected_strikes: [2800, 2600, 2200] # Includes 2800 not in positions
Expected: 3 entries: 2800 (zero qty), 2600 (has position), 2200 (has position)
Test portfolio display without selected strikes (auto from positions).
Test portfolio display with mix of positions and selected strikes.