mirror of
https://github.com/Mihirkansara/nexus-quant-terminal.git
synced 2026-08-20 22:28:09 +00:00
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>
106 lines
3.9 KiB
Python
106 lines
3.9 KiB
Python
"""
|
||
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), 231–237.
|
||
|
||
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))
|