spb/vquant Public MIT
VibeQuant — AI-powered institutional-grade financial intelligence platform.
TypeScript 84.3%
Python 11.7%
JavaScript 1.6%
CSS 1.5%
HTML 0.7%
1/*2 * =============================================================================3 * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4 * -----------------------------------------------------------------------------5 * File: client/src/components/financial/options-pricing-card.tsx6 *7 * Author: Simon-Pierre Boucher8 * Contact: contact@spboucher.ai9 * Website: https://www.spboucher.ai10 * Demo: https://www.vquant.ai11 * License: MIT (see LICENSE)12 *13 * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14 * =============================================================================15 */1617import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";18import { Badge } from "@/components/ui/badge";19import { TrendingUp, TrendingDown, DollarSign, Clock, Percent, Activity } from "lucide-react";2021interface OptionGreeks {22 delta: number;23 gamma: number;24 theta: number;25 vega: number;26 rho: number;27}2829interface OptionResult {30 price: number;31 intrinsic_value: number;32 time_value: number;33 greeks: OptionGreeks;34 moneyness: string;35}3637interface OptionsPricingData {38 parameters: {39 stock_price: number;40 strike_price: number;41 time_to_maturity: number;42 risk_free_rate: number;43 volatility: number;44 option_type: string;45 };46 call_option: OptionResult;47 put_option: OptionResult;48 parity_check: {49 call_minus_put: number;50 stock_minus_pv_strike: number;51 parity_holds: boolean;52 };53}5455interface OptionsPricingCardProps {56 data: OptionsPricingData;57}5859export function OptionsPricingCard({ data }: OptionsPricingCardProps) {60 const formatPrice = (value: number) => `$${value.toFixed(4)}`;61 const formatPercent = (value: number) => `${(value * 100).toFixed(2)}%`;62 const formatGreek = (value: number, decimals: number = 4) => value.toFixed(decimals);6364 const getMoneynessColor = (moneyness: string) => {65 switch (moneyness) {66 case 'ITM':67 return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200';68 case 'ATM':69 return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200';70 case 'OTM':71 return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200';72 default:73 return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200';74 }75 };7677 const GreekIndicator = ({ label, value, tooltip }: { label: string; value: number; tooltip: string }) => (78 <div className="flex items-center justify-between py-2 border-b border-border/40 last:border-0">79 <div className="flex items-center gap-2">80 <span className="text-sm font-medium text-muted-foreground">{label}</span>81 <span className="text-xs text-muted-foreground/60" title={tooltip}>ⓘ</span>82 </div>83 <span className={`text-sm font-semibold ${value >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>84 {formatGreek(value)}85 </span>86 </div>87 );8889 const OptionCard = ({ title, option, icon }: { title: string; option: OptionResult; icon: React.ReactNode }) => (90 <Card className="h-full">91 <CardHeader>92 <div className="flex items-center justify-between">93 <div className="flex items-center gap-2">94 {icon}95 <CardTitle className="text-lg">{title}</CardTitle>96 </div>97 <Badge className={getMoneynessColor(option.moneyness)}>98 {option.moneyness}99 </Badge>100 </div>101 </CardHeader>102 <CardContent className="space-y-4">103 {/* Option Price */}104 <div className="p-4 bg-primary/5 rounded-lg">105 <div className="text-sm text-muted-foreground mb-1">Option Price</div>106 <div className="text-3xl font-bold text-primary">{formatPrice(option.price)}</div>107 </div>108109 {/* Value Breakdown */}110 <div className="grid grid-cols-2 gap-3">111 <div className="p-3 bg-muted/50 rounded-lg">112 <div className="text-xs text-muted-foreground mb-1">Intrinsic</div>113 <div className="text-lg font-semibold">{formatPrice(option.intrinsic_value)}</div>114 </div>115 <div className="p-3 bg-muted/50 rounded-lg">116 <div className="text-xs text-muted-foreground mb-1">Time Value</div>117 <div className="text-lg font-semibold">{formatPrice(option.time_value)}</div>118 </div>119 </div>120121 {/* Greeks */}122 <div className="pt-2">123 <div className="text-sm font-semibold mb-3 flex items-center gap-2">124 <Activity className="h-4 w-4" />125 Greeks (Sensitivities)126 </div>127 <div className="space-y-1">128 <GreekIndicator129 label="Delta (Δ)"130 value={option.greeks.delta}131 tooltip="Change in option price for $1 change in stock price"132 />133 <GreekIndicator134 label="Gamma (Γ)"135 value={option.greeks.gamma}136 tooltip="Rate of change of Delta"137 />138 <GreekIndicator139 label="Theta (Θ)"140 value={option.greeks.theta}141 tooltip="Time decay - change in price per day"142 />143 <GreekIndicator144 label="Vega (ν)"145 value={option.greeks.vega}146 tooltip="Change in price for 1% change in volatility"147 />148 <GreekIndicator149 label="Rho (ρ)"150 value={option.greeks.rho}151 tooltip="Change in price for 1% change in interest rate"152 />153 </div>154 </div>155 </CardContent>156 </Card>157 );158159 return (160 <div className="space-y-6">161 {/* Parameters Header */}162 <Card>163 <CardHeader>164 <CardTitle className="flex items-center gap-2">165 <DollarSign className="h-5 w-5" />166 Black-Scholes Option Pricing167 </CardTitle>168 <CardDescription>Theoretical option values and Greeks for European options</CardDescription>169 </CardHeader>170 <CardContent>171 <div className="grid grid-cols-2 md:grid-cols-5 gap-4">172 <div className="space-y-1">173 <div className="text-xs text-muted-foreground">Stock Price</div>174 <div className="text-lg font-semibold">{formatPrice(data.parameters.stock_price)}</div>175 </div>176 <div className="space-y-1">177 <div className="text-xs text-muted-foreground">Strike Price</div>178 <div className="text-lg font-semibold">{formatPrice(data.parameters.strike_price)}</div>179 </div>180 <div className="space-y-1">181 <div className="text-xs text-muted-foreground flex items-center gap-1">182 <Clock className="h-3 w-3" />183 Time to Expiry184 </div>185 <div className="text-lg font-semibold">{data.parameters.time_to_maturity.toFixed(4)} yr</div>186 <div className="text-xs text-muted-foreground">{(data.parameters.time_to_maturity * 365).toFixed(0)} days</div>187 </div>188 <div className="space-y-1">189 <div className="text-xs text-muted-foreground flex items-center gap-1">190 <Percent className="h-3 w-3" />191 Volatility192 </div>193 <div className="text-lg font-semibold">{formatPercent(data.parameters.volatility)}</div>194 </div>195 <div className="space-y-1">196 <div className="text-xs text-muted-foreground">Risk-Free Rate</div>197 <div className="text-lg font-semibold">{formatPercent(data.parameters.risk_free_rate)}</div>198 </div>199 </div>200 </CardContent>201 </Card>202203 {/* Call and Put Options Side by Side */}204 <div className="grid md:grid-cols-2 gap-4">205 <OptionCard206 title="Call Option"207 option={data.call_option}208 icon={<TrendingUp className="h-5 w-5 text-green-600" />}209 />210 <OptionCard211 title="Put Option"212 option={data.put_option}213 icon={<TrendingDown className="h-5 w-5 text-red-600" />}214 />215 </div>216217 {/* Put-Call Parity Check */}218 <Card>219 <CardHeader>220 <CardTitle className="text-base">Put-Call Parity Verification</CardTitle>221 <CardDescription className="text-xs">222 Verifies that C - P = S - K×e^(-rT)223 </CardDescription>224 </CardHeader>225 <CardContent>226 <div className="grid grid-cols-3 gap-4">227 <div className="space-y-1">228 <div className="text-xs text-muted-foreground">Call - Put</div>229 <div className="text-sm font-semibold">{formatPrice(data.parity_check.call_minus_put)}</div>230 </div>231 <div className="space-y-1">232 <div className="text-xs text-muted-foreground">S - PV(K)</div>233 <div className="text-sm font-semibold">{formatPrice(data.parity_check.stock_minus_pv_strike)}</div>234 </div>235 <div className="space-y-1">236 <div className="text-xs text-muted-foreground">Parity Check</div>237 <Badge variant={data.parity_check.parity_holds ? "default" : "destructive"}>238 {data.parity_check.parity_holds ? '✓ Holds' : '✗ Failed'}239 </Badge>240 </div>241 </div>242 </CardContent>243 </Card>244 </div>245 );246}247