Metadata-Version: 2.4
Name: lbriv
Version: 1.0.0
Summary: Black-76 pricing and Let's-Be-Rational implied volatility (Cython port of Peter Jaeckel's LetsBeRational)
Author: Martial Ren
License-Expression: MIT AND LicenseRef-LetsBeRational
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: scipy
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Dynamic: license-file

# lbriv

Black-76 pricing and implied volatility for European options, with the implied-vol
inversion done by a Cython port of Peter Jaeckel's **LetsBeRational** algorithm
(~2 Householder steps per quote to machine precision, `nogil` batch loops).

Everything works in the **T=1, r=0 convention**: prices are undiscounted
(premium / discount factor) and vols are Black *total* vols (raw IV at T=1).
Rescale externally for other maturities. `q = +1` for calls, `-1` for puts.

## Install

```
pip install lbriv
```

Prebuilt wheels cover CPython 3.11+ on Linux (x86_64, aarch64), Windows (x86_64),
and macOS (arm64, x86_64). On anything else pip falls back to the sdist, which
needs a C compiler — the compiled extension is required, there is no pure-Python
fallback.

To work on the package itself, either install from a checkout:

```
pip install .
```

or build in place and put the repo root on `PYTHONPATH`:

```
python setup.py build_ext --inplace
```

## Usage

```python
import numpy as np
from lbriv import black76_undiscounted, vectorized_implied_vol_strikes

forward = 100.0
strikes = np.array([80.0, 100.0, 120.0])
prices = black76_undiscounted(forward, strikes, np.array([0.25, 0.20, 0.22]), q=1)

iv = vectorized_implied_vol_strikes(prices, forward, strikes, q=1)
# -> array([0.25, 0.20, 0.22])
```

Unsolvable quotes (at/below intrinsic, or at/above the vol→∞ bound) come back as **NaN**.

## API

| Function | Purpose |
|---|---|
| `black76_undiscounted(F, K, total_vol, q)` | vectorised Black-76 price |
| `black76_vega(F, K, total_vol)` | d(price)/d(total_vol) |
| `implied_vol(price, F, K, q)` | scalar IV (returns 0.0 on unsolvable) |
| `vectorized_implied_vol_strikes(prices, F, K[], q)` | IV across strikes, NaN on unsolvable |
| `vectorized_implied_vol(prices[], F[], K, q)` | IV across a time series, one strike |
| `black_delta / black_gamma / black_vega` | scalar Black greeks (T=1, r=0) |
| `compute_trades_greeks(...)` | batch IV + delta/gamma/vega over mixed trades |

## Tests

```
pip install -e .[test]
pytest
```

## License

MIT. The implied-vol solver is a port of Peter Jäckel's
[LetsBeRational](http://www.jaeckel.org) reference implementation, whose
permissive notice is preserved in [LICENSE](LICENSE).
