Files
vault-dash/app/components/greeks_table.py
Bu5hm4nn 00a68bc767 Initial commit: Vault Dashboard for options hedging
- 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
2026-03-21 19:21:40 +01:00

105 lines
4.8 KiB
Python

from __future__ import annotations
from typing import Any
from nicegui import ui
from app.models.option import OptionContract
class GreeksTable:
"""Live Greeks table with simple risk-level color coding."""
def __init__(self, options: list[OptionContract | dict[str, Any]] | None = None) -> None:
self.options = options or []
with ui.card().classes("w-full rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900"):
with ui.row().classes("w-full items-center justify-between"):
ui.label("Option Greeks").classes("text-lg font-semibold text-slate-900 dark:text-slate-100")
ui.label("Live Risk Snapshot").classes(
"rounded-full bg-violet-100 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-violet-700 dark:bg-violet-500/15 dark:text-violet-300"
)
self.table_html = ui.html("").classes("w-full")
self.set_options(self.options)
def set_options(self, options: list[OptionContract | dict[str, Any]]) -> None:
self.options = options
self.table_html.content = self._render_table()
self.table_html.update()
def _render_table(self) -> str:
rows = [self._row_html(option) for option in self.options]
return f"""
<div class=\"overflow-x-auto\">
<table class=\"min-w-full\">
<thead class=\"bg-slate-100 dark:bg-slate-800\">
<tr>
<th class=\"px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300\">Option</th>
<th class=\"px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300\">Delta</th>
<th class=\"px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300\">Gamma</th>
<th class=\"px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300\">Theta</th>
<th class=\"px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300\">Vega</th>
<th class=\"px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300\">Rho</th>
</tr>
</thead>
<tbody>{''.join(rows) if rows else self._empty_row()}</tbody>
</table>
</div>
"""
def _row_html(self, option: OptionContract | dict[str, Any]) -> str:
if isinstance(option, OptionContract):
label = f"{option.option_type.upper()} {option.strike:.2f}"
greeks = {
"delta": option.greeks.delta,
"gamma": option.greeks.gamma,
"theta": option.greeks.theta,
"vega": option.greeks.vega,
"rho": option.greeks.rho,
}
else:
label = str(option.get("label") or option.get("symbol") or option.get("name") or "Option")
greeks = {
greek: float(option.get(greek, option.get("greeks", {}).get(greek, 0.0)))
for greek in ("delta", "gamma", "theta", "vega", "rho")
}
cells = "".join(
f'<td class="px-4 py-3 font-semibold {self._risk_class(name, value)}">{value:+.4f}</td>'
for name, value in greeks.items()
)
return (
'<tr class="border-b border-slate-200 dark:border-slate-800">'
f'<td class="px-4 py-3 font-medium text-slate-900 dark:text-slate-100">{label}</td>'
f'{cells}'
'</tr>'
)
@staticmethod
def _risk_class(name: str, value: float) -> str:
magnitude = abs(value)
if name == "gamma":
if magnitude >= 0.08:
return "text-rose-600 dark:text-rose-400"
if magnitude >= 0.04:
return "text-amber-600 dark:text-amber-400"
return "text-emerald-600 dark:text-emerald-400"
if name == "theta":
if value <= -0.08:
return "text-rose-600 dark:text-rose-400"
if value <= -0.03:
return "text-amber-600 dark:text-amber-400"
return "text-emerald-600 dark:text-emerald-400"
if magnitude >= 0.6:
return "text-rose-600 dark:text-rose-400"
if magnitude >= 0.3:
return "text-amber-600 dark:text-amber-400"
return "text-emerald-600 dark:text-emerald-400"
@staticmethod
def _empty_row() -> str:
return (
'<tr><td colspan="6" class="px-4 py-6 text-center text-slate-500 dark:text-slate-400">'
'No options selected'
'</td></tr>'
)