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"):