chore: update ferro-ta version to 1.1.3 (#8)

- Bumped version numbers across Cargo.toml, Cargo.lock, pyproject.toml, and conda/meta.yaml to 1.1.3.
- Added new features including American option pricing, digital options, extended Greeks, and historical volatility estimators.
- Enhanced documentation and tests for new functionalities.
- Updated CHANGELOG.md to reflect changes for version 1.1.3.
This commit is contained in:
Pratik Bhadane
2026-04-02 16:38:32 +05:30
committed by GitHub
parent 125eb32d9f
commit 3e0f289d51
38 changed files with 5619 additions and 85 deletions
+245 -4
View File
@@ -2,7 +2,7 @@
"surfaces": {
"python": {
"indicator_count": 208,
"method_count": 447,
"method_count": 464,
"categories": [
"aggregation",
"alerts",
@@ -1736,6 +1736,13 @@
"doc": "",
"params": []
},
{
"name": "stock_leg_payoff",
"category": "derivatives_payoff",
"module": "ferro_ta.analysis.derivatives_payoff",
"doc": "",
"params": []
},
{
"name": "strategy_payoff",
"category": "derivatives_payoff",
@@ -1743,6 +1750,13 @@
"doc": "",
"params": []
},
{
"name": "strategy_value",
"category": "derivatives_payoff",
"module": "ferro_ta.analysis.derivatives_payoff",
"doc": "",
"params": []
},
{
"name": "CHANDELIER_EXIT",
"category": "extended",
@@ -2289,6 +2303,13 @@
"doc": "",
"params": []
},
{
"name": "ExtendedGreeks",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "OptionGreeks",
"category": "options",
@@ -2303,6 +2324,20 @@
"doc": "",
"params": []
},
{
"name": "VolCone",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "american_option_price",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "black_76_price",
"category": "options",
@@ -2317,6 +2352,55 @@
"doc": "",
"params": []
},
{
"name": "close_to_close_vol",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "digital_option_greeks",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "digital_option_price",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "early_exercise_premium",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "expected_move",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "extended_greeks",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "garman_klass_vol",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "greeks",
"category": "options",
@@ -2366,6 +2450,27 @@
"doc": "",
"params": []
},
{
"name": "parkinson_vol",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "put_call_parity_deviation",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "rogers_satchell_vol",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "select_strike",
"category": "options",
@@ -2387,6 +2492,20 @@
"doc": "",
"params": []
},
{
"name": "vol_cone",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "yang_zhang_vol",
"category": "options",
"module": "ferro_ta.analysis.options",
"doc": "",
"params": []
},
{
"name": "DerivativesStrategy",
"category": "options_strategy",
@@ -4616,7 +4735,7 @@
]
},
"rust_core": {
"public_function_count": 331,
"public_function_count": 349,
"functions": [
{
"module": "aggregation",
@@ -5288,6 +5407,16 @@
"function": "willr",
"file": "momentum.rs"
},
{
"module": "options.american",
"function": "american_price_baw",
"file": "options/american.rs"
},
{
"module": "options.american",
"function": "early_exercise_premium",
"file": "options/american.rs"
},
{
"module": "options.chain",
"function": "atm_index",
@@ -5308,16 +5437,36 @@
"function": "select_strike_by_offset",
"file": "options/chain.rs"
},
{
"module": "options.digital",
"function": "digital_greeks",
"file": "options/digital.rs"
},
{
"module": "options.digital",
"function": "digital_price",
"file": "options/digital.rs"
},
{
"module": "options.greeks",
"function": "black_76_greeks",
"file": "options/greeks.rs"
},
{
"module": "options.greeks",
"function": "black_scholes_extended_greeks",
"file": "options/greeks.rs"
},
{
"module": "options.greeks",
"function": "black_scholes_greeks",
"file": "options/greeks.rs"
},
{
"module": "options.greeks",
"function": "model_extended_greeks",
"file": "options/greeks.rs"
},
{
"module": "options.greeks",
"function": "model_greeks",
@@ -5363,6 +5512,26 @@
"function": "pdf",
"file": "options/normal.rs"
},
{
"module": "options.payoff",
"function": "aggregate_greeks_dense",
"file": "options/payoff.rs"
},
{
"module": "options.payoff",
"function": "strategy_payoff_dense",
"file": "options/payoff.rs"
},
{
"module": "options.payoff",
"function": "strategy_value_dense",
"file": "options/payoff.rs"
},
{
"module": "options.payoff",
"function": "strategy_value_grid",
"file": "options/payoff.rs"
},
{
"module": "options.pricing",
"function": "black_76_price",
@@ -5388,11 +5557,51 @@
"function": "price_upper_bound",
"file": "options/pricing.rs"
},
{
"module": "options.pricing",
"function": "put_call_parity_deviation",
"file": "options/pricing.rs"
},
{
"module": "options.realized_vol",
"function": "close_to_close_vol",
"file": "options/realized_vol.rs"
},
{
"module": "options.realized_vol",
"function": "garman_klass_vol",
"file": "options/realized_vol.rs"
},
{
"module": "options.realized_vol",
"function": "parkinson_vol",
"file": "options/realized_vol.rs"
},
{
"module": "options.realized_vol",
"function": "rogers_satchell_vol",
"file": "options/realized_vol.rs"
},
{
"module": "options.realized_vol",
"function": "vol_cone",
"file": "options/realized_vol.rs"
},
{
"module": "options.realized_vol",
"function": "yang_zhang_vol",
"file": "options/realized_vol.rs"
},
{
"module": "options.surface",
"function": "atm_iv",
"file": "options/surface.rs"
},
{
"module": "options.surface",
"function": "expected_move",
"file": "options/surface.rs"
},
{
"module": "options.surface",
"function": "linear_interpolate",
@@ -6276,16 +6485,18 @@
]
},
"wasm_node": {
"export_count": 205,
"export_count": 221,
"exports": [
"ad",
"adosc",
"adx",
"adx_all",
"adxr",
"aggregate_greeks_dense",
"aggregate_tick_bars",
"aggregate_time_bars",
"aggregate_volume_bars_ticks",
"american_price",
"annualized_basis",
"apo",
"aroon",
@@ -6318,6 +6529,7 @@
"check_cross",
"check_threshold",
"choppiness_index",
"close_to_close_vol",
"cmo",
"collect_alert_bars",
"compose_rank",
@@ -6330,17 +6542,23 @@
"curve_summary",
"dema",
"detect_breaks_cusum",
"digital_greeks",
"digital_price",
"donchian",
"drawdown_series",
"dx",
"early_exercise_premium",
"ema",
"exchange_charges_rate",
"expected_move",
"extended_greeks",
"extract_trades",
"fast_period",
"flat_per_order",
"forward_fill_nan",
"funding_cumulative_pnl",
"futures_basis",
"garman_klass_vol",
"gst_rate",
"half_kelly_fraction",
"ht_dcperiod",
@@ -6396,6 +6614,7 @@
"obv",
"ohlcv_agg",
"parity_gap",
"parkinson_vol",
"per_lot",
"period",
"pivot_points",
@@ -6405,6 +6624,7 @@
"ppo",
"price_lower_bound",
"price_upper_bound",
"put_call_parity_deviation",
"rank_series",
"rank_values",
"rate_of_value",
@@ -6418,6 +6638,7 @@
"rocp",
"rocr",
"rocr100",
"rogers_satchell_vol",
"roll_yield",
"rolling_beta",
"rolling_max",
@@ -6455,6 +6676,8 @@
"stoch",
"stochf",
"stochrsi",
"strategy_payoff_dense",
"strategy_value_grid",
"stt_on_buy",
"stt_on_sell",
"stt_rate",
@@ -6474,6 +6697,7 @@
"typprice",
"ultosc",
"var",
"vol_cone",
"volume_bars",
"vwap",
"vwma",
@@ -6482,13 +6706,14 @@
"weighted_continuous",
"willr",
"wma",
"yang_zhang_vol",
"zscore_series"
]
}
},
"parity_summary": {
"python_indicator_count": 207,
"wasm_export_count": 205,
"wasm_export_count": 221,
"common_python_wasm_count": 91,
"common_python_wasm": [
"ad",
@@ -6703,9 +6928,11 @@
],
"wasm_only_vs_python": [
"adx_all",
"aggregate_greeks_dense",
"aggregate_tick_bars",
"aggregate_time_bars",
"aggregate_volume_bars_ticks",
"american_price",
"annualized_basis",
"atm_index",
"atm_iv",
@@ -6723,19 +6950,26 @@
"bottom_n_indices",
"calendar_spreads",
"carry_spread",
"close_to_close_vol",
"compose_rank",
"compose_weighted",
"compute_performance_metrics",
"curve_slope",
"curve_summary",
"digital_greeks",
"digital_price",
"drawdown_series",
"early_exercise_premium",
"exchange_charges_rate",
"expected_move",
"extended_greeks",
"extract_trades",
"fast_period",
"flat_per_order",
"forward_fill_nan",
"funding_cumulative_pnl",
"futures_basis",
"garman_klass_vol",
"gst_rate",
"half_kelly_fraction",
"implied_carry_rate",
@@ -6763,10 +6997,12 @@
"new",
"ohlcv_agg",
"parity_gap",
"parkinson_vol",
"per_lot",
"period",
"price_lower_bound",
"price_upper_bound",
"put_call_parity_deviation",
"rank_series",
"rank_values",
"rate_of_value",
@@ -6774,6 +7010,7 @@
"ratio_adjusted_continuous",
"regulatory_charges_rate",
"relative_strength",
"rogers_satchell_vol",
"roll_yield",
"rolling_beta",
"rolling_max",
@@ -6803,6 +7040,8 @@
"spread",
"stamp_duty_rate",
"stitch_chunks",
"strategy_payoff_dense",
"strategy_value_grid",
"stt_on_buy",
"stt_on_sell",
"stt_rate",
@@ -6813,8 +7052,10 @@
"trade_stats",
"trim_overlap",
"trix_indicator",
"vol_cone",
"walk_forward_indices",
"weighted_continuous",
"yang_zhang_vol",
"zscore_series"
]
}
+1 -1
View File
@@ -1,7 +1,7 @@
Release Notes
=============
These docs track package version ``1.1.2``.
These docs track package version ``1.1.3``.
1.1.0-audit (2026-03-28)
------------------------
+198 -42
View File
@@ -1,50 +1,187 @@
# Derivatives Analytics
`ferro-ta` now includes a Rust-backed derivatives analytics layer focused on
research, simulation, and risk analysis.
`ferro-ta` ships a Rust-backed derivatives analytics layer focused on
research, simulation, and risk analysis. All functions are implemented in
Rust core and exposed to Python (via PyO3) and WebAssembly (via wasm-bindgen).
---
## Modules
- `ferro_ta.analysis.options`
- Black-Scholes-Merton and Black-76 pricing
- Delta, gamma, vega, theta, rho
- Implied volatility inversion with guarded Newton + bisection fallback
- IV rank / percentile / z-score
- Smile metrics: ATM IV, 25-delta risk reversal, butterfly, skew slope, convexity
- Chain helpers: moneyness labels and strike selection by offset or delta
- `ferro_ta.analysis.futures`
- Synthetic forwards and parity diagnostics
- Basis, annualized basis, implied carry, carry spread
- Continuous contract stitching: weighted, back-adjusted, ratio-adjusted
- Curve analytics: calendar spreads, slope, contango summary
- `ferro_ta.analysis.options_strategy`
- Typed strategy schemas for expiry selectors, strike selectors, multi-leg presets,
risk controls, cost assumptions, and simulation limits
- `ferro_ta.analysis.derivatives_payoff`
- Multi-leg payoff aggregation
- Portfolio-level Greeks aggregation across option and futures legs
### `ferro_ta.analysis.options`
| Category | Functions |
|---|---|
| **Pricing** | `black_scholes_price`, `black_76_price`, `option_price` |
| **Greeks** | `greeks`, `extended_greeks` |
| **Implied vol** | `implied_volatility`, `iv_rank`, `iv_percentile`, `iv_zscore` |
| **Digital options** | `digital_option_price`, `digital_option_greeks` |
| **American options** | `american_option_price`, `early_exercise_premium` |
| **Smile / surface** | `smile_metrics`, `term_structure_slope`, `expected_move` |
| **Chain helpers** | `label_moneyness`, `select_strike` |
| **Realised vol** | `close_to_close_vol`, `parkinson_vol`, `garman_klass_vol`, `rogers_satchell_vol`, `yang_zhang_vol` |
| **Vol cone** | `vol_cone` |
| **Diagnostics** | `put_call_parity_deviation` |
### `ferro_ta.analysis.futures`
- Synthetic forwards and parity diagnostics
- Basis, annualized basis, implied carry, carry spread
- Continuous contract stitching: weighted, back-adjusted, ratio-adjusted
- Curve analytics: calendar spreads, slope, contango summary
### `ferro_ta.analysis.options_strategy`
Typed strategy schemas: expiry selectors, strike selectors, multi-leg presets
(`STRADDLE`, `STRANGLE`, `IRON_CONDOR`, `BULL_CALL_SPREAD`, `BEAR_PUT_SPREAD`),
risk controls, cost assumptions, and simulation limits.
### `ferro_ta.analysis.derivatives_payoff`
Multi-leg payoff and Greeks aggregation supporting **option**, **future**, and
**stock** instrument types.
| Function | Description |
|---|---|
| `option_leg_payoff` | Expiry P/L for a single option leg |
| `futures_leg_payoff` | Linear P/L for a futures leg |
| `stock_leg_payoff` | Linear P/L for a stock/equity leg |
| `strategy_payoff` | Aggregate expiry payoff across all legs |
| `strategy_value` | Pre-expiry BSM mid-price value of a multi-leg strategy |
| `aggregate_greeks` | Portfolio-level Greeks across option, futures, and stock legs |
---
## Model conventions
- `model="bsm"` expects the underlying input to be spot and `carry` to represent
a continuous dividend yield or generic carry term.
- `model="black76"` expects the underlying input to be the forward price.
- Volatility and rates use decimal units:
- `0.20` means 20% annualized volatility
- `0.05` means 5% annualized rate
- `time_to_expiry` is expressed in years.
| Parameter | Convention |
|---|---|
| `model="bsm"` | Underlying is spot; `carry` = continuous dividend yield |
| `model="black76"` | Underlying is the forward price |
| `volatility` / `rate` / `carry` | Decimal annual (e.g. `0.20` = 20 %, `0.05` = 5 %) |
| `time_to_expiry` | Years (e.g. `0.25` = 3 months) |
---
## Quick examples
### BSM pricing and Greeks
```python
from ferro_ta.analysis.options import greeks, implied_volatility, option_price
price = option_price(100.0, 100.0, 0.05, 1.0, 0.20, option_type="call")
iv = implied_volatility(price, 100.0, 100.0, 0.05, 1.0, option_type="call")
g = greeks(100.0, 100.0, 0.05, 1.0, 0.20, option_type="call")
print(price, iv, g.delta)
iv = implied_volatility(price, 100.0, 100.0, 0.05, 1.0, option_type="call")
g = greeks(100.0, 100.0, 0.05, 1.0, 0.20, option_type="call")
print(price, iv, g.delta, g.gamma)
```
### Extended (second-order) Greeks
```python
from ferro_ta.analysis.options import extended_greeks
eg = extended_greeks(100.0, 100.0, 0.05, 1.0, 0.20, option_type="call")
print(eg.vanna, eg.volga, eg.charm, eg.speed, eg.color)
```
### Digital options
```python
from ferro_ta.analysis.options import digital_option_price, digital_option_greeks
# Cash-or-nothing call at ATM ≈ e^{-rT} * N(d2) ≈ 0.53
price = digital_option_price(100.0, 100.0, 0.05, 1.0, 0.20,
option_type="call", digital_type="cash_or_nothing")
g = digital_option_greeks(100.0, 100.0, 0.05, 1.0, 0.20,
option_type="call", digital_type="cash_or_nothing")
print(price, g.delta, g.gamma, g.vega)
```
### American options (BAW approximation)
```python
from ferro_ta.analysis.options import american_option_price, early_exercise_premium
# American put — may have meaningful early exercise premium
american = american_option_price(100.0, 100.0, 0.05, 1.0, 0.20, option_type="put")
premium = early_exercise_premium(100.0, 100.0, 0.05, 1.0, 0.20, option_type="put")
print(american, premium)
```
### Historical volatility estimators
```python
import numpy as np
from ferro_ta.analysis.options import (
close_to_close_vol, garman_klass_vol, parkinson_vol,
rogers_satchell_vol, yang_zhang_vol,
)
# Assume daily OHLC arrays of length N
open_p, high_p, low_p, close_p = ... # numpy arrays
ctc = close_to_close_vol(close_p, window=20) # close-only
park = parkinson_vol(high_p, low_p, window=20) # high-low
gk = garman_klass_vol(open_p, high_p, low_p, close_p, window=20)
rs = rogers_satchell_vol(open_p, high_p, low_p, close_p, window=20)
yz = yang_zhang_vol(open_p, high_p, low_p, close_p, window=20)
```
### Volatility cone
```python
from ferro_ta.analysis.options import vol_cone
cone = vol_cone(close_p, windows=(21, 42, 63, 126, 252))
# Overlay current IV against the cone to gauge richness/cheapness
for w, med in zip(cone.windows, cone.median):
print(f"window={int(w):3d} median_rv={med:.1%}")
```
### Put-call parity check
```python
from ferro_ta.analysis.options import option_price, put_call_parity_deviation
call = option_price(100.0, 100.0, 0.05, 1.0, 0.20, option_type="call")
put = option_price(100.0, 100.0, 0.05, 1.0, 0.20, option_type="put")
dev = put_call_parity_deviation(call, put, 100.0, 100.0, 0.05, 1.0)
# dev ≈ 0.0 for BSM-consistent prices; non-zero signals stale/mismatched quotes
```
### Expected move
```python
from ferro_ta.analysis.options import expected_move
lower, upper = expected_move(100.0, 0.20, days_to_expiry=30)
print(f"Expected ±1σ range: [{100+lower:.2f}, {100+upper:.2f}]")
```
### Multi-leg strategies with stock
```python
import numpy as np
from ferro_ta.analysis.derivatives_payoff import PayoffLeg, strategy_payoff, strategy_value
# Covered Call: long 100 shares + short 1 OTM call
spot_grid = np.linspace(80, 130, 100)
legs = [
PayoffLeg("stock", "long", entry_price=100.0),
PayoffLeg("option", "short", option_type="call",
strike=110.0, premium=3.0, volatility=0.20, time_to_expiry=0.25),
]
# Expiry P/L
payoff = strategy_payoff(spot_grid, legs=legs)
# Pre-expiry BSM value (T=3 months remaining)
value = strategy_value(spot_grid, legs=legs, time_to_expiry=0.25, volatility=0.20)
```
### Futures analytics
```python
from ferro_ta.analysis.futures import basis, curve_summary
@@ -52,19 +189,38 @@ print(basis(100.0, 103.0))
print(curve_summary(100.0, [0.1, 0.5, 1.0], [101.0, 102.0, 104.0]))
```
```python
from ferro_ta.analysis.derivatives_payoff import PayoffLeg, strategy_payoff
---
legs = [
PayoffLeg("option", "long", option_type="call", strike=100.0, premium=5.0),
PayoffLeg("future", "long", entry_price=100.0),
]
grid = [90.0, 100.0, 110.0]
print(strategy_payoff(grid, legs=legs))
```
## Instrument types in `PayoffLeg` / `StrategyLeg`
| `instrument` | Required fields | Payoff |
|---|---|---|
| `"option"` | `option_type`, `strike`, `expiry_selector`, `strike_selector` | `max(φ(SK), 0) premium` |
| `"future"` | `entry_price` | `S entry_price` |
| `"stock"` | `entry_price` | `S entry_price` (identical to future, no margin) |
---
## Volatility estimator efficiency comparison
| Estimator | Relative efficiency vs close-to-close | Handles overnight gaps |
|---|---|---|
| Close-to-close | 1× (baseline) | N/A (uses close only) |
| Parkinson | ~5× | No |
| Garman-Klass | ~7.4× | No |
| Rogers-Satchell | ~8× | No |
| Yang-Zhang | ~14× | Yes |
*Use Yang-Zhang when you have overnight gaps (futures, crypto). Use Parkinson
or Garman-Klass for continuous trading sessions.*
---
## Notes
- Existing `iv_rank`, `iv_percentile`, and `iv_zscore` names are preserved.
- The derivatives layer is analytics-only: there is no broker connectivity,
order routing, or execution workflow in this API.
- All existing function names (`iv_rank`, `iv_percentile`, `iv_zscore`, `greeks`,
`option_price`, etc.) are preserved — fully backward compatible.
- The derivatives layer is analytics-only: no broker connectivity, order routing,
or execution workflow.
- WASM: all functions in this layer are also exported as WebAssembly bindings
(see `wasm/src/lib.rs`).
+1 -1
View File
@@ -180,7 +180,7 @@ For source builds, packaging details, and platform notes, see
Release status
--------------
These docs track package version ``1.1.2``.
These docs track package version ``1.1.3``.
- Release notes by version: :doc:`changelog`
- Canonical project changelog: `CHANGELOG.md <https://github.com/pratikbhadane24/ferro-ta/blob/main/CHANGELOG.md>`_