- FastAPI + NiceGUI web application - QuantLib-based Black-Scholes pricing with Greeks - Protective put, laddered, and LEAPS strategies - Real-time WebSocket updates - TradingView-style charts via Lightweight-Charts - Docker containerization - GitLab CI/CD pipeline for VPS deployment - VPN-only access configuration
10 KiB
Strategy Documentation
Overview
Vault Dashboard currently documents and compares hedging approaches for a Lombard-style loan backed by gold exposure. The implementation focuses on paper analysis using option pricing, LTV protection metrics, and scenario analysis.
The strategy subsystem currently includes:
- protective puts
- laddered puts
- lease/LEAPS duration analysis
This document focuses on the two primary hedge structures requested here:
- protective put
- laddered put
Common portfolio assumptions
The default research engine in app/strategies/engine.py uses:
- portfolio value:
1,000,000 - loan amount:
600,000 - margin-call threshold:
0.75 - spot price:
460 - volatility:
0.16 - risk-free rate:
0.045
From these values, the portfolio is modeled as a LombardPortfolio:
- gold ounces =
portfolio_value / spot_price - initial LTV =
loan_amount / portfolio_value - margin call price =
loan_amount / (margin_call_ltv * gold_ounces)
These assumptions create the common basis used to compare all strategies.
Protective put
What it is
A protective put is the simplest downside hedge in the project.
Structure:
- long the underlying collateral exposure implicitly represented by the gold-backed portfolio
- buy one put hedge sized to the portfolio's underlying units
In this codebase, ProtectivePutStrategy creates a single long put whose strike is defined as a percentage of spot.
Examples currently used by the engine:
- ATM protective put: strike =
100%of spot - 95% OTM protective put: strike =
95%of spot - 90% OTM protective put: strike =
90%of spot
Why use it
A protective put sets a floor on downside beyond the strike, helping reduce the chance that falling collateral value pushes the portfolio above the margin-call LTV.
How it is implemented
File: app/strategies/protective_put.py
Main properties:
hedge_units:portfolio.gold_value / spot_pricestrike:spot_price * strike_pctterm_years:months / 12
A put contract is priced with Black-Scholes inputs:
- current spot
- strike
- time to expiry
- risk-free rate
- volatility
- option type =
put
The resulting OptionContract uses:
quantity = 1.0contract_size = hedge_units
That means one model contract covers the full portfolio exposure in underlying units.
Protective put payoff intuition
At expiry:
- if spot is above strike, the put expires worthless
- if spot is below strike, payoff rises linearly as
strike - spot
Total gross payoff is:
max(strike - spot, 0) * hedge_units
Protective put trade-offs
Advantages:
- simple to explain
- clear downside floor
- strongest protection when strike is high
Costs:
- premium can be expensive, especially at-the-money and for longer tenor
- full notional protection may overspend relative to a client's risk budget
- upside is preserved, but cost drags returns
Laddered put
What it is
A laddered put splits the hedge across multiple put strikes instead of buying the full hedge at one strike.
Structure:
- multiple long put legs
- each leg covers a weighted fraction of the total hedge
- lower strikes usually reduce premium while preserving some tail protection
Examples currently used by the engine:
50/50ATM + 95% OTM33/33/33ATM + 95% OTM + 90% OTM
Why use it
A ladder can reduce hedge cost versus a full ATM protective put, while still providing meaningful protection as the underlying falls.
This is useful when:
- full-cost protection is too expensive
- some drawdown can be tolerated before the hedge fully engages
- the client wants a better cost/protection balance
How it is implemented
File: app/strategies/laddered_put.py
A LadderSpec defines:
weightsstrike_pctsmonths
Validation rules:
- number of weights must equal number of strikes
- weights must sum to
1.0
Each leg is implemented by internally creating a ProtectivePutStrategy, then weighting its premium and payoff.
Ladder payoff intuition
Each leg pays off independently:
max(leg_strike - spot, 0) * hedge_units * weight
Total ladder payoff is the sum across legs.
Relative to a single-strike hedge:
- protection turns on in stages
- blended premium is lower when some legs are farther OTM
- downside support is smoother but less absolute near the first loss zone than a full ATM hedge
Ladder trade-offs
Advantages:
- lower blended hedge cost
- more flexible cost/protection shaping
- better fit for cost-sensitive clients
Costs and limitations:
- weaker immediate protection than a fully ATM hedge
- more complex to explain to users
- floor value depends on weight distribution across strikes
Cost calculations
Protective put cost calculation
ProtectivePutStrategy.calculate_cost() returns:
premium_per_sharetotal_costcost_pct_of_portfolioterm_monthsannualized_costannualized_cost_pct
Formula summary
Let:
P= option premium per underlying unitU= hedge unitsT= term in yearsV= portfolio value
Then:
total_cost = P * U
cost_pct_of_portfolio = total_cost / V
annualized_cost = total_cost / T
annualized_cost_pct = annualized_cost / V
Because the model contract size equals the full hedge units, the total premium directly represents the whole-portfolio hedge cost.
Laddered put cost calculation
LadderedPutStrategy.calculate_cost() computes weighted leg costs.
For each leg i:
weight_ipremium_ihedge_units
Leg cost:
leg_cost_i = premium_i * hedge_units * weight_i
Blended totals:
blended_cost = sum(leg_cost_i)
blended_premium_per_share = sum(premium_i * weight_i)
annualized_cost = blended_cost / term_years
cost_pct_of_portfolio = blended_cost / portfolio_value
annualized_cost_pct = annualized_cost / portfolio_value
Why annualized cost matters
The engine compares strategies with different durations, especially in LeaseStrategy. Annualizing allows the system to compare short-dated and long-dated hedges on a common yearly basis.
Protection calculations
Margin-call threshold price
The project defines the collateral price that would trigger a margin call as:
margin_call_price = loan_amount / (margin_call_ltv * gold_ounces)
This is a key reference point for all protection calculations.
Protective put protection calculation
At the threshold price:
- compute the put payoff
- add that payoff to the stressed collateral value
- recompute LTV on the hedged collateral
Formulas:
payoff_at_threshold = max(strike - threshold_price, 0) * hedge_units
hedged_value_at_threshold = gold_value_at_threshold + payoff_at_threshold
hedged_ltv_at_threshold = loan_amount / hedged_value_at_threshold
The strategy is flagged as maintaining a margin buffer when:
hedged_ltv_at_threshold < margin_call_ltv
Laddered put protection calculation
For a ladder, threshold payoff is the weighted sum of all leg payoffs:
weighted_payoff_i = max(strike_i - threshold_price, 0) * hedge_units * weight_i
payoff_at_threshold = sum(weighted_payoff_i)
hedged_value_at_threshold = gold_value_at_threshold + payoff_at_threshold
hedged_ltv_at_threshold = loan_amount / hedged_value_at_threshold
The ladder's implied floor value is approximated as the weighted strike coverage:
portfolio_floor_value = sum(strike_i * hedge_units * weight_i)
Scenario analysis methodology
Scenario grid
The current scenario engine in ProtectivePutStrategy uses a fixed price-change grid:
-60%, -50%, -40%, -30%, -20%, -10%, 0%, +10%, +20%, +30%, +40%, +50%
For each change:
scenario_price = spot_price * (1 + change)
Negative or zero prices are ignored.
Metrics produced per scenario
For each scenario, the strategy computes:
- scenario spot price
- unhedged gold value
- option payoff
- hedge cost
- net portfolio value after hedge cost
- unhedged LTV
- hedged LTV
- whether a margin call occurs without the hedge
- whether a margin call occurs with the hedge
Protective put scenario formulas
Let S be scenario spot.
gold_value = gold_ounces * S
option_payoff = max(strike - S, 0) * hedge_units
hedged_collateral = gold_value + option_payoff
net_portfolio_value = gold_value + option_payoff - hedge_cost
unhedged_ltv = loan_amount / gold_value
hedged_ltv = loan_amount / hedged_collateral
Margin-call flags:
margin_call_without_hedge = unhedged_ltv >= margin_call_ltv
margin_call_with_hedge = hedged_ltv >= margin_call_ltv
Laddered put scenario formulas
For ladders:
option_payoff = sum(max(strike_i - S, 0) * hedge_units * weight_i)
hedged_collateral = gold_value + option_payoff
net_portfolio_value = gold_value + option_payoff - blended_cost
All other LTV and margin-call logic is the same.
Interpretation methodology
Scenario analysis is used to answer four practical questions:
- Cost: How much premium is paid upfront?
- Activation: At what downside level does protection meaningfully start?
- Buffer: Does the hedge keep LTV below the margin-call threshold under stress?
- Efficiency: How much protection is obtained per dollar of annualized hedge cost?
This is why each strategy exposes both:
- a
calculate_protection()summary around the threshold price - a full
get_scenarios()table across broad upside/downside moves
Comparing protective puts vs laddered puts
| Dimension | Protective put | Laddered put |
|---|---|---|
| Structure | Single put strike | Multiple weighted put strikes |
| Simplicity | Highest | Moderate |
| Upfront cost | Usually higher | Usually lower |
| Near-threshold protection | Stronger if ATM-heavy | Depends on ladder weights |
| Tail downside protection | Strong | Strong, but blended |
| Customization | Limited | High |
| Best fit | conservative protection | balanced or cost-sensitive protection |
Important limitations
- The strategy engine is currently research-oriented, not an execution engine
- Black-Scholes assumptions simplify real-world market behavior
- Transaction costs, slippage, taxes, liquidity, and early exercise effects are not modeled here
- The API payloads should be treated as analytical outputs, not trade recommendations
- For non-
GLDsymbols, the engine currently still uses research-style assumptions rather than a complete live instrument-specific calibration
Future strategy extensions
Natural follow-ups for this subsystem:
- collars and financed hedges
- partial notional hedging
- dynamic re-hedging rules
- volatility surface-based pricing
- broker-native contract sizing and expiries
- user-configurable scenario grids