diff --git a/README.md b/README.md index c1a96567dc..165ce67ab9 100644 --- a/README.md +++ b/README.md @@ -614,7 +614,7 @@ Intraday bars: 1m / 5m / 15m / 30m / 1H / 4H / 1D. 15 metrics + benchmark compar
-Quant Library 286 tested functions across 19 modules, callable from every transport +Quant Library 287 tested functions across 19 modules, callable from every transport `src/quantlib` holds one tested implementation of each piece of finance math the agent needs. Skills **import** these rather than carrying formulas inside diff --git a/README_ar.md b/README_ar.md index 48bae5d04c..2af3665035 100644 --- a/README_ar.md +++ b/README_ar.md @@ -610,7 +610,7 @@ LONGBRIDGE_ACCESS_TOKEN=...
-Quant Library 286 دالة مختبَرة عبر 19 وحدة، قابلة للاستدعاء من كل المسارات +Quant Library 287 دالة مختبَرة عبر 19 وحدة، قابلة للاستدعاء من كل المسارات يحتفظ `src/quantlib` بتنفيذ مختبَر **واحد فقط** لكل قطعة من الرياضيات المالية التي يحتاجها الـ agent. صارت الـ skills **تستورد** هذه الدوال بدلاً من حمل الصيغ داخل كتل diff --git a/README_es.md b/README_es.md index ab9c70de65..ccbc2405f2 100644 --- a/README_es.md +++ b/README_es.md @@ -615,7 +615,7 @@ Barras intradía: 1m / 5m / 15m / 30m / 1H / 4H / 1D. 15 métricas + comparació
-Quant Library 286 funciones probadas en 19 módulos, invocables desde cualquier transporte +Quant Library 287 funciones probadas en 19 módulos, invocables desde cualquier transporte `src/quantlib` contiene una implementación probada de cada pieza de matemática financiera que el agente necesita. Las skills **importan** estas funciones en diff --git a/README_ja.md b/README_ja.md index 494a2ca088..524140387a 100644 --- a/README_ja.md +++ b/README_ja.md @@ -610,7 +610,7 @@ Intraday bars: 1m / 5m / 15m / 30m / 1H / 4H / 1D. 15 metrics + benchmark compar
-Quant Library 19 モジュール・286 個のテスト済み関数、すべての経路から呼び出し可能 +Quant Library 19 モジュール・287 個のテスト済み関数、すべての経路から呼び出し可能 `src/quantlib` は、agent が必要とする金融数学のそれぞれについて、テスト済みの実装を **1 つだけ**保持します。skill はこれらを **import** するようになり、markdown コード diff --git a/README_ko.md b/README_ko.md index 092f4db1df..53f0ddab3a 100644 --- a/README_ko.md +++ b/README_ko.md @@ -610,7 +610,7 @@ Intraday bars: 1m / 5m / 15m / 30m / 1H / 4H / 1D. 15 metrics + benchmark compar
-Quant Library 19개 모듈 286개의 테스트된 함수, 모든 경로에서 호출 가능 +Quant Library 19개 모듈 287개의 테스트된 함수, 모든 경로에서 호출 가능 `src/quantlib`는 agent가 필요로 하는 각 금융 수학에 대해 테스트된 구현을 **하나씩만** 보유합니다. skill은 이제 이 함수들을 **import**하며, markdown 코드 블록 안에 수식을 diff --git a/README_zh.md b/README_zh.md index 61a55db264..6753ab6a13 100644 --- a/README_zh.md +++ b/README_zh.md @@ -607,7 +607,7 @@ LONGBRIDGE_ACCESS_TOKEN=...
-Quant Library 19 个模块 286 个经测试的函数,四条通路皆可调用 +Quant Library 19 个模块 287 个经测试的函数,四条通路皆可调用 `src/quantlib` 为 agent 需要的每一块金融数学各提供**一份**经测试的实现。skill 现在是 **import** 这些函数,而不再把公式抄在 markdown 代码块里——如果你在某个 `SKILL.md` diff --git a/agent/src/quantlib/options.py b/agent/src/quantlib/options.py index faf59bdddc..24d12656c1 100644 --- a/agent/src/quantlib/options.py +++ b/agent/src/quantlib/options.py @@ -32,6 +32,7 @@ __all__ = [ "BARRIER_TYPES", + "barrier_greeks", "barrier_option_price", "bs_greeks", "bs_price", @@ -633,3 +634,69 @@ def barrier_option_price( raise ValueError(f"Unhandled barrier type {b_type}") return float(max(0.0, price)) + + + +def barrier_greeks( + S: float, + K: float, + H: float, + T: float, + r: float, + sigma: float, + barrier_type: str, + option_type: str = "call", + q: float = 0.0, + rebate: float = 0.0, +) -> dict[str, float]: + """Compute sensitivity Greeks for single-barrier options via central finite differences. + + Matches the conventions of :func:`bs_greeks`: + * delta: per 1.0 of spot + * gamma: per 1.0 of spot squared + * theta: per calendar day (1/365) + * vega: per 1 percentage point of volatility (0.01) + * rho: per 1 percentage point of interest rate (0.01) + + Args: + S, K, H, T, r, sigma, barrier_type, option_type, q, rebate: Standard barrier inputs. + + Returns: + dict with keys: ``delta``, ``gamma``, ``theta``, ``vega``, ``rho``. + """ + p = barrier_option_price(S, K, H, T, r, sigma, barrier_type, option_type, q, rebate) + + dS = max(1e-4, 1e-4 * S) + p_up = barrier_option_price(S + dS, K, H, T, r, sigma, barrier_type, option_type, q, rebate) + p_down = barrier_option_price(S - dS, K, H, T, r, sigma, barrier_type, option_type, q, rebate) + + delta = float((p_up - p_down) / (2.0 * dS)) + gamma = float((p_up - 2.0 * p + p_down) / (dS**2)) + + # Theta (per calendar day): time decay moves forward, so T - dt + dt = 1.0 / 365.0 + if T > dt: + p_dt = barrier_option_price(S, K, H, T - dt, r, sigma, barrier_type, option_type, q, rebate) + theta = float(p_dt - p) + else: + theta = 0.0 + + # Vega (per 1 percentage point = 0.01) + dvol = 1e-4 + p_vol_up = barrier_option_price(S, K, H, T, r, sigma + dvol, barrier_type, option_type, q, rebate) + p_vol_down = barrier_option_price(S, K, H, T, r, max(1e-6, sigma - dvol), barrier_type, option_type, q, rebate) + vega = float((p_vol_up - p_vol_down) / (2.0 * dvol) * 0.01) + + # Rho (per 1 percentage point = 0.01) + dr = 1e-4 + p_r_up = barrier_option_price(S, K, H, T, r + dr, sigma, barrier_type, option_type, q, rebate) + p_r_down = barrier_option_price(S, K, H, T, r - dr, sigma, barrier_type, option_type, q, rebate) + rho = float((p_r_up - p_r_down) / (2.0 * dr) * 0.01) + + return { + "delta": delta, + "gamma": gamma, + "theta": theta, + "vega": vega, + "rho": rho, + } diff --git a/agent/tests/quantlib/test_options.py b/agent/tests/quantlib/test_options.py index d67d3ac9f0..e0d8ad802a 100644 --- a/agent/tests/quantlib/test_options.py +++ b/agent/tests/quantlib/test_options.py @@ -20,12 +20,11 @@ import pytest from src.quantlib.options import ( - BARRIER_TYPES, + barrier_greeks, barrier_option_price, bs_greeks, bs_price, implied_volatility, - normalise_barrier_type, normalise_option_type, ) @@ -560,6 +559,17 @@ def test_already_breached_barrier_behavior(self): assert barrier_option_price(85.0, 100.0, 90.0, 0.5, 0.05, 0.20, "down-and-in", "call") == pytest.approx( vanilla ) + def test_barrier_greeks_far_from_barrier_matches_bs_greeks(self): + # When barrier H is far away (e.g. down barrier H=10 when S=100), barrier call greeks ~ vanilla call greeks + S, K, H, T, r, sigma = 100.0, 100.0, 10.0, 1.0, 0.05, 0.20 + bg = barrier_greeks(S, K, H, T, r, sigma, "down-and-out", "call") + vg = bs_greeks(S, K, T, r, sigma, "call") + + assert bg["delta"] == pytest.approx(vg["delta"], abs=5e-3) + assert bg["gamma"] == pytest.approx(vg["gamma"], abs=5e-3) + assert bg["vega"] == pytest.approx(vg["vega"], abs=5e-3) + assert bg["theta"] == pytest.approx(vg["theta"], abs=5e-3) + assert bg["rho"] == pytest.approx(vg["rho"], abs=5e-3) def test_barrier_option_input_validation(self): with pytest.raises(ValueError, match="strictly positive"):