- 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
12 KiB
API Documentation
Overview
Vault Dashboard exposes a small read-only HTTP API plus a WebSocket stream.
Base capabilities:
- health monitoring
- portfolio snapshot retrieval
- options chain retrieval
- strategy analysis retrieval
- periodic real-time portfolio updates over WebSocket
Unless noted otherwise, all responses are JSON.
Conventions
Base URL
Examples:
http://localhost:8000
https://vault.example.com
Content type
Responses use:
Content-Type: application/json
Authentication
There is currently no application-layer authentication on these endpoints.
If the deployment requires restricted access, enforce it at the network or reverse-proxy layer.
Errors
The app currently relies mostly on framework defaults. Typical failures may include:
422 Unprocessable Entityfor invalid query parameters500 Internal Server Errorfor unexpected runtime issues
HTTP endpoints
1. Health
GET /health
Deployment and uptime check.
Query parameters
None.
Response schema
{
"status": "ok",
"environment": "production",
"redis_enabled": false
}
Field definitions
status(string): expected value is currently"ok"environment(string): runtime environment fromAPP_ENVorENVIRONMENTredis_enabled(boolean):truewhen Redis is configured and connected
Example request
curl -fsS http://localhost:8000/health
Example response
{
"status": "ok",
"environment": "development",
"redis_enabled": false
}
2. Portfolio
GET /api/portfolio
Returns a portfolio snapshot derived from the current quote for a symbol.
Query parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
symbol |
string | no | GLD |
Ticker symbol to analyze |
Response schema
{
"symbol": "GLD",
"spot_price": 215.0,
"portfolio_value": 215000.0,
"loan_amount": 600000.0,
"ltv_ratio": 2.7907,
"updated_at": "2026-03-21T12:34:56.000000+00:00",
"source": "fallback"
}
Field definitions
symbol(string): requested ticker, uppercasedspot_price(number): latest spot/quote priceportfolio_value(number): current modeled collateral value, currentlyspot_price * 1000loan_amount(number): modeled loan balance, currently fixed at600000.0ltv_ratio(number):loan_amount / portfolio_valueupdated_at(string, ISO 8601): response generation timestampsource(string): quote source such asyfinanceorfallback
Example request
curl "http://localhost:8000/api/portfolio?symbol=GLD"
Example response
{
"symbol": "GLD",
"spot_price": 215.0,
"portfolio_value": 215000.0,
"loan_amount": 600000.0,
"ltv_ratio": 2.7907,
"updated_at": "2026-03-21T12:34:56.000000+00:00",
"source": "fallback"
}
3. Options chain
GET /api/options
Returns a simplified options chain snapshot for the symbol.
Query parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
symbol |
string | no | GLD |
Ticker symbol to analyze |
Response schema
{
"symbol": "GLD",
"updated_at": "2026-03-21T12:34:56.000000+00:00",
"calls": [
{
"strike": 225.75,
"premium": 6.45,
"expiry": "2026-06-19"
}
],
"puts": [
{
"strike": 204.25,
"premium": 6.02,
"expiry": "2026-06-19"
}
],
"source": "fallback"
}
Array item schema
Each option row in calls or puts has:
strike(number)premium(number)expiry(string,YYYY-MM-DD)
Field definitions
symbol(string): requested ticker, uppercasedupdated_at(string, ISO 8601): response generation timestampcalls(array<object>): example call rows derived from spotputs(array<object>): example put rows derived from spotsource(string): upstream quote source used to derive the chain
Notes
The current options chain is synthetic. It is not yet a full broker-grade chain feed.
Example request
curl "http://localhost:8000/api/options?symbol=GLD"
4. Strategies
GET /api/strategies
Returns strategy comparison data, recommendations by risk profile, and sensitivity analysis.
Query parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
symbol |
string | no | GLD |
Ticker symbol to analyze |
Top-level response schema
{
"symbol": "GLD",
"updated_at": "2026-03-21T12:34:56.000000+00:00",
"paper_parameters": {},
"strategies": [],
"recommendations": {},
"sensitivity_analysis": {}
}
Top-level field definitions
symbol(string): requested ticker, uppercasedupdated_at(string, ISO 8601): response generation timestamppaper_parameters(object): engine inputs used for the analysisstrategies(array<object>): detailed strategy comparison rowsrecommendations(object): recommendation results keyed by risk profilesensitivity_analysis(object): recommendation changes across parameter shifts
4.1 paper_parameters schema
{
"portfolio_value": 1000000.0,
"loan_amount": 600000.0,
"margin_call_threshold": 0.75,
"spot_price": 460.0,
"volatility": 0.16,
"risk_free_rate": 0.045
}
Fields:
portfolio_value(number)loan_amount(number)margin_call_threshold(number)spot_price(number)volatility(number)risk_free_rate(number)
4.2 strategies[] schema
Each element in strategies is produced by StrategySelectionEngine.compare_all_strategies():
{
"name": "protective_put_atm",
"cost": {},
"protection": {},
"scenarios": [],
"score_inputs": {
"annual_cost": 0.0,
"hedged_ltv_at_threshold": 0.0
}
}
Fields:
name(string): internal strategy identifiercost(object): strategy-specific cost payloadprotection(object): strategy-specific protection payloadscenarios(array<object>): scenario analysis rowsscore_inputs(object): normalized inputs used for recommendation scoring
Protective put cost schema
Typical cost object for protective_put_*:
{
"strategy": "protective_put_atm",
"label": "ATM",
"strike": 460.0,
"strike_pct": 1.0,
"premium_per_share": 21.1234,
"total_cost": 45920.43,
"cost_pct_of_portfolio": 0.04592,
"term_months": 12,
"annualized_cost": 45920.43,
"annualized_cost_pct": 0.04592
}
Protective put protection schema
{
"strategy": "protective_put_atm",
"threshold_price": 368.0,
"strike": 460.0,
"portfolio_floor_value": 1000000.0,
"unhedged_ltv_at_threshold": 0.75,
"hedged_ltv_at_threshold": 0.652174,
"payoff_at_threshold": 200000.0,
"maintains_margin_call_buffer": true
}
Protective put scenario row schema
{
"price_change_pct": -0.2,
"gld_price": 368.0,
"gold_value": 800000.0,
"option_payoff": 200000.0,
"hedge_cost": 45920.43,
"net_portfolio_value": 954079.57,
"unhedged_ltv": 0.75,
"hedged_ltv": 0.6,
"margin_call_without_hedge": true,
"margin_call_with_hedge": false
}
Laddered put cost schema
Typical cost object for laddered_put_*:
{
"strategy": "laddered_put_50_50_atm_otm95",
"label": "50_50_ATM_OTM95",
"legs": [
{
"weight": 0.5,
"strike": 460.0,
"premium_per_share": 21.1234,
"weighted_cost": 22960.22
}
],
"blended_premium_per_share": 18.4567,
"blended_cost": 40123.45,
"cost_pct_of_portfolio": 0.040123,
"annualized_cost": 40123.45,
"annualized_cost_pct": 0.040123
}
Laddered put protection schema
{
"strategy": "laddered_put_50_50_atm_otm95",
"threshold_price": 368.0,
"portfolio_floor_value": 975000.0,
"payoff_at_threshold": 175000.0,
"unhedged_ltv_at_threshold": 0.75,
"hedged_ltv_at_threshold": 0.615385,
"maintains_margin_call_buffer": true,
"legs": [
{
"weight": 0.5,
"strike": 460.0,
"weighted_payoff_at_threshold": 100000.0
}
]
}
Lease duration analysis cost schema
Typical cost object for lease_duration_analysis:
{
"strategy": "lease_duration_analysis",
"comparison": [
{
"months": 3,
"strike": 460.0,
"premium_per_share": 9.1234,
"total_cost": 19833.48,
"annualized_cost": 79333.92,
"annualized_cost_pct": 0.079334,
"rolls_per_year": 4.0,
"recommended_roll_month": 2
}
],
"optimal_duration_months": 12,
"lowest_annual_cost": 45920.43,
"lowest_annual_cost_pct": 0.04592
}
Lease duration analysis protection schema
{
"strategy": "lease_duration_analysis",
"threshold_price": 368.0,
"durations": [
{
"months": 12,
"payoff_at_threshold": 200000.0,
"hedged_ltv_at_threshold": 0.6,
"maintains_margin_call_buffer": true
}
]
}
4.3 recommendations schema
The object contains keys:
conservativebalancedcost_sensitive
Each recommendation object has this shape:
{
"risk_profile": "balanced",
"recommended_strategy": "laddered_put_50_50_atm_otm95",
"rationale": {
"portfolio_value": 1000000.0,
"loan_amount": 600000.0,
"margin_call_threshold": 0.75,
"spot_price": 460.0,
"volatility": 0.16,
"risk_free_rate": 0.045
},
"comparison_summary": [
{
"name": "protective_put_atm",
"annual_cost": 45920.43,
"hedged_ltv_at_threshold": 0.6
}
]
}
4.4 sensitivity_analysis schema
{
"volatility": [
{
"volatility": 0.12,
"recommended_strategy": "protective_put_otm_95"
}
],
"spot_price": [
{
"spot_price": 414.0,
"recommended_strategy": "protective_put_otm_95"
}
]
}
WebSocket API
Endpoint
WS /ws/updates
Used for server-pushed real-time updates.
Connection lifecycle
- Client opens a WebSocket connection to
/ws/updates - Server accepts the connection
- Server immediately sends a
connectedevent - Server periodically broadcasts
portfolio_updateevents - Client may keep the connection alive by sending text frames
- Server removes the connection when disconnected or on send failure
Event: connected
Sent once after successful connection.
Schema
{
"type": "connected",
"message": "Real-time updates enabled"
}
Fields:
type(string): event namemessage(string): human-readable confirmation
Event: portfolio_update
Broadcast on an interval controlled by WEBSOCKET_INTERVAL_SECONDS.
Schema
{
"type": "portfolio_update",
"connections": 2,
"portfolio": {
"symbol": "GLD",
"spot_price": 215.0,
"portfolio_value": 215000.0,
"loan_amount": 600000.0,
"ltv_ratio": 2.7907,
"updated_at": "2026-03-21T12:34:56.000000+00:00",
"source": "fallback"
}
}
Fields:
type(string): event nameconnections(integer): current number of connected WebSocket clientsportfolio(object): same schema asGET /api/portfolio
Example JavaScript client
const ws = new WebSocket('ws://localhost:8000/ws/updates');
ws.onmessage = (event) => {
const payload = JSON.parse(event.data);
console.log(payload.type, payload);
};
ws.onopen = () => {
// optional keepalive or ping surrogate
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send('ping');
}
}, 10000);
};
OpenAPI
Because the app is built on FastAPI, interactive docs are typically available at:
/docs/redoc
This file is the human-oriented reference for payload semantics and current behavior.
Notes and limitations
- Endpoints are read-only today
- There are no POST/PUT/DELETE endpoints yet
- The options chain is currently synthetic
- Strategy outputs are paper-analysis results, not execution instructions
- Symbol validation is minimal and currently delegated to downstream quote behavior