Files
nexus-quant-terminal/backend/app/core/garman_kohlhagen.py
T
KansaramandClaude Sonnet 4.6 61e145a442 feat: launch NEXUS TERMINAL — Bloomberg-style FX options analytics platform
Full-stack forex options analytics terminal with Bloomberg-inspired UI.

Backend (FastAPI + Python):
- Garman-Kohlhagen options pricing engine with full Greeks
- Goldman Sachs gs-quant AI signals (RSI, MACD, Bollinger, Hurst, OU)
- Monte Carlo GBM simulation and volatility surface generation
- CFTC COT institutional positioning + Forex Factory economic calendar
- Live data proxy: OpenSky aircraft + USGS earthquakes (CORS-safe)
- Multi-leg strategy library (straddle, iron condor, butterfly, spreads)

Frontend (React 18 + Vite):
- NEXUS animated orbital logo (3-ring SVG) + canvas favicon animation
- Bloomberg terminal design: JetBrains Mono, color-mix() tokens
- 11 dashboard tabs: Greeks, Chart, AI Signals, 3D Surfaces, Breakeven,
  Scenarios, Monte Carlo, Institutional, Calendar, Live Map, Live Feeds
- Live World Map (react-leaflet): aircraft, earthquakes, weather radar
- Live Feeds: CoinGecko crypto top-12 + Windy.com global webcams
- Economic calendar with filters + institutional flow (CFTC COT)
- Animated landing page + session-based routing
- Fully responsive dark-only terminal design system

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 18:19:23 +05:30

106 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
garman_kohlhagen.py — Garman-Kohlhagen (1983) model for European forex options.
Extension of Black-Scholes that accounts for BOTH the domestic and foreign
risk-free interest rates — essential for currency options pricing.
Reference: Garman, M.B. & Kohlhagen, S.W. (1983). "Foreign currency option values."
Journal of International Money and Finance, 2(3), 231237.
Model:
d1 = [ln(S/K) + (r_d r_f + σ²/2)·T] / (σ·√T)
d2 = d1 σ·√T
C = S·e^(r_f·T)·N(d1) K·e^(r_d·T)·N(d2)
P = K·e^(r_d·T)·N(d2) S·e^(r_f·T)·N(d1)
"""
import numpy as np
from scipy.stats import norm
def _d1_d2(S: float, K: float, T: float, r_d: float, r_f: float, sigma: float):
"""Compute GK d1 and d2 intermediate values."""
S = np.asarray(S, dtype=float)
sqrt_T = np.sqrt(T)
d1 = (np.log(S / K) + (r_d - r_f + 0.5 * sigma ** 2) * T) / (sigma * sqrt_T)
d2 = d1 - sigma * sqrt_T
return d1, d2
def gk_price(S, K, T, r_d, r_f, sigma, option_type="call"):
d1, d2 = _d1_d2(S, K, T, r_d, r_f, sigma)
S = np.asarray(S, dtype=float)
if option_type == "call":
return float(S * np.exp(-r_f * T) * norm.cdf(d1) - K * np.exp(-r_d * T) * norm.cdf(d2))
return float(K * np.exp(-r_d * T) * norm.cdf(-d2) - S * np.exp(-r_f * T) * norm.cdf(-d1))
def gk_delta(S, K, T, r_d, r_f, sigma, option_type="call"):
"""
Delta — sensitivity of option price to spot rate change.
Call: e^(r_f·T)·N(d1) Put: e^(r_f·T)·N(d1)
"""
d1, _ = _d1_d2(S, K, T, r_d, r_f, sigma)
factor = np.exp(-r_f * T)
if option_type == "call":
return float(factor * norm.cdf(d1))
return float(-factor * norm.cdf(-d1))
def gk_gamma(S, K, T, r_d, r_f, sigma):
"""
Gamma — rate of change of delta.
Γ = e^(r_f·T)·N'(d1) / (S·σ·√T) (same sign for calls and puts)
"""
d1, _ = _d1_d2(S, K, T, r_d, r_f, sigma)
return float(np.exp(-r_f * T) * norm.pdf(d1) / (np.asarray(S) * sigma * np.sqrt(T)))
def gk_vega(S, K, T, r_d, r_f, sigma):
"""
Vega — sensitivity to implied volatility.
ν = S·e^(r_f·T)·N'(d1)·√T (same for calls and puts)
"""
d1, _ = _d1_d2(S, K, T, r_d, r_f, sigma)
return float(np.asarray(S) * np.exp(-r_f * T) * norm.pdf(d1) * np.sqrt(T))
def gk_theta(S, K, T, r_d, r_f, sigma, option_type="call"):
"""
Theta — time decay (per year).
Call: S·σ·e^(r_f·T)·N'(d1)/(2√T) r_d·K·e^(r_d·T)·N(d2) + r_f·S·e^(r_f·T)·N(d1)
Put: S·σ·e^(r_f·T)·N'(d1)/(2√T) + r_d·K·e^(r_d·T)·N(d2) r_f·S·e^(r_f·T)·N(d1)
"""
d1, d2 = _d1_d2(S, K, T, r_d, r_f, sigma)
S = np.asarray(S, dtype=float)
decay = -(S * sigma * np.exp(-r_f * T) * norm.pdf(d1)) / (2 * np.sqrt(T))
if option_type == "call":
return float(decay - r_d * K * np.exp(-r_d * T) * norm.cdf(d2)
+ r_f * S * np.exp(-r_f * T) * norm.cdf(d1))
return float(decay + r_d * K * np.exp(-r_d * T) * norm.cdf(-d2)
- r_f * S * np.exp(-r_f * T) * norm.cdf(-d1))
def gk_rho_d(S, K, T, r_d, r_f, sigma, option_type="call"):
"""
Rho_d — sensitivity to DOMESTIC interest rate.
Call: K·T·e^(r_d·T)·N(d2) Put: K·T·e^(r_d·T)·N(d2)
"""
_, d2 = _d1_d2(S, K, T, r_d, r_f, sigma)
factor = K * T * np.exp(-r_d * T)
if option_type == "call":
return float(factor * norm.cdf(d2))
return float(-factor * norm.cdf(-d2))
def gk_phi(S, K, T, r_d, r_f, sigma, option_type="call"):
"""
Phi (ρ_f) — sensitivity to FOREIGN interest rate.
Call: S·T·e^(r_f·T)·N(d1) Put: S·T·e^(r_f·T)·N(d1)
"""
d1, _ = _d1_d2(S, K, T, r_d, r_f, sigma)
factor = np.asarray(S) * T * np.exp(-r_f * T)
if option_type == "call":
return float(-factor * norm.cdf(d1))
return float(factor * norm.cdf(-d1))